Rebase origin and fix miss-merged segments
[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();
101}
102
103sub _generate_reader_method {
104 my ($self) = @_;
105
106 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
107 return $self->_generate_reader_method_xs($xs);
108 }
109
110 if($self->is_inline){
111 return $self->_generate_reader_method_inline();
112 }
113
114 return $self->_generate_reader_method_basic();
115}
116
117sub _generate_writer_method {
118 my ($self) = @_;
119
120 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
121 return $self->_generate_writer_method_xs($xs);
122 }
123
124 if($self->is_inline){
125 return $self->_generate_writer_method_inline();
126 }
127
128 return $self->_generate_writer_method_basic();
129}
130
131sub _generate_clearer_method {
132 my ($self) = @_;
133
134 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
135 return $self->_generate_clearer_method_xs($xs);
136 }
137
138 if($self->is_inline){
139 return $self->_generate_clearer_method_inline();
140 }
141
142 return $self->_generate_clearer_method_basic();
143}
144
145sub _generate_predicate_method {
146 my ($self) = @_;
147
148 if(my $xs = $self->associated_metaclass->instance_metaclass->can_xs()){
149 return $self->_generate_predicate_method_xs($xs);
150 }
151
152 if($self->is_inline){
153 return $self->_generate_predicate_method_inline();
154 }
155
156 return $self->_generate_predicate_method_basic();
157}
158
159
160## basic generators
161
e989c0df 162sub _generate_accessor_method_basic {
8d2d4c67 163 my $attr = (shift)->associated_attribute;
ba38bf08 164 return sub {
165 $attr->set_value($_[0], $_[1]) if scalar(@_) == 2;
166 $attr->get_value($_[0]);
167 };
168}
169
e989c0df 170sub _generate_reader_method_basic {
8d2d4c67 171 my $attr = (shift)->associated_attribute;
172 return sub {
ba38bf08 173 confess "Cannot assign a value to a read-only accessor" if @_ > 1;
174 $attr->get_value($_[0]);
8d2d4c67 175 };
ba38bf08 176}
177
e989c0df 178sub _generate_writer_method_basic {
8d2d4c67 179 my $attr = (shift)->associated_attribute;
ba38bf08 180 return sub {
181 $attr->set_value($_[0], $_[1]);
182 };
183}
184
e989c0df 185sub _generate_predicate_method_basic {
8d2d4c67 186 my $attr = (shift)->associated_attribute;
187 return sub {
3545c727 188 $attr->has_value($_[0])
ba38bf08 189 };
190}
191
e989c0df 192sub _generate_clearer_method_basic {
8d2d4c67 193 my $attr = (shift)->associated_attribute;
194 return sub {
3545c727 195 $attr->clear_value($_[0])
ba38bf08 196 };
197}
198
199## Inline methods
200
afc92ac6 201sub _generate_accessor_method_inline {
7f8de9b4 202 my $self = shift;
203 my $attr = $self->associated_attribute;
ba38bf08 204 my $attr_name = $attr->name;
205 my $meta_instance = $attr->associated_class->instance_metaclass;
206
e24b19fb 207 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 208 {},
7f8de9b4 209 'sub {'
a71a4ccb 210 . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
7f8de9b4 211 . ' if scalar(@_) == 2; '
a71a4ccb 212 . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
7f8de9b4 213 . '}'
214 );
e24b19fb 215 confess "Could not generate inline accessor because : $e" if $e;
a6eef5a3 216
217 return $code;
ba38bf08 218}
219
afc92ac6 220sub _generate_reader_method_inline {
7f8de9b4 221 my $self = shift;
222 my $attr = $self->associated_attribute;
ba38bf08 223 my $attr_name = $attr->name;
224 my $meta_instance = $attr->associated_class->instance_metaclass;
225
e24b19fb 226 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 227 {},
7f8de9b4 228 'sub {'
ba38bf08 229 . 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;'
e9a19694 230 . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
7f8de9b4 231 . '}'
232 );
e24b19fb 233 confess "Could not generate inline reader because : $e" if $e;
a6eef5a3 234
235 return $code;
ba38bf08 236}
237
afc92ac6 238sub _generate_writer_method_inline {
7f8de9b4 239 my $self = shift;
240 my $attr = $self->associated_attribute;
ba38bf08 241 my $attr_name = $attr->name;
242 my $meta_instance = $attr->associated_class->instance_metaclass;
243
e24b19fb 244 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 245 {},
7f8de9b4 246 'sub {'
e9a19694 247 . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
7f8de9b4 248 . '}'
249 );
e24b19fb 250 confess "Could not generate inline writer because : $e" if $e;
a6eef5a3 251
252 return $code;
ba38bf08 253}
254
afc92ac6 255sub _generate_predicate_method_inline {
7f8de9b4 256 my $self = shift;
257 my $attr = $self->associated_attribute;
ba38bf08 258 my $attr_name = $attr->name;
259 my $meta_instance = $attr->associated_class->instance_metaclass;
260
e24b19fb 261 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 262 {},
7f8de9b4 263 'sub {'
e9a19694 264 . $meta_instance->inline_is_slot_initialized('$_[0]', $attr_name)
7f8de9b4 265 . '}'
266 );
e24b19fb 267 confess "Could not generate inline predicate because : $e" if $e;
a6eef5a3 268
269 return $code;
ba38bf08 270}
271
afc92ac6 272sub _generate_clearer_method_inline {
7f8de9b4 273 my $self = shift;
274 my $attr = $self->associated_attribute;
ba38bf08 275 my $attr_name = $attr->name;
276 my $meta_instance = $attr->associated_class->instance_metaclass;
277
e24b19fb 278 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 279 {},
7f8de9b4 280 'sub {'
e9a19694 281 . $meta_instance->inline_deinitialize_slot('$_[0]', $attr_name)
7f8de9b4 282 . '}'
283 );
e24b19fb 284 confess "Could not generate inline clearer because : $e" if $e;
a6eef5a3 285
286 return $code;
ba38bf08 287}
288
2891;
290
291__END__
292
293=pod
294
8d2d4c67 295=head1 NAME
ba38bf08 296
297Class::MOP::Method::Accessor - Method Meta Object for accessors
298
299=head1 SYNOPSIS
300
96e38ba6 301 use Class::MOP::Method::Accessor;
302
303 my $reader = Class::MOP::Method::Accessor->new(
304 attribute => $attribute,
305 is_inline => 1,
306 accessor_type => 'reader',
307 );
8d2d4c67 308
b7045e66 309 $reader->body->execute($instance); # call the reader method
ba38bf08 310
311=head1 DESCRIPTION
312
1385ad9d 313This is a subclass of <Class::MOP::Method> which is used by
314C<Class::MOP::Attribute> to generate accessor code. It handles
315generation of readers, writers, predicates and clearers. For each type
316of method, it can either create a subroutine reference, or actually
317inline code by generating a string and C<eval>'ing it.
96e38ba6 318
ba38bf08 319=head1 METHODS
320
321=over 4
322
1385ad9d 323=item B<< Class::MOP::Method::Accessor->new(%options) >>
ba38bf08 324
1385ad9d 325This returns a new C<Class::MOP::Method::Accessor> based on the
326C<%options> provided.
96e38ba6 327
328=over 4
329
9258c369 330=item * attribute
96e38ba6 331
1385ad9d 332This is the C<Class::MOP::Attribute> for which accessors are being
333generated. This option is required.
96e38ba6 334
9258c369 335=item * accessor_type
96e38ba6 336
1385ad9d 337This is a string which should be one of "reader", "writer",
338"accessor", "predicate", or "clearer". This is the type of method
339being generated. This option is required.
96e38ba6 340
9258c369 341=item * is_inline
96e38ba6 342
1385ad9d 343This indicates whether or not the accessor should be inlined. This
cb8d08c6 344defaults to false.
96e38ba6 345
9258c369 346=item * name
347
348The method name (without a package name). This is required.
349
350=item * package_name
351
352The package name for the method. This is required.
353
96e38ba6 354=back
ba38bf08 355
1385ad9d 356=item B<< $metamethod->accessor_type >>
ba38bf08 357
1385ad9d 358Returns the accessor type which was passed to C<new>.
96e38ba6 359
1385ad9d 360=item B<< $metamethod->is_inline >>
ba38bf08 361
1385ad9d 362Returns a boolean indicating whether or not the accessor is inlined.
96e38ba6 363
1385ad9d 364=item B<< $metamethod->associated_attribute >>
ba38bf08 365
1385ad9d 366This returns the L<Class::MOP::Attribute> object which was passed to
367C<new>.
96e38ba6 368
1385ad9d 369=item B<< $metamethod->body >>
96e38ba6 370
1385ad9d 371The method itself is I<generated> when the accessor object is
372constructed.
ba38bf08 373
374=back
375
376=head1 AUTHORS
377
378Stevan Little E<lt>stevan@iinteractive.comE<gt>
379
ba38bf08 380=head1 COPYRIGHT AND LICENSE
381
070bb6c9 382Copyright 2006-2009 by Infinity Interactive, Inc.
ba38bf08 383
384L<http://www.iinteractive.com>
385
386This library is free software; you can redistribute it and/or modify
8d2d4c67 387it under the same terms as Perl itself.
ba38bf08 388
389=cut
390