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