bump version and update Changes
[gitmo/Moose.git] / lib / Moose / Meta / Method / Accessor.pm
CommitLineData
8ee73eeb 1
2package Moose::Meta::Method::Accessor;
3
4use strict;
5use warnings;
6
e1737edc 7our $VERSION = '0.62_02';
e606ae5f 8$VERSION = eval $VERSION;
d44714be 9our $AUTHORITY = 'cpan:STEVAN';
8ee73eeb 10
39b3bc94 11use base 'Moose::Meta::Method',
d617b644 12 'Class::MOP::Method::Accessor';
13
18748ad6 14sub _error_thrower {
15 my $self = shift;
16 ( ref $self && $self->associated_attribute ) || $self->SUPER::_error_thrower();
17}
d617b644 18
c9183ffc 19sub _eval_code {
20 my ( $self, $code ) = @_;
21
22 # NOTE:
23 # set up the environment
24 my $attr = $self->associated_attribute;
25 my $attr_name = $attr->name;
cee532a1 26 my $meta = $self,
c9183ffc 27
28 my $type_constraint_obj = $attr->type_constraint;
29 my $type_constraint_name = $type_constraint_obj && $type_constraint_obj->name;
9df136d0 30 my $type_constraint = $type_constraint_obj
31 ? $type_constraint_obj->_compiled_type_constraint
32 : undef;
c9183ffc 33
ae8d63f2 34 #warn "code for $attr_name =>\n" . $code . "\n";
c9183ffc 35 my $sub = eval $code;
cee532a1 36 $self->throw_error("Could not create writer for '$attr_name' because $@ \n code: $code", error => $@, data => $code ) if $@;
c9183ffc 37 return $sub;
38
39}
40
946289d1 41sub generate_accessor_method_inline {
3ccdc84a 42 my $self = $_[0];
26fbace8 43 my $attr = $self->associated_attribute;
3ccdc84a 44 my $attr_name = $attr->name;
45 my $inv = '$_[0]';
e27dfc11 46 my $slot_access = $self->_inline_access($inv, $attr_name);
ac211120 47 my $value_name = $self->_value_needs_copy ? '$val' : '$_[1]';
d617b644 48
c9183ffc 49 $self->_eval_code('sub { ' . "\n"
e27dfc11 50 . $self->_inline_pre_body(@_) . "\n"
e7c06c1e 51 . 'if (scalar(@_) >= 2) {' . "\n"
ac211120 52 . $self->_inline_copy_value . "\n"
e27dfc11 53 . $self->_inline_check_required . "\n"
54 . $self->_inline_check_coercion . "\n"
55 . $self->_inline_check_constraint($value_name) . "\n"
32dd4a95 56 . $self->_inline_store($inv, $value_name) . "\n"
57 . $self->_inline_trigger($inv, $value_name) . "\n"
e27dfc11 58 . ' }' . "\n"
e606ae5f 59 . $self->_inline_check_lazy($inv) . "\n"
e27dfc11 60 . $self->_inline_post_body(@_) . "\n"
61 . 'return ' . $self->_inline_auto_deref($self->_inline_get($inv)) . "\n"
c9183ffc 62 . ' }');
d617b644 63}
64
946289d1 65sub generate_writer_method_inline {
3ccdc84a 66 my $self = $_[0];
26fbace8 67 my $attr = $self->associated_attribute;
3ccdc84a 68 my $attr_name = $attr->name;
69 my $inv = '$_[0]';
70 my $slot_access = $self->_inline_get($inv, $attr_name);
ac211120 71 my $value_name = $self->_value_needs_copy ? '$val' : '$_[1]';
3ccdc84a 72
c9183ffc 73 $self->_eval_code('sub { '
c350159f 74 . $self->_inline_pre_body(@_)
ac211120 75 . $self->_inline_copy_value
d617b644 76 . $self->_inline_check_required
77 . $self->_inline_check_coercion
32dd4a95 78 . $self->_inline_check_constraint($value_name)
79 . $self->_inline_store($inv, $value_name)
80 . $self->_inline_post_body(@_)
81 . $self->_inline_trigger($inv, $value_name)
c9183ffc 82 . ' }');
d617b644 83}
84
946289d1 85sub generate_reader_method_inline {
3ccdc84a 86 my $self = $_[0];
26fbace8 87 my $attr = $self->associated_attribute;
3ccdc84a 88 my $attr_name = $attr->name;
89 my $inv = '$_[0]';
90 my $slot_access = $self->_inline_get($inv, $attr_name);
26fbace8 91
c9183ffc 92 $self->_eval_code('sub {'
c350159f 93 . $self->_inline_pre_body(@_)
cee532a1 94 . $self->_inline_throw_error('"Cannot assign a value to a read-only accessor"', 'data => \@_') . ' if @_ > 1;'
e606ae5f 95 . $self->_inline_check_lazy($inv)
c350159f 96 . $self->_inline_post_body(@_)
3ccdc84a 97 . 'return ' . $self->_inline_auto_deref( $slot_access ) . ';'
c9183ffc 98 . '}');
d617b644 99}
100
ac211120 101sub _inline_copy_value {
102 return '' unless shift->_value_needs_copy;
103 return 'my $val = $_[1];'
104}
105
106sub _value_needs_copy {
107 my $attr = (shift)->associated_attribute;
108 return $attr->should_coerce;
109}
110
51308c23 111sub generate_reader_method { shift->generate_reader_method_inline(@_) }
112sub generate_writer_method { shift->generate_writer_method_inline(@_) }
113sub generate_accessor_method { shift->generate_accessor_method_inline(@_) }
8ecb1fa0 114
3ccdc84a 115sub _inline_pre_body { '' }
c350159f 116sub _inline_post_body { '' }
117
d617b644 118sub _inline_check_constraint {
97e11ef5 119 my ($self, $value) = @_;
120
121 my $attr = $self->associated_attribute;
8bb7da15 122 my $attr_name = $attr->name;
97e11ef5 123
124 return '' unless $attr->has_type_constraint;
125
8bb7da15 126 my $type_constraint_name = $attr->type_constraint->name;
127
cee532a1 128 qq{\$type_constraint->($value) || } . $self->_inline_throw_error(qq{"Attribute ($attr_name) does not pass the type constraint because: " . \$type_constraint_obj->get_message($value)}, "data => $value") . ";";
d617b644 129}
130
131sub _inline_check_coercion {
97e11ef5 132 my $attr = (shift)->associated_attribute;
133
134 return '' unless $attr->should_coerce;
ac211120 135 return '$val = $attr->type_constraint->coerce($_[1]);'
d617b644 136}
137
138sub _inline_check_required {
cee532a1 139 my $self = shift;
140 my $attr = $self->associated_attribute;
8bb7da15 141
142 my $attr_name = $attr->name;
97e11ef5 143
144 return '' unless $attr->is_required;
cee532a1 145 return qq{(\@_ >= 2) || } . $self->_inline_throw_error(qq{"Attribute ($attr_name) is required, so cannot be set to undef"}) . ';' # defined $_[1] is not good enough
d617b644 146}
147
148sub _inline_check_lazy {
e606ae5f 149 my ($self, $instance) = @_;
150
26fbace8 151 my $attr = $self->associated_attribute;
152
3822d5ee 153 return '' unless $attr->is_lazy;
26fbace8 154
e606ae5f 155 my $slot_access = $self->_inline_access($instance, $attr->name);
3822d5ee 156
e606ae5f 157 my $slot_exists = $self->_inline_has($instance, $attr->name);
3822d5ee 158
159 my $code = 'unless (' . $slot_exists . ') {' . "\n";
160 if ($attr->has_type_constraint) {
97e11ef5 161 if ($attr->has_default || $attr->has_builder) {
162 if ($attr->has_default) {
e606ae5f 163 $code .= ' my $default = $attr->default(' . $instance . ');'."\n";
97e11ef5 164 }
165 elsif ($attr->has_builder) {
3822d5ee 166 $code .= ' my $default;'."\n".
e606ae5f 167 ' if(my $builder = '.$instance.'->can($attr->builder)){ '."\n".
168 ' $default = '.$instance.'->$builder; '. "\n } else {\n" .
169 ' ' . $self->_inline_throw_error(q{sprintf "%s does not support builder method '%s' for attribute '%s'", ref(} . $instance . ') || '.$instance.', $attr->builder, $attr->name') .
170 ';'. "\n }";
3822d5ee 171 }
7c4f0d32 172 $code .= ' $default = $type_constraint_obj->coerce($default);'."\n" if $attr->should_coerce;
173 $code .= ' ($type_constraint->($default))' .
cee532a1 174 ' || ' . $self->_inline_throw_error('"Attribute (" . $attr_name . ") does not pass the type constraint ("' .
175 ' . $type_constraint_name . ") with " . (defined($default) ? overload::StrVal($default) : "undef")' ) . ';'
ab76842e 176 . "\n";
e606ae5f 177 $code .= ' ' . $self->_inline_init_slot($attr, $instance, $slot_access, '$default') . "\n";
97e11ef5 178 }
179 else {
e606ae5f 180 $code .= ' ' . $self->_inline_init_slot($attr, $instance, $slot_access, 'undef') . "\n";
26fbace8 181 }
182
3822d5ee 183 } else {
97e11ef5 184 if ($attr->has_default) {
e606ae5f 185 $code .= ' ' . $self->_inline_init_slot($attr, $instance, $slot_access, ('$attr->default(' . $instance . ')')) . "\n";
97e11ef5 186 }
187 elsif ($attr->has_builder) {
e606ae5f 188 $code .= ' if (my $builder = '.$instance.'->can($attr->builder)) { ' . "\n"
189 . ' ' . $self->_inline_init_slot($attr, $instance, $slot_access, ($instance . '->$builder'))
190 . "\n } else {\n"
191 . ' ' . $self->_inline_throw_error(q{sprintf "%s does not support builder method '%s' for attribute '%s'", ref(} . $instance . ') || '.$instance.', $attr->builder, $attr->name')
192 . ';'. "\n }";
97e11ef5 193 }
194 else {
e606ae5f 195 $code .= ' ' . $self->_inline_init_slot($attr, $instance, $slot_access, 'undef') . "\n";
3822d5ee 196 }
197 }
198 $code .= "}\n";
199 return $code;
d617b644 200}
201
9df136d0 202sub _inline_init_slot {
203 my ($self, $attr, $inv, $slot_access, $value) = @_;
204 if ($attr->has_initializer) {
205 return ('$attr->set_initial_value(' . $inv . ', ' . $value . ');');
206 }
207 else {
208 return ($slot_access . ' = ' . $value . ';');
209 }
210}
d617b644 211
212sub _inline_store {
97e11ef5 213 my ($self, $instance, $value) = @_;
214 my $attr = $self->associated_attribute;
215
216 my $mi = $attr->associated_class->get_meta_instance;
217 my $slot_name = sprintf "'%s'", $attr->slots;
218
d617b644 219 my $code = $mi->inline_set_slot_value($instance, $slot_name, $value) . ";";
97e11ef5 220 $code .= $mi->inline_weaken_slot_value($instance, $slot_name, $value) . ";"
221 if $attr->is_weak_ref;
d617b644 222 return $code;
223}
224
225sub _inline_trigger {
97e11ef5 226 my ($self, $instance, $value) = @_;
227 my $attr = $self->associated_attribute;
228 return '' unless $attr->has_trigger;
229 return sprintf('$attr->trigger->(%s, %s, $attr);', $instance, $value);
d617b644 230}
231
232sub _inline_get {
97e11ef5 233 my ($self, $instance) = @_;
234 my $attr = $self->associated_attribute;
235
236 my $mi = $attr->associated_class->get_meta_instance;
237 my $slot_name = sprintf "'%s'", $attr->slots;
d617b644 238
239 return $mi->inline_get_slot_value($instance, $slot_name);
240}
241
e27dfc11 242sub _inline_access {
97e11ef5 243 my ($self, $instance) = @_;
244 my $attr = $self->associated_attribute;
245
246 my $mi = $attr->associated_class->get_meta_instance;
247 my $slot_name = sprintf "'%s'", $attr->slots;
e27dfc11 248
249 return $mi->inline_slot_access($instance, $slot_name);
250}
251
252sub _inline_has {
97e11ef5 253 my ($self, $instance) = @_;
254 my $attr = $self->associated_attribute;
255
256 my $mi = $attr->associated_class->get_meta_instance;
257 my $slot_name = sprintf "'%s'", $attr->slots;
e27dfc11 258
259 return $mi->inline_is_slot_initialized($instance, $slot_name);
260}
261
d617b644 262sub _inline_auto_deref {
263 my ( $self, $ref_value ) = @_;
26fbace8 264 my $attr = $self->associated_attribute;
d617b644 265
39b3bc94 266 return $ref_value unless $attr->should_auto_deref;
d617b644 267
39b3bc94 268 my $type_constraint = $attr->type_constraint;
d617b644 269
270 my $sigil;
271 if ($type_constraint->is_a_type_of('ArrayRef')) {
272 $sigil = '@';
26fbace8 273 }
d617b644 274 elsif ($type_constraint->is_a_type_of('HashRef')) {
275 $sigil = '%';
26fbace8 276 }
d617b644 277 else {
46cb090f 278 $self->throw_error("Can not auto de-reference the type constraint '" . $type_constraint->name . "'", type_constraint => $type_constraint );
d617b644 279 }
280
281 "(wantarray() ? $sigil\{ ( $ref_value ) || return } : ( $ref_value ) )";
282}
8ee73eeb 283
2841;
285
286__END__
287
288=pod
289
39b3bc94 290=head1 NAME
291
ecb59493 292Moose::Meta::Method::Accessor - A Moose Method metaclass for accessors
39b3bc94 293
294=head1 DESCRIPTION
295
26fbace8 296This is a subclass of L<Class::MOP::Method::Accessor> and it's primary
297responsibility is to generate the accessor methods for attributes. It
ecb59493 298can handle both closure based accessors, as well as inlined source based
26fbace8 299accessors.
ecb59493 300
301This is a fairly new addition to the MOP, but this will play an important
302role in the optimization strategy we are currently following.
303
39b3bc94 304=head1 METHODS
305
306=over 4
307
8ecb1fa0 308=item B<generate_accessor_method>
309
310=item B<generate_reader_method>
311
312=item B<generate_writer_method>
313
39b3bc94 314=item B<generate_accessor_method_inline>
315
39b3bc94 316=item B<generate_reader_method_inline>
317
39b3bc94 318=item B<generate_writer_method_inline>
319
320=back
321
322=head1 BUGS
323
26fbace8 324All complex software has bugs lurking in it, and this module is no
39b3bc94 325exception. If you find a bug please either email me, or add the bug
326to cpan-RT.
327
328=head1 AUTHOR
329
330Stevan Little E<lt>stevan@iinteractive.comE<gt>
331
332Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
333
334=head1 COPYRIGHT AND LICENSE
335
778db3ac 336Copyright 2006-2008 by Infinity Interactive, Inc.
39b3bc94 337
338L<http://www.iinteractive.com>
339
340This library is free software; you can redistribute it and/or modify
341it under the same terms as Perl itself.
342
51308c23 343=cut