Merge branch 'topic/unified-method-generation-w-xs' of gitmo@moose.perl.org:Class...
[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';
9
19042e4d 10our $VERSION = '0.92';
d519662a 11$VERSION = eval $VERSION;
ba38bf08 12our $AUTHORITY = 'cpan:STEVAN';
13
565f0cbb 14use base 'Class::MOP::Method::Generated';
ba38bf08 15
ba38bf08 16sub new {
17 my $class = shift;
18 my %options = @_;
8d2d4c67 19
ba38bf08 20 (exists $options{attribute})
21 || confess "You must supply an attribute to construct with";
8d2d4c67 22
ba38bf08 23 (exists $options{accessor_type})
8d2d4c67 24 || confess "You must supply an accessor_type to construct with";
25
ba38bf08 26 (blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute'))
8d2d4c67 27 || confess "You must supply an attribute which is a 'Class::MOP::Attribute' instance";
28
b38f3848 29 ($options{package_name} && $options{name})
32202ce2 30 || confess "You must supply the package_name and name parameters $Class::MOP::Method::UPGRADE_ERROR_TEXT";
b38f3848 31
0bfc85b8 32 my $self = $class->_new(\%options);
8d2d4c67 33
34 # we don't want this creating
35 # a cycle in the code, if not
ba38bf08 36 # needed
8683db0e 37 weaken($self->{'attribute'});
ace00b18 38 weaken($self->{'associated_metaclass'});
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
ddd16947 62 is_inline => $params->{is_inline},
ec9e38e5 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
206860b8 71
8d2d4c67 72## factory
ba38bf08 73
e9497117 74sub _initialize_body {
ba38bf08 75 my $self = shift;
8d2d4c67 76
ba38bf08 77 my $method_name = join "_" => (
afc92ac6 78 '_generate',
8d2d4c67 79 $self->accessor_type,
e989c0df 80 'method',
ba38bf08 81 );
8d2d4c67 82
1be5f78f 83 $self->{'body'} = $self->$method_name();
e989c0df 84 return;
ba38bf08 85}
86
87## generators
88
afc92ac6 89sub _generate_accessor_method {
e989c0df 90 my ($self) = @_;
91
92 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
93 return $self->_generate_accessor_method_xs($xs);
94 }
95
96 if($self->is_inline){
97 return $self->_generate_accessor_method_inline();
98 }
99
100 return $self->_generate_accessor_method_basic();
ef027418 101<<<<<<< HEAD:lib/Class/MOP/Method/Accessor.pm
ba38bf08 102}
103
353c6152 104sub _generate_reader_method {
105 my ($self) = @_;
106
107 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
108 return $self->_generate_reader_method_xs($xs);
109 }
110
111 if($self->is_inline){
112 return $self->_generate_reader_method_inline();
113 }
114
115 return $self->_generate_reader_method_basic();
116}
117
118sub _generate_writer_method {
119 my ($self) = @_;
120
121 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
122 return $self->_generate_writer_method_xs($xs);
123 }
124
125 if($self->is_inline){
126 return $self->_generate_writer_method_inline();
127 }
128
129 return $self->_generate_writer_method_basic();
130}
131
132sub _generate_clearer_method {
133 my ($self) = @_;
134
135 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
136 return $self->_generate_clearer_method_xs($xs);
137 }
138
139 if($self->is_inline){
140 return $self->_generate_clearer_method_inline();
141 }
142
143 return $self->_generate_clearer_method_basic();
144}
145
146sub _generate_predicate_method {
147 my ($self) = @_;
148
149 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
150 return $self->_generate_predicate_method_xs($xs);
151 }
152
153 if($self->is_inline){
154 return $self->_generate_predicate_method_inline();
155 }
156
157 return $self->_generate_predicate_method_basic();
158}
159
160
161## basic generators
ba38bf08 162
ef027418 163=======
e989c0df 164}
165
166sub _generate_reader_method {
167 my ($self) = @_;
168
169 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
170 return $self->_generate_reader_method_xs($xs);
171 }
172
173 if($self->is_inline){
174 return $self->_generate_reader_method_inline();
175 }
176
177 return $self->_generate_reader_method_basic();
178}
179
180sub _generate_writer_method {
181 my ($self) = @_;
182
183 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
184 return $self->_generate_writer_method_xs($xs);
185 }
186
187 if($self->is_inline){
188 return $self->_generate_writer_method_inline();
189 }
190
191 return $self->_generate_writer_method_basic();
192}
193
194sub _generate_clearer_method {
195 my ($self) = @_;
196
197 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
198 return $self->_generate_clearer_method_xs($xs);
199 }
200
201 if($self->is_inline){
202 return $self->_generate_clearer_method_inline();
203 }
204
205 return $self->_generate_clearer_method_basic();
206}
207
208sub _generate_predicate_method {
209 my ($self) = @_;
210
211 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
212 return $self->_generate_predicate_method_xs($xs);
213 }
214
215 if($self->is_inline){
216 return $self->_generate_predicate_method_inline();
217 }
218
219 return $self->_generate_predicate_method_basic();
220}
221
222
223## basic generators
224
e989c0df 225sub _generate_accessor_method_basic {
8d2d4c67 226 my $attr = (shift)->associated_attribute;
ba38bf08 227 return sub {
228 $attr->set_value($_[0], $_[1]) if scalar(@_) == 2;
229 $attr->get_value($_[0]);
230 };
231}
232
e989c0df 233sub _generate_reader_method_basic {
8d2d4c67 234 my $attr = (shift)->associated_attribute;
235 return sub {
ba38bf08 236 confess "Cannot assign a value to a read-only accessor" if @_ > 1;
237 $attr->get_value($_[0]);
8d2d4c67 238 };
ba38bf08 239}
240
e989c0df 241sub _generate_writer_method_basic {
8d2d4c67 242 my $attr = (shift)->associated_attribute;
ba38bf08 243 return sub {
244 $attr->set_value($_[0], $_[1]);
245 };
246}
247
e989c0df 248sub _generate_predicate_method_basic {
8d2d4c67 249 my $attr = (shift)->associated_attribute;
250 return sub {
3545c727 251 $attr->has_value($_[0])
ba38bf08 252 };
253}
254
e989c0df 255sub _generate_clearer_method_basic {
8d2d4c67 256 my $attr = (shift)->associated_attribute;
257 return sub {
3545c727 258 $attr->clear_value($_[0])
ba38bf08 259 };
260}
261
262## Inline methods
263
afc92ac6 264sub _generate_accessor_method_inline {
7f8de9b4 265 my $self = shift;
266 my $attr = $self->associated_attribute;
ba38bf08 267 my $attr_name = $attr->name;
268 my $meta_instance = $attr->associated_class->instance_metaclass;
269
e24b19fb 270 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 271 {},
7f8de9b4 272 'sub {'
a71a4ccb 273 . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
7f8de9b4 274 . ' if scalar(@_) == 2; '
a71a4ccb 275 . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
7f8de9b4 276 . '}'
277 );
e24b19fb 278 confess "Could not generate inline accessor because : $e" if $e;
a6eef5a3 279
280 return $code;
ba38bf08 281}
282
afc92ac6 283sub _generate_reader_method_inline {
7f8de9b4 284 my $self = shift;
285 my $attr = $self->associated_attribute;
ba38bf08 286 my $attr_name = $attr->name;
287 my $meta_instance = $attr->associated_class->instance_metaclass;
288
e24b19fb 289 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 290 {},
7f8de9b4 291 'sub {'
ba38bf08 292 . 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;'
e9a19694 293 . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
7f8de9b4 294 . '}'
295 );
e24b19fb 296 confess "Could not generate inline reader because : $e" if $e;
a6eef5a3 297
298 return $code;
ba38bf08 299}
300
afc92ac6 301sub _generate_writer_method_inline {
7f8de9b4 302 my $self = shift;
303 my $attr = $self->associated_attribute;
ba38bf08 304 my $attr_name = $attr->name;
305 my $meta_instance = $attr->associated_class->instance_metaclass;
306
e24b19fb 307 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 308 {},
7f8de9b4 309 'sub {'
e9a19694 310 . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
7f8de9b4 311 . '}'
312 );
e24b19fb 313 confess "Could not generate inline writer because : $e" if $e;
a6eef5a3 314
315 return $code;
ba38bf08 316}
317
afc92ac6 318sub _generate_predicate_method_inline {
7f8de9b4 319 my $self = shift;
320 my $attr = $self->associated_attribute;
ba38bf08 321 my $attr_name = $attr->name;
322 my $meta_instance = $attr->associated_class->instance_metaclass;
323
e24b19fb 324 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 325 {},
7f8de9b4 326 'sub {'
e9a19694 327 . $meta_instance->inline_is_slot_initialized('$_[0]', $attr_name)
7f8de9b4 328 . '}'
329 );
e24b19fb 330 confess "Could not generate inline predicate because : $e" if $e;
a6eef5a3 331
332 return $code;
ba38bf08 333}
334
afc92ac6 335sub _generate_clearer_method_inline {
7f8de9b4 336 my $self = shift;
337 my $attr = $self->associated_attribute;
ba38bf08 338 my $attr_name = $attr->name;
339 my $meta_instance = $attr->associated_class->instance_metaclass;
340
e24b19fb 341 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 342 {},
7f8de9b4 343 'sub {'
e9a19694 344 . $meta_instance->inline_deinitialize_slot('$_[0]', $attr_name)
7f8de9b4 345 . '}'
346 );
e24b19fb 347 confess "Could not generate inline clearer because : $e" if $e;
a6eef5a3 348
349 return $code;
ba38bf08 350}
351
3521;
353
354__END__
355
356=pod
357
8d2d4c67 358=head1 NAME
ba38bf08 359
360Class::MOP::Method::Accessor - Method Meta Object for accessors
361
362=head1 SYNOPSIS
363
96e38ba6 364 use Class::MOP::Method::Accessor;
365
366 my $reader = Class::MOP::Method::Accessor->new(
367 attribute => $attribute,
368 is_inline => 1,
369 accessor_type => 'reader',
370 );
8d2d4c67 371
b7045e66 372 $reader->body->execute($instance); # call the reader method
ba38bf08 373
374=head1 DESCRIPTION
375
1385ad9d 376This is a subclass of <Class::MOP::Method> which is used by
377C<Class::MOP::Attribute> to generate accessor code. It handles
378generation of readers, writers, predicates and clearers. For each type
379of method, it can either create a subroutine reference, or actually
380inline code by generating a string and C<eval>'ing it.
96e38ba6 381
ba38bf08 382=head1 METHODS
383
384=over 4
385
1385ad9d 386=item B<< Class::MOP::Method::Accessor->new(%options) >>
ba38bf08 387
1385ad9d 388This returns a new C<Class::MOP::Method::Accessor> based on the
389C<%options> provided.
96e38ba6 390
391=over 4
392
9258c369 393=item * attribute
96e38ba6 394
1385ad9d 395This is the C<Class::MOP::Attribute> for which accessors are being
396generated. This option is required.
96e38ba6 397
9258c369 398=item * accessor_type
96e38ba6 399
1385ad9d 400This is a string which should be one of "reader", "writer",
401"accessor", "predicate", or "clearer". This is the type of method
402being generated. This option is required.
96e38ba6 403
9258c369 404=item * is_inline
96e38ba6 405
1385ad9d 406This indicates whether or not the accessor should be inlined. This
cb8d08c6 407defaults to false.
96e38ba6 408
9258c369 409=item * name
410
411The method name (without a package name). This is required.
412
413=item * package_name
414
415The package name for the method. This is required.
416
96e38ba6 417=back
ba38bf08 418
1385ad9d 419=item B<< $metamethod->accessor_type >>
ba38bf08 420
1385ad9d 421Returns the accessor type which was passed to C<new>.
96e38ba6 422
1385ad9d 423=item B<< $metamethod->is_inline >>
ba38bf08 424
1385ad9d 425Returns a boolean indicating whether or not the accessor is inlined.
96e38ba6 426
1385ad9d 427=item B<< $metamethod->associated_attribute >>
ba38bf08 428
1385ad9d 429This returns the L<Class::MOP::Attribute> object which was passed to
430C<new>.
96e38ba6 431
1385ad9d 432=item B<< $metamethod->body >>
96e38ba6 433
1385ad9d 434The method itself is I<generated> when the accessor object is
435constructed.
ba38bf08 436
437=back
438
439=head1 AUTHORS
440
441Stevan Little E<lt>stevan@iinteractive.comE<gt>
442
ba38bf08 443=head1 COPYRIGHT AND LICENSE
444
070bb6c9 445Copyright 2006-2009 by Infinity Interactive, Inc.
ba38bf08 446
447L<http://www.iinteractive.com>
448
449This library is free software; you can redistribute it and/or modify
8d2d4c67 450it under the same terms as Perl itself.
ba38bf08 451
452=cut
453