push a thin error throwing wrapper back here
[gitmo/Class-MOP.git] / lib / Class / MOP / Method / Accessor.pm
CommitLineData
ba38bf08 1
2package Class::MOP::Method::Accessor;
3
4use strict;
5use warnings;
6
7use Carp 'confess';
8use Scalar::Util 'blessed', 'weaken';
15961c86 9use Try::Tiny;
ba38bf08 10
a9f48b4b 11our $VERSION = '1.11';
d519662a 12$VERSION = eval $VERSION;
ba38bf08 13our $AUTHORITY = 'cpan:STEVAN';
14
565f0cbb 15use base 'Class::MOP::Method::Generated';
ba38bf08 16
ba38bf08 17sub new {
18 my $class = shift;
19 my %options = @_;
8d2d4c67 20
ba38bf08 21 (exists $options{attribute})
22 || confess "You must supply an attribute to construct with";
8d2d4c67 23
ba38bf08 24 (exists $options{accessor_type})
8d2d4c67 25 || confess "You must supply an accessor_type to construct with";
26
ba38bf08 27 (blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute'))
8d2d4c67 28 || confess "You must supply an attribute which is a 'Class::MOP::Attribute' instance";
29
b38f3848 30 ($options{package_name} && $options{name})
32202ce2 31 || confess "You must supply the package_name and name parameters $Class::MOP::Method::UPGRADE_ERROR_TEXT";
b38f3848 32
0bfc85b8 33 my $self = $class->_new(\%options);
8d2d4c67 34
35 # we don't want this creating
36 # a cycle in the code, if not
ba38bf08 37 # needed
8683db0e 38 weaken($self->{'attribute'});
8d2d4c67 39
e9497117 40 $self->_initialize_body;
8d2d4c67 41
ba38bf08 42 return $self;
43}
44
a9e38dc7 45sub _new {
0bfc85b8 46 my $class = shift;
a9e38dc7 47
ec9e38e5 48 return Class::MOP::Class->initialize($class)->new_object(@_)
812d58f9 49 if $class ne __PACKAGE__;
a9e38dc7 50
ec9e38e5 51 my $params = @_ == 1 ? $_[0] : {@_};
52
53 return bless {
54 # inherited from Class::MOP::Method
55 body => $params->{body},
56 associated_metaclass => $params->{associated_metaclass},
57 package_name => $params->{package_name},
58 name => $params->{name},
59 original_method => $params->{original_method},
60
61 # inherit from Class::MOP::Generated
62 is_inline => $params->{is_inline} || 0,
63 definition_context => $params->{definition_context},
64
65 # defined in this class
66 attribute => $params->{attribute},
67 accessor_type => $params->{accessor_type},
68 } => $class;
a9e38dc7 69}
70
ba38bf08 71## accessors
72
8683db0e 73sub associated_attribute { (shift)->{'attribute'} }
74sub accessor_type { (shift)->{'accessor_type'} }
ba38bf08 75
8d2d4c67 76## factory
ba38bf08 77
e9497117 78sub _initialize_body {
ba38bf08 79 my $self = shift;
8d2d4c67 80
ba38bf08 81 my $method_name = join "_" => (
afc92ac6 82 '_generate',
8d2d4c67 83 $self->accessor_type,
ba38bf08 84 'method',
d90b42a6 85 ($self->is_inline ? 'inline' : ())
ba38bf08 86 );
8d2d4c67 87
1be5f78f 88 $self->{'body'} = $self->$method_name();
ba38bf08 89}
90
91## generators
92
afc92ac6 93sub _generate_accessor_method {
5e5102f1 94 my $self = shift;
95 my $attr = $self->associated_attribute;
ba38bf08 96
8d2d4c67 97 return sub {
5e5102f1 98 if (@_ >= 2) {
99 $attr->set_value($_[0], $_[1]);
100 }
ba38bf08 101 $attr->get_value($_[0]);
8d2d4c67 102 };
ba38bf08 103}
104
afc92ac6 105sub _generate_accessor_method_inline {
03a3092d 106 my $self = shift;
107 my $attr = $self->associated_attribute;
ba38bf08 108
5e5102f1 109 return try {
5efa6a46 110 $self->_compile_code([
111 'sub {',
753d7546 112 'if (@_ > 1) {',
5e5102f1 113 $attr->_inline_set_value('$_[0]', '$_[1]'),
114 '}',
115 $attr->_inline_get_value('$_[0]'),
5efa6a46 116 '}',
117 ]);
15961c86 118 }
119 catch {
120 confess "Could not generate inline accessor because : $_";
121 };
5e5102f1 122}
123
124sub _generate_reader_method {
125 my $self = shift;
126 my $attr = $self->associated_attribute;
a6eef5a3 127
5e5102f1 128 return sub {
129 confess "Cannot assign a value to a read-only accessor"
130 if @_ > 1;
131 $attr->get_value($_[0]);
132 };
ba38bf08 133}
134
afc92ac6 135sub _generate_reader_method_inline {
03a3092d 136 my $self = shift;
137 my $attr = $self->associated_attribute;
ba38bf08 138
5e5102f1 139 return try {
5efa6a46 140 $self->_compile_code([
141 'sub {',
753d7546 142 'if (@_ > 1) {',
143 # XXX: this is a hack, but our error stuff is terrible
144 $self->_inline_throw_error(
145 '"Cannot assign a value to a read-only accessor"',
146 'data => \@_'
147 ) . ';',
148 '}',
5e5102f1 149 $attr->_inline_get_value('$_[0]'),
5efa6a46 150 '}',
151 ]);
15961c86 152 }
153 catch {
154 confess "Could not generate inline reader because : $_";
155 };
5e5102f1 156}
a6eef5a3 157
753d7546 158sub _inline_throw_error {
159 my $self = shift;
160 return 'confess ' . $_[0];
161}
162
5e5102f1 163sub _generate_writer_method {
164 my $self = shift;
165 my $attr = $self->associated_attribute;
166
167 return sub {
168 $attr->set_value($_[0], $_[1]);
169 };
ba38bf08 170}
171
afc92ac6 172sub _generate_writer_method_inline {
03a3092d 173 my $self = shift;
174 my $attr = $self->associated_attribute;
ba38bf08 175
5e5102f1 176 return try {
5efa6a46 177 $self->_compile_code([
178 'sub {',
5e5102f1 179 $attr->_inline_set_value('$_[0]', '$_[1]'),
5efa6a46 180 '}',
181 ]);
15961c86 182 }
183 catch {
184 confess "Could not generate inline writer because : $_";
185 };
5e5102f1 186}
187
188sub _generate_predicate_method {
189 my $self = shift;
190 my $attr = $self->associated_attribute;
a6eef5a3 191
5e5102f1 192 return sub {
193 $attr->has_value($_[0])
194 };
ba38bf08 195}
196
afc92ac6 197sub _generate_predicate_method_inline {
03a3092d 198 my $self = shift;
199 my $attr = $self->associated_attribute;
ba38bf08 200
5e5102f1 201 return try {
5efa6a46 202 $self->_compile_code([
203 'sub {',
5e5102f1 204 $attr->_inline_has_value('$_[0]'),
5efa6a46 205 '}',
206 ]);
15961c86 207 }
208 catch {
209 confess "Could not generate inline predicate because : $_";
210 };
5e5102f1 211}
a6eef5a3 212
5e5102f1 213sub _generate_clearer_method {
214 my $self = shift;
215 my $attr = $self->associated_attribute;
216
217 return sub {
218 $attr->clear_value($_[0])
219 };
ba38bf08 220}
221
afc92ac6 222sub _generate_clearer_method_inline {
03a3092d 223 my $self = shift;
224 my $attr = $self->associated_attribute;
ba38bf08 225
5e5102f1 226 return try {
5efa6a46 227 $self->_compile_code([
228 'sub {',
5e5102f1 229 $attr->_inline_clear_value('$_[0]'),
5efa6a46 230 '}',
231 ]);
15961c86 232 }
233 catch {
234 confess "Could not generate inline clearer because : $_";
235 };
ba38bf08 236}
237
2381;
239
240__END__
241
242=pod
243
8d2d4c67 244=head1 NAME
ba38bf08 245
246Class::MOP::Method::Accessor - Method Meta Object for accessors
247
248=head1 SYNOPSIS
249
96e38ba6 250 use Class::MOP::Method::Accessor;
251
252 my $reader = Class::MOP::Method::Accessor->new(
253 attribute => $attribute,
254 is_inline => 1,
255 accessor_type => 'reader',
256 );
8d2d4c67 257
b7045e66 258 $reader->body->execute($instance); # call the reader method
ba38bf08 259
260=head1 DESCRIPTION
261
6f241a63 262This is a subclass of C<Class::MOP::Method> which is used by
1385ad9d 263C<Class::MOP::Attribute> to generate accessor code. It handles
264generation of readers, writers, predicates and clearers. For each type
265of method, it can either create a subroutine reference, or actually
266inline code by generating a string and C<eval>'ing it.
96e38ba6 267
ba38bf08 268=head1 METHODS
269
270=over 4
271
1385ad9d 272=item B<< Class::MOP::Method::Accessor->new(%options) >>
ba38bf08 273
1385ad9d 274This returns a new C<Class::MOP::Method::Accessor> based on the
275C<%options> provided.
96e38ba6 276
277=over 4
278
9258c369 279=item * attribute
96e38ba6 280
1385ad9d 281This is the C<Class::MOP::Attribute> for which accessors are being
282generated. This option is required.
96e38ba6 283
9258c369 284=item * accessor_type
96e38ba6 285
1385ad9d 286This is a string which should be one of "reader", "writer",
287"accessor", "predicate", or "clearer". This is the type of method
288being generated. This option is required.
96e38ba6 289
9258c369 290=item * is_inline
96e38ba6 291
1385ad9d 292This indicates whether or not the accessor should be inlined. This
cb8d08c6 293defaults to false.
96e38ba6 294
9258c369 295=item * name
296
297The method name (without a package name). This is required.
298
299=item * package_name
300
301The package name for the method. This is required.
302
96e38ba6 303=back
ba38bf08 304
1385ad9d 305=item B<< $metamethod->accessor_type >>
ba38bf08 306
1385ad9d 307Returns the accessor type which was passed to C<new>.
96e38ba6 308
1385ad9d 309=item B<< $metamethod->is_inline >>
ba38bf08 310
1385ad9d 311Returns a boolean indicating whether or not the accessor is inlined.
96e38ba6 312
1385ad9d 313=item B<< $metamethod->associated_attribute >>
ba38bf08 314
1385ad9d 315This returns the L<Class::MOP::Attribute> object which was passed to
316C<new>.
96e38ba6 317
1385ad9d 318=item B<< $metamethod->body >>
96e38ba6 319
1385ad9d 320The method itself is I<generated> when the accessor object is
321constructed.
ba38bf08 322
323=back
324
325=head1 AUTHORS
326
327Stevan Little E<lt>stevan@iinteractive.comE<gt>
328
ba38bf08 329=head1 COPYRIGHT AND LICENSE
330
3e2c8600 331Copyright 2006-2010 by Infinity Interactive, Inc.
ba38bf08 332
333L<http://www.iinteractive.com>
334
335This library is free software; you can redistribute it and/or modify
8d2d4c67 336it under the same terms as Perl itself.
ba38bf08 337
338=cut
339