Add a test exposing [rt.cpan.org #70419]
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
CommitLineData
c0e30cf5 1
2package Moose::Meta::Attribute;
3
4use strict;
5use warnings;
6
9238220f 7use Class::MOP ();
37ffa261 8use B ();
21f1e231 9use Scalar::Util 'blessed', 'weaken';
fe11f190 10use List::MoreUtils 'any';
1454efcc 11use Try::Tiny;
a909a4df 12use overload ();
a15dff8d 13
f1309155 14use Moose::Deprecated;
8ee73eeb 15use Moose::Meta::Method::Accessor;
a05f85c1 16use Moose::Meta::Method::Delegation;
d5c30e52 17use Moose::Util ();
a3c7e2fe 18use Moose::Util::TypeConstraints ();
d2782813 19use Class::MOP::MiniTrait;
bc1e29b5 20
f785aad8 21use base 'Class::MOP::Attribute', 'Moose::Meta::Mixin::AttributeCore';
c0e30cf5 22
d2782813 23Class::MOP::MiniTrait::apply(__PACKAGE__, 'Moose::Meta::Object::Trait');
24
82a5b1a7 25__PACKAGE__->meta->add_attribute('traits' => (
26 reader => 'applied_traits',
27 predicate => 'has_applied_traits',
dc2b7cc8 28 Class::MOP::_definition_context(),
82a5b1a7 29));
82168dbb 30
d03bd989 31# we need to have a ->does method in here to
32# more easily support traits, and the introspection
0db4f1d7 33# of those traits. We extend the does check to look
34# for metatrait aliases.
35sub does {
36 my ($self, $role_name) = @_;
1454efcc 37 my $name = try {
0db4f1d7 38 Moose::Util::resolve_metatrait_alias(Attribute => $role_name)
39 };
40 return 0 if !defined($name); # failed to load class
e8895723 41 return $self->Moose::Object::does($name);
0db4f1d7 42}
587e457d 43
bcc04ae1 44sub _error_thrower {
45 my $self = shift;
46 require Moose::Meta::Class;
47 ( ref $self && $self->associated_class ) || "Moose::Meta::Class";
48}
49
be05faea 50sub throw_error {
51 my $self = shift;
bcc04ae1 52 my $inv = $self->_error_thrower;
be05faea 53 unshift @_, "message" if @_ % 2 == 1;
54 unshift @_, attr => $self if ref $self;
bcc04ae1 55 unshift @_, $inv;
56 my $handler = $inv->can("throw_error"); # to avoid incrementing depth by 1
18748ad6 57 goto $handler;
be05faea 58}
59
6e50f7e9 60sub _inline_throw_error {
61 my ( $self, $msg, $args ) = @_;
bcc04ae1 62
63 my $inv = $self->_error_thrower;
64 # XXX ugh
65 $inv = 'Moose::Meta::Class' unless $inv->can('_inline_throw_error');
66
67 # XXX ugh ugh UGH
68 my $class = $self->associated_class;
69 if ($class) {
70 my $class_name = B::perlstring($class->name);
71 my $attr_name = B::perlstring($self->name);
72 $args = 'attr => Class::MOP::class_of(' . $class_name . ')'
73 . '->find_attribute_by_name(' . $attr_name . '), '
74 . (defined $args ? $args : '');
75 }
76
77 return $inv->_inline_throw_error($msg, $args)
6e50f7e9 78}
79
78cd1d3b 80sub new {
f3c4e20e 81 my ($class, $name, %options) = @_;
c32c2c61 82 $class->_process_options($name, \%options) unless $options{__hack_no_process_options}; # used from clone()... YECHKKK FIXME ICKY YUCK GROSS
aa4c3a8d 83
84 delete $options{__hack_no_process_options};
85
86 my %attrs =
87 ( map { $_ => 1 }
88 grep { defined }
89 map { $_->init_arg() }
90 $class->meta()->get_all_attributes()
91 );
92
93 my @bad = sort grep { ! $attrs{$_} } keys %options;
94
95 if (@bad)
96 {
97 Carp::cluck "Found unknown argument(s) passed to '$name' attribute constructor in '$class': @bad";
98 }
99
f3c4e20e 100 return $class->SUPER::new($name, %options);
1d768fb1 101}
102
d5c30e52 103sub interpolate_class_and_new {
aa4c3a8d 104 my ($class, $name, %args) = @_;
d5c30e52 105
aa4c3a8d 106 my ( $new_class, @traits ) = $class->interpolate_class(\%args);
d03bd989 107
aa4c3a8d 108 $new_class->new($name, %args, ( scalar(@traits) ? ( traits => \@traits ) : () ) );
d5c30e52 109}
110
111sub interpolate_class {
aa4c3a8d 112 my ($class, $options) = @_;
d5c30e52 113
c32c2c61 114 $class = ref($class) || $class;
115
aa4c3a8d 116 if ( my $metaclass_name = delete $options->{metaclass} ) {
c32c2c61 117 my $new_class = Moose::Util::resolve_metaclass_alias( Attribute => $metaclass_name );
d03bd989 118
c32c2c61 119 if ( $class ne $new_class ) {
120 if ( $new_class->can("interpolate_class") ) {
aa4c3a8d 121 return $new_class->interpolate_class($options);
c32c2c61 122 } else {
123 $class = $new_class;
124 }
125 }
d5c30e52 126 }
127
c32c2c61 128 my @traits;
129
aa4c3a8d 130 if (my $traits = $options->{traits}) {
8974015d 131 my $i = 0;
132 while ($i < @$traits) {
133 my $trait = $traits->[$i++];
134 next if ref($trait); # options to a trait we discarded
135
136 $trait = Moose::Util::resolve_metatrait_alias(Attribute => $trait)
137 || $trait;
138
139 next if $class->does($trait);
140
141 push @traits, $trait;
142
143 # are there options?
144 push @traits, $traits->[$i++]
145 if $traits->[$i] && ref($traits->[$i]);
146 }
965743fb 147
148 if (@traits) {
c32c2c61 149 my $anon_class = Moose::Meta::Class->create_anon_class(
150 superclasses => [ $class ],
151 roles => [ @traits ],
152 cache => 1,
153 );
154
155 $class = $anon_class->name;
156 }
d5c30e52 157 }
c32c2c61 158
159 return ( wantarray ? ( $class, @traits ) : $class );
d5c30e52 160}
161
e606ae5f 162# ...
163
ec835085 164# method-generating options shouldn't be overridden
165sub illegal_options_for_inheritance {
d21262bd 166 qw(reader writer accessor clearer predicate)
ec835085 167}
e606ae5f 168
169# NOTE/TODO
d03bd989 170# This method *must* be able to handle
171# Class::MOP::Attribute instances as
172# well. Yes, I know that is wrong, but
173# apparently we didn't realize it was
174# doing that and now we have some code
175# which is dependent on it. The real
176# solution of course is to push this
e606ae5f 177# feature back up into Class::MOP::Attribute
178# but I not right now, I am too lazy.
d03bd989 179# However if you are reading this and
180# looking for something to do,.. please
e606ae5f 181# be my guest.
182# - stevan
ce0e8d63 183sub clone_and_inherit_options {
184 my ($self, %options) = @_;
d03bd989 185
e606ae5f 186 # NOTE:
187 # we may want to extends a Class::MOP::Attribute
d03bd989 188 # in which case we need to be able to use the
189 # core set of legal options that have always
e606ae5f 190 # been here. But we allows Moose::Meta::Attribute
191 # instances to changes them.
192 # - SL
7782e1da 193 my @illegal_options = $self->can('illegal_options_for_inheritance')
194 ? $self->illegal_options_for_inheritance
195 : ();
196
ec835085 197 my @found_illegal_options = grep { exists $options{$_} && exists $self->{$_} ? $_ : undef } @illegal_options;
7782e1da 198 (scalar @found_illegal_options == 0)
199 || $self->throw_error("Illegal inherited options => (" . (join ', ' => @found_illegal_options) . ")", data => \%options);
26fbace8 200
ce0e8d63 201 if ($options{isa}) {
202 my $type_constraint;
8de73ff1 203 if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
204 $type_constraint = $options{isa};
205 }
206 else {
d40ce9d5 207 $type_constraint = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options{isa});
8de73ff1 208 (defined $type_constraint)
be05faea 209 || $self->throw_error("Could not find the type constraint '" . $options{isa} . "'", data => $options{isa});
8de73ff1 210 }
5e98d2b6 211
7782e1da 212 $options{type_constraint} = $type_constraint;
ce0e8d63 213 }
d03bd989 214
2ea379cb 215 if ($options{does}) {
216 my $type_constraint;
217 if (blessed($options{does}) && $options{does}->isa('Moose::Meta::TypeConstraint')) {
218 $type_constraint = $options{does};
219 }
220 else {
d40ce9d5 221 $type_constraint = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options{does});
2ea379cb 222 (defined $type_constraint)
be05faea 223 || $self->throw_error("Could not find the type constraint '" . $options{does} . "'", data => $options{does});
2ea379cb 224 }
225
7782e1da 226 $options{type_constraint} = $type_constraint;
d03bd989 227 }
c32c2c61 228
cbd141ca 229 # NOTE:
d03bd989 230 # this doesn't apply to Class::MOP::Attributes,
cbd141ca 231 # so we can ignore it for them.
232 # - SL
233 if ($self->can('interpolate_class')) {
7782e1da 234 ( $options{metaclass}, my @traits ) = $self->interpolate_class(\%options);
c32c2c61 235
cbd141ca 236 my %seen;
237 my @all_traits = grep { $seen{$_}++ } @{ $self->applied_traits || [] }, @traits;
7782e1da 238 $options{traits} = \@all_traits if @all_traits;
cbd141ca 239 }
c32c2c61 240
d412262b 241 # This method can be called on a CMOP::Attribute object, so we need to
1aefb264 242 # make sure we can call this method.
243 $self->_process_lazy_build_option( $self->name, \%options )
244 if $self->can('_process_lazy_build_option');
4a8c7092 245
7782e1da 246 $self->clone(%options);
1d768fb1 247}
248
c32c2c61 249sub clone {
250 my ( $self, %params ) = @_;
251
aa4c3a8d 252 my $class = delete $params{metaclass} || ref $self;
c32c2c61 253
db72153d 254 my ( @init, @non_init );
c32c2c61 255
0772362a 256 foreach my $attr ( grep { $_->has_value($self) } Class::MOP::class_of($self)->get_all_attributes ) {
db72153d 257 push @{ $attr->has_init_arg ? \@init : \@non_init }, $attr;
258 }
c32c2c61 259
db72153d 260 my %new_params = ( ( map { $_->init_arg => $_->get_value($self) } @init ), %params );
c32c2c61 261
db72153d 262 my $name = delete $new_params{name};
c32c2c61 263
db72153d 264 my $clone = $class->new($name, %new_params, __hack_no_process_options => 1 );
c32c2c61 265
db72153d 266 foreach my $attr ( @non_init ) {
267 $attr->set_value($clone, $attr->get_value($self));
c32c2c61 268 }
db72153d 269
270 return $clone;
c32c2c61 271}
272
1d768fb1 273sub _process_options {
1aefb264 274 my ( $class, $name, $options ) = @_;
8de73ff1 275
1aefb264 276 $class->_process_is_option( $name, $options );
277 $class->_process_isa_option( $name, $options );
278 $class->_process_does_option( $name, $options );
279 $class->_process_coerce_option( $name, $options );
280 $class->_process_trigger_option( $name, $options );
281 $class->_process_auto_deref_option( $name, $options );
282 $class->_process_lazy_build_option( $name, $options );
283 $class->_process_lazy_option( $name, $options );
284 $class->_process_required_option( $name, $options );
285}
21f1e231 286
1aefb264 287sub _process_is_option {
288 my ( $class, $name, $options ) = @_;
d03bd989 289
1aefb264 290 return unless $options->{is};
291
292 ### -------------------------
293 ## is => ro, writer => _foo # turns into (reader => foo, writer => _foo) as before
294 ## is => rw, writer => _foo # turns into (reader => foo, writer => _foo)
295 ## is => rw, accessor => _foo # turns into (accessor => _foo)
296 ## is => ro, accessor => _foo # error, accesor is rw
297 ### -------------------------
298
299 if ( $options->{is} eq 'ro' ) {
300 $class->throw_error(
301 "Cannot define an accessor name on a read-only attribute, accessors are read/write",
302 data => $options )
303 if exists $options->{accessor};
304 $options->{reader} ||= $name;
305 }
306 elsif ( $options->{is} eq 'rw' ) {
307 if ( $options->{writer} ) {
8de73ff1 308 $options->{reader} ||= $name;
8de73ff1 309 }
8de73ff1 310 else {
1aefb264 311 $options->{accessor} ||= $name;
8de73ff1 312 }
f3c4e20e 313 }
1aefb264 314 elsif ( $options->{is} eq 'bare' ) {
315 return;
316 # do nothing, but don't complain (later) about missing methods
317 }
318 else {
319 $class->throw_error( "I do not understand this option (is => "
320 . $options->{is}
321 . ") on attribute ($name)", data => $options->{is} );
322 }
323}
8de73ff1 324
1aefb264 325sub _process_isa_option {
326 my ( $class, $name, $options ) = @_;
327
328 return unless exists $options->{isa};
8de73ff1 329
1aefb264 330 if ( exists $options->{does} ) {
331 if ( try { $options->{isa}->can('does') } ) {
332 ( $options->{isa}->does( $options->{does} ) )
333 || $class->throw_error(
334 "Cannot have an isa option and a does option if the isa does not do the does on attribute ($name)",
335 data => $options );
8de73ff1 336 }
337 else {
1aefb264 338 $class->throw_error(
339 "Cannot have an isa option which cannot ->does() on attribute ($name)",
340 data => $options );
8de73ff1 341 }
f3c4e20e 342 }
1aefb264 343
344 # allow for anon-subtypes here ...
345 if ( blessed( $options->{isa} )
346 && $options->{isa}->isa('Moose::Meta::TypeConstraint') ) {
347 $options->{type_constraint} = $options->{isa};
348 }
349 else {
350 $options->{type_constraint}
351 = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint(
352 $options->{isa} );
f3c4e20e 353 }
1aefb264 354}
8de73ff1 355
1aefb264 356sub _process_does_option {
357 my ( $class, $name, $options ) = @_;
2b54d2a6 358
1aefb264 359 return unless exists $options->{does} && ! exists $options->{isa};
f1309155 360
1aefb264 361 # allow for anon-subtypes here ...
362 if ( blessed( $options->{does} )
363 && $options->{does}->isa('Moose::Meta::TypeConstraint') ) {
364 $options->{type_constraint} = $options->{does};
f3c4e20e 365 }
1aefb264 366 else {
367 $options->{type_constraint}
368 = Moose::Util::TypeConstraints::find_or_create_does_type_constraint(
369 $options->{does} );
0b7df53c 370 }
1aefb264 371}
0b7df53c 372
1aefb264 373sub _process_coerce_option {
374 my ( $class, $name, $options ) = @_;
8de73ff1 375
1aefb264 376 return unless $options->{coerce};
8de73ff1 377
1aefb264 378 ( exists $options->{type_constraint} )
379 || $class->throw_error(
380 "You cannot have coercion without specifying a type constraint on attribute ($name)",
381 data => $options );
382
383 $class->throw_error(
384 "You cannot have a weak reference to a coerced value on attribute ($name)",
385 data => $options )
386 if $options->{weak_ref};
26fbace8 387
1aefb264 388 unless ( $options->{type_constraint}->has_coercion ) {
389 my $type = $options->{type_constraint}->name;
390
391 Moose::Deprecated::deprecated(
392 feature => 'coerce without coercion',
393 message =>
394 "You cannot coerce an attribute ($name) unless its type ($type) has a coercion"
395 );
9edba990 396 }
1aefb264 397}
398
399sub _process_trigger_option {
400 my ( $class, $name, $options ) = @_;
401
402 return unless exists $options->{trigger};
9edba990 403
1aefb264 404 ( 'CODE' eq ref $options->{trigger} )
405 || $class->throw_error("Trigger must be a CODE ref on attribute ($name)", data => $options->{trigger});
78cd1d3b 406}
c0e30cf5 407
1aefb264 408sub _process_auto_deref_option {
409 my ( $class, $name, $options ) = @_;
410
411 return unless $options->{auto_deref};
412
413 ( exists $options->{type_constraint} )
414 || $class->throw_error(
415 "You cannot auto-dereference without specifying a type constraint on attribute ($name)",
416 data => $options );
417
418 ( $options->{type_constraint}->is_a_type_of('ArrayRef')
419 || $options->{type_constraint}->is_a_type_of('HashRef') )
420 || $class->throw_error(
421 "You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute ($name)",
422 data => $options );
423}
424
425sub _process_lazy_build_option {
4a8c7092 426 my ( $class, $name, $options ) = @_;
427
428 return unless $options->{lazy_build};
429
430 $class->throw_error(
431 "You can not use lazy_build and default for the same attribute ($name)",
432 data => $options )
433 if exists $options->{default};
434
435 $options->{lazy} = 1;
436 $options->{builder} ||= "_build_${name}";
1aefb264 437
4a8c7092 438 if ( $name =~ /^_/ ) {
439 $options->{clearer} ||= "_clear${name}";
440 $options->{predicate} ||= "_has${name}";
441 }
442 else {
443 $options->{clearer} ||= "clear_${name}";
444 $options->{predicate} ||= "has_${name}";
445 }
446}
447
1aefb264 448sub _process_lazy_option {
449 my ( $class, $name, $options ) = @_;
450
451 return unless $options->{lazy};
452
453 ( exists $options->{default} || defined $options->{builder} )
454 || $class->throw_error(
455 "You cannot have a lazy attribute ($name) without specifying a default value for it",
456 data => $options );
457}
458
459sub _process_required_option {
460 my ( $class, $name, $options ) = @_;
461
462 if (
463 $options->{required}
464 && !(
465 ( !exists $options->{init_arg} || defined $options->{init_arg} )
466 || exists $options->{default}
467 || defined $options->{builder}
468 )
469 ) {
470 $class->throw_error(
471 "You cannot have a required attribute ($name) without a default, builder, or an init_arg",
472 data => $options );
473 }
474}
475
d500266f 476sub initialize_instance_slot {
ddd0ec20 477 my ($self, $meta_instance, $instance, $params) = @_;
d500266f 478 my $init_arg = $self->init_arg();
479 # try to fetch the init arg from the %params ...
ddd0ec20 480
26fbace8 481 my $val;
1ed0b94f 482 my $value_is_set;
625d571f 483 if ( defined($init_arg) and exists $params->{$init_arg}) {
d500266f 484 $val = $params->{$init_arg};
d03bd989 485 $value_is_set = 1;
d500266f 486 }
487 else {
488 # skip it if it's lazy
489 return if $self->is_lazy;
490 # and die if it's required and doesn't have a default value
be05faea 491 $self->throw_error("Attribute (" . $self->name . ") is required", object => $instance, data => $params)
26fbace8 492 if $self->is_required && !$self->has_default && !$self->has_builder;
ddd0ec20 493
1ed0b94f 494 # if nothing was in the %params, we can use the
495 # attribute's default value (if it has one)
496 if ($self->has_default) {
497 $val = $self->default($instance);
498 $value_is_set = 1;
d03bd989 499 }
a6c84c69 500 elsif ($self->has_builder) {
e606ae5f 501 $val = $self->_call_builder($instance);
502 $value_is_set = 1;
a0748c37 503 }
26fbace8 504 }
505
1ed0b94f 506 return unless $value_is_set;
507
9c9563c7 508 $val = $self->_coerce_and_verify( $val, $instance );
ddd0ec20 509
759e4e8f 510 $self->set_initial_value($instance, $val);
312e0f0c 511
512 if ( ref $val && $self->is_weak_ref ) {
32881f68 513 $self->_weaken_value($instance);
312e0f0c 514 }
d500266f 515}
516
e606ae5f 517sub _call_builder {
518 my ( $self, $instance ) = @_;
519
520 my $builder = $self->builder();
521
522 return $instance->$builder()
523 if $instance->can( $self->builder );
524
525 $self->throw_error( blessed($instance)
526 . " does not support builder method '"
527 . $self->builder
528 . "' for attribute '"
529 . $self->name
530 . "'",
531 object => $instance,
532 );
533}
534
d617b644 535## Slot management
9e93dd19 536
4a315f4b 537sub _make_initializer_writer_callback {
538 my $self = shift;
539 my ($meta_instance, $instance, $slot_name) = @_;
540 my $old_callback = $self->SUPER::_make_initializer_writer_callback(@_);
541 return sub {
542 $old_callback->($self->_coerce_and_verify($_[0], $instance));
8abe9636 543 };
8abe9636 544}
545
946289d1 546sub set_value {
b6af66f8 547 my ($self, $instance, @args) = @_;
548 my $value = $args[0];
26fbace8 549
37ffa261 550 my $attr_name = quotemeta($self->name);
26fbace8 551
b6af66f8 552 if ($self->is_required and not @args) {
be05faea 553 $self->throw_error("Attribute ($attr_name) is required", object => $instance);
946289d1 554 }
26fbace8 555
9c9563c7 556 $value = $self->_coerce_and_verify( $value, $instance );
26fbace8 557
3dda07f5 558 my @old;
559 if ( $self->has_trigger && $self->has_value($instance) ) {
560 @old = $self->get_value($instance, 'for trigger');
561 }
562
312e0f0c 563 $self->SUPER::set_value($instance, $value);
26fbace8 564
312e0f0c 565 if ( ref $value && $self->is_weak_ref ) {
32881f68 566 $self->_weaken_value($instance);
946289d1 567 }
26fbace8 568
946289d1 569 if ($self->has_trigger) {
3dda07f5 570 $self->trigger->($instance, $value, @old);
946289d1 571 }
572}
573
6e50f7e9 574sub _inline_set_value {
575 my $self = shift;
a619fc2f 576 my ($instance, $value, $tc, $coercion, $message, $for_constructor) = @_;
6e50f7e9 577
c40e4359 578 my $old = '@old';
579 my $copy = '$val';
580 $tc ||= '$type_constraint';
581 $coercion ||= '$type_coercion';
a619fc2f 582 $message ||= '$type_message';
6e50f7e9 583
584 my @code;
585 if ($self->_writer_value_needs_copy) {
586 push @code, $self->_inline_copy_value($value, $copy);
587 $value = $copy;
588 }
589
ec86bdff 590 # constructors already handle required checks
591 push @code, $self->_inline_check_required
592 unless $for_constructor;
593
a619fc2f 594 push @code, $self->_inline_tc_code($value, $tc, $coercion, $message);
ec86bdff 595
596 # constructors do triggers all at once at the end
597 push @code, $self->_inline_get_old_value_for_trigger($instance, $old)
598 unless $for_constructor;
599
6e50f7e9 600 push @code, (
6e50f7e9 601 $self->SUPER::_inline_set_value($instance, $value),
602 $self->_inline_weaken_value($instance, $value),
6e50f7e9 603 );
604
ec86bdff 605 # constructors do triggers all at once at the end
606 push @code, $self->_inline_trigger($instance, $value, $old)
607 unless $for_constructor;
608
6e50f7e9 609 return @code;
610}
611
612sub _writer_value_needs_copy {
613 my $self = shift;
614 return $self->should_coerce;
615}
616
617sub _inline_copy_value {
618 my $self = shift;
619 my ($value, $copy) = @_;
620
621 return 'my ' . $copy . ' = ' . $value . ';'
622}
623
624sub _inline_check_required {
625 my $self = shift;
626
627 return unless $self->is_required;
628
629 my $attr_name = quotemeta($self->name);
630
631 return (
632 'if (@_ < 2) {',
633 $self->_inline_throw_error(
634 '"Attribute (' . $attr_name . ') is required, so cannot '
635 . 'be set to undef"' # defined $_[1] is not good enough
636 ) . ';',
637 '}',
638 );
639}
640
641sub _inline_tc_code {
642 my $self = shift;
a619fc2f 643 my ($value, $tc, $coercion, $message, $is_lazy) = @_;
6e50f7e9 644 return (
c40e4359 645 $self->_inline_check_coercion(
646 $value, $tc, $coercion, $is_lazy,
647 ),
648 $self->_inline_check_constraint(
a619fc2f 649 $value, $tc, $message, $is_lazy,
c40e4359 650 ),
6e50f7e9 651 );
652}
653
654sub _inline_check_coercion {
655 my $self = shift;
c40e4359 656 my ($value, $tc, $coercion) = @_;
6e50f7e9 657
658 return unless $self->should_coerce && $self->type_constraint->has_coercion;
659
c40e4359 660 if ( $self->type_constraint->can_be_inlined ) {
661 return (
662 'if (! (' . $self->type_constraint->_inline_check($value) . ')) {',
663 $value . ' = ' . $coercion . '->(' . $value . ');',
664 '}',
665 );
666 }
667 else {
668 return (
669 'if (!' . $tc . '->(' . $value . ')) {',
670 $value . ' = ' . $coercion . '->(' . $value . ');',
671 '}',
672 );
673 }
6e50f7e9 674}
675
676sub _inline_check_constraint {
677 my $self = shift;
a619fc2f 678 my ($value, $tc, $message) = @_;
6e50f7e9 679
680 return unless $self->has_type_constraint;
681
682 my $attr_name = quotemeta($self->name);
683
7c047a36 684 if ( $self->type_constraint->can_be_inlined ) {
4e36cf24 685 return (
686 'if (! (' . $self->type_constraint->_inline_check($value) . ')) {',
687 $self->_inline_throw_error(
688 '"Attribute (' . $attr_name . ') does not pass the type '
689 . 'constraint because: " . '
a619fc2f 690 . 'do { local $_ = ' . $value . '; '
691 . $message . '->(' . $value . ')'
692 . '}',
4e36cf24 693 'data => ' . $value
694 ) . ';',
695 '}',
696 );
697 }
698 else {
699 return (
700 'if (!' . $tc . '->(' . $value . ')) {',
701 $self->_inline_throw_error(
702 '"Attribute (' . $attr_name . ') does not pass the type '
703 . 'constraint because: " . '
a619fc2f 704 . 'do { local $_ = ' . $value . '; '
705 . $message . '->(' . $value . ')'
706 . '}',
4e36cf24 707 'data => ' . $value
708 ) . ';',
709 '}',
710 );
711 }
6e50f7e9 712}
713
714sub _inline_get_old_value_for_trigger {
715 my $self = shift;
716 my ($instance, $old) = @_;
717
718 return unless $self->has_trigger;
719
720 return (
721 'my ' . $old . ' = ' . $self->_inline_instance_has($instance),
722 '? ' . $self->_inline_instance_get($instance),
723 ': ();',
724 );
725}
726
727sub _inline_weaken_value {
728 my $self = shift;
729 my ($instance, $value) = @_;
730
731 return unless $self->is_weak_ref;
732
733 my $mi = $self->associated_class->get_meta_instance;
734 return (
735 $mi->inline_weaken_slot_value($instance, $self->name, $value),
736 'if ref ' . $value . ';',
737 );
738}
739
740sub _inline_trigger {
741 my $self = shift;
742 my ($instance, $value, $old) = @_;
743
744 return unless $self->has_trigger;
745
37ffa261 746 return '$trigger->(' . $instance . ', ' . $value . ', ' . $old . ');';
6e50f7e9 747}
748
f7db8e35 749sub _eval_environment {
750 my $self = shift;
751
752 my $env = { };
753
754 $env->{'$trigger'} = \($self->trigger)
755 if $self->has_trigger;
756 $env->{'$attr_default'} = \($self->default)
757 if $self->has_default;
758
759 if ($self->has_type_constraint) {
760 my $tc_obj = $self->type_constraint;
761
762 $env->{'$type_constraint'} = \(
763 $tc_obj->_compiled_type_constraint
764 ) unless $tc_obj->can_be_inlined;
765 # these two could probably get inlined versions too
766 $env->{'$type_coercion'} = \(
767 $tc_obj->coercion->_compiled_type_coercion
768 ) if $tc_obj->has_coercion;
769 $env->{'$type_message'} = \(
770 $tc_obj->has_message ? $tc_obj->message : $tc_obj->_default_message
771 );
772
773 $env = { %$env, %{ $tc_obj->inline_environment } };
774 }
775
776 # XXX ugh, fix these
777 $env->{'$attr'} = \$self
778 if $self->has_initializer && $self->is_lazy;
779 # pretty sure this is only going to be closed over if you use a custom
780 # error class at this point, but we should still get rid of this
781 # at some point
782 $env->{'$meta'} = \($self->associated_class);
783
784 return $env;
785}
786
32881f68 787sub _weaken_value {
312e0f0c 788 my ( $self, $instance ) = @_;
789
32881f68 790 my $meta_instance = Class::MOP::Class->initialize( blessed($instance) )
791 ->get_meta_instance;
312e0f0c 792
793 $meta_instance->weaken_slot_value( $instance, $self->name );
794}
795
946289d1 796sub get_value {
3dda07f5 797 my ($self, $instance, $for_trigger) = @_;
26fbace8 798
946289d1 799 if ($self->is_lazy) {
8de73ff1 800 unless ($self->has_value($instance)) {
e606ae5f 801 my $value;
8de73ff1 802 if ($self->has_default) {
e606ae5f 803 $value = $self->default($instance);
3f11800d 804 } elsif ( $self->has_builder ) {
e606ae5f 805 $value = $self->_call_builder($instance);
806 }
9c9563c7 807
808 $value = $self->_coerce_and_verify( $value, $instance );
809
e606ae5f 810 $self->set_initial_value($instance, $value);
8de73ff1 811 }
946289d1 812 }
26fbace8 813
3dda07f5 814 if ( $self->should_auto_deref && ! $for_trigger ) {
26fbace8 815
946289d1 816 my $type_constraint = $self->type_constraint;
817
818 if ($type_constraint->is_a_type_of('ArrayRef')) {
819 my $rv = $self->SUPER::get_value($instance);
820 return unless defined $rv;
821 return wantarray ? @{ $rv } : $rv;
26fbace8 822 }
946289d1 823 elsif ($type_constraint->is_a_type_of('HashRef')) {
824 my $rv = $self->SUPER::get_value($instance);
825 return unless defined $rv;
826 return wantarray ? %{ $rv } : $rv;
26fbace8 827 }
946289d1 828 else {
46cb090f 829 $self->throw_error("Can not auto de-reference the type constraint '" . $type_constraint->name . "'", object => $instance, type_constraint => $type_constraint);
946289d1 830 }
26fbace8 831
946289d1 832 }
833 else {
26fbace8 834
946289d1 835 return $self->SUPER::get_value($instance);
26fbace8 836 }
946289d1 837}
a15dff8d 838
6e50f7e9 839sub _inline_get_value {
840 my $self = shift;
a619fc2f 841 my ($instance, $tc, $coercion, $message) = @_;
6e50f7e9 842
843 my $slot_access = $self->_inline_instance_get($instance);
ec86bdff 844 $tc ||= '$type_constraint';
c40e4359 845 $coercion ||= '$type_coercion';
a619fc2f 846 $message ||= '$type_message';
6e50f7e9 847
848 return (
a619fc2f 849 $self->_inline_check_lazy($instance, $tc, $coercion, $message),
6e50f7e9 850 $self->_inline_return_auto_deref($slot_access),
851 );
852}
853
854sub _inline_check_lazy {
855 my $self = shift;
a619fc2f 856 my ($instance, $tc, $coercion, $message) = @_;
6e50f7e9 857
858 return unless $self->is_lazy;
859
860 my $slot_exists = $self->_inline_instance_has($instance);
861
862 return (
863 'if (!' . $slot_exists . ') {',
a619fc2f 864 $self->_inline_init_from_default($instance, '$default', $tc, $coercion, $message, 'lazy'),
6e50f7e9 865 '}',
866 );
867}
868
869sub _inline_init_from_default {
870 my $self = shift;
a619fc2f 871 my ($instance, $default, $tc, $coercion, $message, $for_lazy) = @_;
6e50f7e9 872
873 if (!($self->has_default || $self->has_builder)) {
874 $self->throw_error(
875 'You cannot have a lazy attribute '
876 . '(' . $self->name . ') '
877 . 'without specifying a default value for it',
878 attr => $self,
879 );
880 }
881
882 return (
883 $self->_inline_generate_default($instance, $default),
884 # intentionally not using _inline_tc_code, since that can be overridden
885 # to do things like possibly only do member tc checks, which isn't
886 # appropriate for checking the result of a default
887 $self->has_type_constraint
c40e4359 888 ? ($self->_inline_check_coercion($default, $tc, $coercion, $for_lazy),
a619fc2f 889 $self->_inline_check_constraint($default, $tc, $message, $for_lazy))
6e50f7e9 890 : (),
891 $self->_inline_init_slot($instance, $default),
892 );
893}
894
895sub _inline_generate_default {
896 my $self = shift;
897 my ($instance, $default) = @_;
898
899 if ($self->has_default) {
0ec49767 900 my $source = 'my ' . $default . ' = $attr_default';
37ffa261 901 $source .= '->(' . $instance . ')'
902 if $self->is_default_a_coderef;
903 return $source . ';';
6e50f7e9 904 }
905 elsif ($self->has_builder) {
37ffa261 906 my $builder = B::perlstring($self->builder);
907 my $builder_str = quotemeta($self->builder);
908 my $attr_name_str = quotemeta($self->name);
6e50f7e9 909 return (
910 'my ' . $default . ';',
37ffa261 911 'if (my $builder = ' . $instance . '->can(' . $builder . ')) {',
6e50f7e9 912 $default . ' = ' . $instance . '->$builder;',
913 '}',
914 'else {',
915 'my $class = ref(' . $instance . ') || ' . $instance . ';',
6e50f7e9 916 $self->_inline_throw_error(
917 '"$class does not support builder method '
37ffa261 918 . '\'' . $builder_str . '\' for attribute '
919 . '\'' . $attr_name_str . '\'"'
6e50f7e9 920 ) . ';',
921 '}',
922 );
923 }
924 else {
925 $self->throw_error(
926 "Can't generate a default for " . $self->name
927 . " since no default or builder was specified"
928 );
929 }
930}
931
932sub _inline_init_slot {
933 my $self = shift;
934 my ($inv, $value) = @_;
935
936 if ($self->has_initializer) {
937 return '$attr->set_initial_value(' . $inv . ', ' . $value . ');';
938 }
939 else {
940 return $self->_inline_instance_set($inv, $value) . ';';
941 }
942}
943
944sub _inline_return_auto_deref {
945 my $self = shift;
946
947 return 'return ' . $self->_auto_deref(@_) . ';';
948}
949
950sub _auto_deref {
951 my $self = shift;
952 my ($ref_value) = @_;
953
954 return $ref_value unless $self->should_auto_deref;
955
956 my $type_constraint = $self->type_constraint;
957
958 my $sigil;
959 if ($type_constraint->is_a_type_of('ArrayRef')) {
960 $sigil = '@';
961 }
962 elsif ($type_constraint->is_a_type_of('HashRef')) {
963 $sigil = '%';
964 }
965 else {
966 $self->throw_error(
967 'Can not auto de-reference the type constraint \''
968 . $type_constraint->name
969 . '\'',
970 type_constraint => $type_constraint,
971 );
972 }
973
974 return 'wantarray '
975 . '? ' . $sigil . '{ (' . $ref_value . ') || return } '
976 . ': (' . $ref_value . ')';
977}
978
26fbace8 979## installing accessors
c0e30cf5 980
246bbeef 981sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
982
983sub install_accessors {
ae907ae0 984 my $self = shift;
246bbeef 985 $self->SUPER::install_accessors(@_);
986 $self->install_delegation if $self->has_handles;
28af3424 987 return;
988}
989
9340e346 990sub _check_associated_methods {
28af3424 991 my $self = shift;
86cf196b 992 unless (
0bbd378f 993 @{ $self->associated_methods }
86cf196b 994 || ($self->_is_metadata || '') eq 'bare'
995 ) {
996 Carp::cluck(
8f4450f3 997 'Attribute (' . $self->name . ') of class '
998 . $self->associated_class->name
999 . ' has no associated methods'
86cf196b 1000 . ' (did you mean to provide an "is" argument?)'
1001 . "\n"
1002 )
1003 }
e606ae5f 1004}
26fbace8 1005
3b6e2290 1006sub _process_accessors {
1007 my $self = shift;
1008 my ($type, $accessor, $generate_as_inline_methods) = @_;
837f61c9 1009
1010 $accessor = ( keys %$accessor )[0] if ( ref($accessor) || '' ) eq 'HASH';
99541dfd 1011 my $method = $self->associated_class->get_method($accessor);
837f61c9 1012
d7dfe605 1013 if ( $method
1014 && $method->isa('Class::MOP::Method::Accessor')
1015 && $method->associated_attribute->name ne $self->name ) {
1016
1017 my $other_attr_name = $method->associated_attribute->name;
1018 my $name = $self->name;
1019
1020 Carp::cluck(
1021 "You are overwriting an accessor ($accessor) for the $other_attr_name attribute"
1022 . " with a new accessor method for the $name attribute" );
1023 }
1024
837f61c9 1025 if (
1026 $method
1027 && !$method->isa('Class::MOP::Method::Accessor')
1028 && ( !$self->definition_context
1029 || $method->package_name eq $self->definition_context->{package} )
1030 ) {
1031
3b6e2290 1032 Carp::cluck(
1d18c898 1033 "You are overwriting a locally defined method ($accessor) with "
837f61c9 1034 . "an accessor" );
3b6e2290 1035 }
d7dfe605 1036
837f61c9 1037 if ( !$self->associated_class->has_method($accessor)
1038 && $self->associated_class->has_package_symbol( '&' . $accessor ) ) {
1039
3968746e 1040 Carp::cluck(
1041 "You are overwriting a locally defined function ($accessor) with "
837f61c9 1042 . "an accessor" );
3968746e 1043 }
837f61c9 1044
3b6e2290 1045 $self->SUPER::_process_accessors(@_);
e606ae5f 1046}
26fbace8 1047
e1d6f0a3 1048sub remove_accessors {
1049 my $self = shift;
1050 $self->SUPER::remove_accessors(@_);
1051 $self->remove_delegation if $self->has_handles;
1052 return;
1053}
1054
e606ae5f 1055sub install_delegation {
1056 my $self = shift;
26fbace8 1057
e606ae5f 1058 # NOTE:
1059 # Here we canonicalize the 'handles' option
1060 # this will sort out any details and always
1061 # return an hash of methods which we want
1062 # to delagate to, see that method for details
1063 my %handles = $self->_canonicalize_handles;
1064
e606ae5f 1065
1066 # install the delegation ...
1067 my $associated_class = $self->associated_class;
d699590f 1068 foreach my $handle (sort keys %handles) {
e606ae5f 1069 my $method_to_call = $handles{$handle};
1070 my $class_name = $associated_class->name;
1071 my $name = "${class_name}::${handle}";
26fbace8 1072
452bac1b 1073 (!$associated_class->has_method($handle))
cee532a1 1074 || $self->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation", method_name => $handle);
26fbace8 1075
e606ae5f 1076 # NOTE:
1077 # handles is not allowed to delegate
1078 # any of these methods, as they will
1079 # override the ones in your class, which
1080 # is almost certainly not what you want.
4fe78472 1081
e606ae5f 1082 # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
1083 #cluck("Not delegating method '$handle' because it is a core method") and
1084 next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 1085
46f7e6a5 1086 my $method = $self->_make_delegation_method($handle, $method_to_call);
a05f85c1 1087
1088 $self->associated_class->add_method($method->name, $method);
0bbd378f 1089 $self->associate_method($method);
d03bd989 1090 }
452bac1b 1091}
1092
e1d6f0a3 1093sub remove_delegation {
1094 my $self = shift;
1095 my %handles = $self->_canonicalize_handles;
1096 my $associated_class = $self->associated_class;
1097 foreach my $handle (keys %handles) {
684323b3 1098 next unless any { $handle eq $_ }
1099 map { $_->name }
1100 @{ $self->associated_methods };
e1d6f0a3 1101 $self->associated_class->remove_method($handle);
1102 }
1103}
1104
98aae381 1105# private methods to help delegation ...
1106
452bac1b 1107sub _canonicalize_handles {
1108 my $self = shift;
1109 my $handles = $self->handles;
c84f324f 1110 if (my $handle_type = ref($handles)) {
1111 if ($handle_type eq 'HASH') {
1112 return %{$handles};
1113 }
1114 elsif ($handle_type eq 'ARRAY') {
1115 return map { $_ => $_ } @{$handles};
1116 }
1117 elsif ($handle_type eq 'Regexp') {
1118 ($self->has_type_constraint)
0286711b 1119 || $self->throw_error("Cannot delegate methods based on a Regexp without a type constraint (isa)", data => $handles);
26fbace8 1120 return map { ($_ => $_) }
c84f324f 1121 grep { /$handles/ } $self->_get_delegate_method_list;
1122 }
1123 elsif ($handle_type eq 'CODE') {
1124 return $handles->($self, $self->_find_delegate_metaclass);
1125 }
6cbf4a23 1126 elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::DuckType')) {
1127 return map { $_ => $_ } @{ $handles->methods };
1128 }
c7761602 1129 elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::Role')) {
1130 $handles = $handles->role;
1131 }
c84f324f 1132 else {
be05faea 1133 $self->throw_error("Unable to canonicalize the 'handles' option with $handles", data => $handles);
c84f324f 1134 }
452bac1b 1135 }
c84f324f 1136
c7761602 1137 Class::MOP::load_class($handles);
1138 my $role_meta = Class::MOP::class_of($handles);
d03bd989 1139
c7761602 1140 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
1141 || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because its metaclass is not a Moose::Meta::Role", data => $handles);
1142
1143 return map { $_ => $_ }
ba7d613d 1144 map { $_->name }
1145 grep { !$_->isa('Class::MOP::Method::Meta') } (
1146 $role_meta->_get_local_methods,
1147 $role_meta->get_required_method_list,
c7761602 1148 );
452bac1b 1149}
1150
452bac1b 1151sub _get_delegate_method_list {
1152 my $self = shift;
1153 my $meta = $self->_find_delegate_metaclass;
1154 if ($meta->isa('Class::MOP::Class')) {
e606ae5f 1155 return map { $_->name } # NOTE: !never! delegate &meta
ba7d613d 1156 grep { $_->package_name ne 'Moose::Object' && !$_->isa('Class::MOP::Method::Meta') }
e606ae5f 1157 $meta->get_all_methods;
452bac1b 1158 }
1159 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 1160 return $meta->get_method_list;
452bac1b 1161 }
1162 else {
be05faea 1163 $self->throw_error("Unable to recognize the delegate metaclass '$meta'", data => $meta);
452bac1b 1164 }
1165}
1166
ccc2f11f 1167sub _find_delegate_metaclass {
1168 my $self = shift;
1169 if (my $class = $self->_isa_metadata) {
9238220f 1170 unless ( Class::MOP::is_class_loaded($class) ) {
1171 $self->throw_error(
1172 sprintf(
1173 'The %s attribute is trying to delegate to a class which has not been loaded - %s',
1174 $self->name, $class
1175 )
1176 );
1177 }
ccc2f11f 1178 # we might be dealing with a non-Moose class,
1179 # and need to make our own metaclass. if there's
1180 # already a metaclass, it will be returned
1181 return Class::MOP::Class->initialize($class);
1182 }
1183 elsif (my $role = $self->_does_metadata) {
9238220f 1184 unless ( Class::MOP::is_class_loaded($class) ) {
1185 $self->throw_error(
1186 sprintf(
1187 'The %s attribute is trying to delegate to a role which has not been loaded - %s',
1188 $self->name, $role
1189 )
1190 );
1191 }
1192
ccc2f11f 1193 return Class::MOP::class_of($role);
1194 }
1195 else {
1196 $self->throw_error("Cannot find delegate metaclass for attribute " . $self->name);
1197 }
1198}
1199
bd1226e2 1200sub delegation_metaclass { 'Moose::Meta::Method::Delegation' }
1201
a05f85c1 1202sub _make_delegation_method {
46f7e6a5 1203 my ( $self, $handle_name, $method_to_call ) = @_;
a05f85c1 1204
3c573ca4 1205 my @curried_arguments;
2de18801 1206
3c573ca4 1207 ($method_to_call, @curried_arguments) = @$method_to_call
2de18801 1208 if 'ARRAY' eq ref($method_to_call);
1209
bd1226e2 1210 return $self->delegation_metaclass->new(
46f7e6a5 1211 name => $handle_name,
1212 package_name => $self->associated_class->name,
1213 attribute => $self,
1214 delegate_to_method => $method_to_call,
3c573ca4 1215 curried_arguments => \@curried_arguments,
a05f85c1 1216 );
1217}
1218
9c9563c7 1219sub _coerce_and_verify {
1220 my $self = shift;
1221 my $val = shift;
1222 my $instance = shift;
1223
1224 return $val unless $self->has_type_constraint;
1225
2b54d2a6 1226 $val = $self->type_constraint->coerce($val)
5aab256d 1227 if $self->should_coerce && $self->type_constraint->has_coercion;
9c9563c7 1228
1229 $self->verify_against_type_constraint($val, instance => $instance);
1230
1231 return $val;
1232}
1233
5755a9b2 1234sub verify_against_type_constraint {
2b86e02b 1235 my $self = shift;
1236 my $val = shift;
1237
1238 return 1 if !$self->has_type_constraint;
1239
1240 my $type_constraint = $self->type_constraint;
1241
1242 $type_constraint->check($val)
1243 || $self->throw_error("Attribute ("
1244 . $self->name
1245 . ") does not pass the type constraint because: "
1246 . $type_constraint->get_message($val), data => $val, @_);
1247}
1248
21f1e231 1249package Moose::Meta::Attribute::Custom::Moose;
1250sub register_implementation { 'Moose::Meta::Attribute' }
1251
c0e30cf5 12521;
1253
ad46f524 1254# ABSTRACT: The Moose attribute metaclass
1255
c0e30cf5 1256__END__
1257
1258=pod
1259
c0e30cf5 1260=head1 DESCRIPTION
1261
93a708fd 1262This class is a subclass of L<Class::MOP::Attribute> that provides
1263additional Moose-specific functionality.
6ba6d68c 1264
7854b409 1265To really understand this class, you will need to start with the
1266L<Class::MOP::Attribute> documentation. This class can be understood
1267as a set of additional features on top of the basic feature provided
1268by that parent class.
e522431d 1269
d4b1449e 1270=head1 INHERITANCE
1271
1272C<Moose::Meta::Attribute> is a subclass of L<Class::MOP::Attribute>.
1273
c0e30cf5 1274=head1 METHODS
1275
93a708fd 1276Many of the documented below override methods in
1277L<Class::MOP::Attribute> and add Moose specific features.
6ba6d68c 1278
93a708fd 1279=head2 Creation
6ba6d68c 1280
c0e30cf5 1281=over 4
1282
93a708fd 1283=item B<< Moose::Meta::Attribute->new(%options) >>
c0e30cf5 1284
93a708fd 1285This method overrides the L<Class::MOP::Attribute> constructor.
c32c2c61 1286
93a708fd 1287Many of the options below are described in more detail in the
1288L<Moose::Manual::Attributes> document.
6e2840b7 1289
93a708fd 1290It adds the following options to the constructor:
d500266f 1291
93a708fd 1292=over 8
452bac1b 1293
996b8c8d 1294=item * is => 'ro', 'rw', 'bare'
e1d6f0a3 1295
93a708fd 1296This provides a shorthand for specifying the C<reader>, C<writer>, or
1297C<accessor> names. If the attribute is read-only ('ro') then it will
1298have a C<reader> method with the same attribute as the name.
e606ae5f 1299
93a708fd 1300If it is read-write ('rw') then it will have an C<accessor> method
1301with the same name. If you provide an explicit C<writer> for a
1302read-write attribute, then you will have a C<reader> with the same
1303name as the attribute, and a C<writer> with the name you provided.
e1d6f0a3 1304
996b8c8d 1305Use 'bare' when you are deliberately not installing any methods
1306(accessor, reader, etc.) associated with this attribute; otherwise,
1307Moose will issue a deprecation warning when this attribute is added to a
9340e346 1308metaclass.
996b8c8d 1309
93a708fd 1310=item * isa => $type
39b3bc94 1311
93a708fd 1312This option accepts a type. The type can be a string, which should be
1313a type name. If the type name is unknown, it is assumed to be a class
1314name.
1315
1316This option can also accept a L<Moose::Meta::TypeConstraint> object.
1317
1318If you I<also> provide a C<does> option, then your C<isa> option must
1319be a class name, and that class must do the role specified with
1320C<does>.
1321
1322=item * does => $role
1323
1324This is short-hand for saying that the attribute's type must be an
1325object which does the named role.
1326
1327=item * coerce => $bool
1328
1329This option is only valid for objects with a type constraint
3b98ba07 1330(C<isa>) that defined a coercion. If this is true, then coercions will be applied whenever
93a708fd 1331this attribute is set.
1332
1333You can make both this and the C<weak_ref> option true.
1334
1335=item * trigger => $sub
1336
1337This option accepts a subroutine reference, which will be called after
1338the attribute is set.
1339
1340=item * required => $bool
1341
1342An attribute which is required must be provided to the constructor. An
1343attribute which is required can also have a C<default> or C<builder>,
36741534 1344which will satisfy its required-ness.
93a708fd 1345
1346A required attribute must have a C<default>, C<builder> or a
1347non-C<undef> C<init_arg>
1348
1349=item * lazy => $bool
1350
1351A lazy attribute must have a C<default> or C<builder>. When an
1352attribute is lazy, the default value will not be calculated until the
1353attribute is read.
1354
1355=item * weak_ref => $bool
1356
1357If this is true, the attribute's value will be stored as a weak
1358reference.
1359
1360=item * auto_deref => $bool
1361
1362If this is true, then the reader will dereference the value when it is
1363called. The attribute must have a type constraint which defines the
1364attribute as an array or hash reference.
1365
1366=item * lazy_build => $bool
1367
1368Setting this to true makes the attribute lazy and provides a number of
1369default methods.
1370
1371 has 'size' => (
1372 is => 'ro',
1373 lazy_build => 1,
1374 );
1375
1376is equivalent to this:
1377
1378 has 'size' => (
1379 is => 'ro',
1380 lazy => 1,
1381 builder => '_build_size',
1382 clearer => 'clear_size',
1383 predicate => 'has_size',
1384 );
1385
970a92fa 1386
1387If your attribute name starts with an underscore (C<_>), then the clearer
1388and predicate will as well:
1389
1390 has '_size' => (
1391 is => 'ro',
1392 lazy_build => 1,
1393 );
1394
1395becomes:
1396
1397 has '_size' => (
1398 is => 'ro',
1399 lazy => 1,
1400 builder => '_build__size',
1401 clearer => '_clear_size',
1402 predicate => '_has_size',
1403 );
1404
1405Note the doubled underscore in the builder name. Internally, Moose
1406simply prepends the attribute name with "_build_" to come up with the
1407builder name.
1408
93a708fd 1409=item * documentation
1410
1411An arbitrary string that can be retrieved later by calling C<<
1412$attr->documentation >>.
1413
1414=back
1415
1416=item B<< $attr->clone(%options) >>
1417
1418This creates a new attribute based on attribute being cloned. You must
1419supply a C<name> option to provide a new name for the attribute.
1420
1421The C<%options> can only specify options handled by
1422L<Class::MOP::Attribute>.
1423
36741534 1424=back
1425
93a708fd 1426=head2 Value management
1427
36741534 1428=over 4
1429
93a708fd 1430=item B<< $attr->initialize_instance_slot($meta_instance, $instance, $params) >>
1431
1432This method is used internally to initialize the attribute's slot in
1433the object C<$instance>.
1434
1435This overrides the L<Class::MOP::Attribute> method to handle lazy
1436attributes, weak references, and type constraints.
bd1226e2 1437
946289d1 1438=item B<get_value>
1439
1440=item B<set_value>
1441
6549b0d1 1442 eval { $point->meta->get_attribute('x')->set_value($point, 'forty-two') };
bcbaa845 1443 if($@) {
1444 print "Oops: $@\n";
1445 }
1446
6549b0d1 1447I<Attribute (x) does not pass the type constraint (Int) with 'forty-two'>
bcbaa845 1448
1449Before setting the value, a check is made on the type constraint of
1450the attribute, if it has one, to see if the value passes it. If the
cec39889 1451value fails to pass, the set operation dies with a L</throw_error>.
bcbaa845 1452
1453Any coercion to convert values is done before checking the type constraint.
1454
1455To check a value against a type constraint before setting it, fetch the
ec00fa75 1456attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 1457fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
e606ae5f 1458and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Recipe4>
bcbaa845 1459for an example.
1460
a15dff8d 1461=back
1462
93a708fd 1463=head2 Attribute Accessor generation
6ba6d68c 1464
a15dff8d 1465=over 4
1466
93a708fd 1467=item B<< $attr->install_accessors >>
be05faea 1468
93a708fd 1469This method overrides the parent to also install delegation methods.
be05faea 1470
7a582117 1471If, after installing all methods, the attribute object has no associated
1472methods, it throws an error unless C<< is => 'bare' >> was passed to the
1473attribute constructor. (Trying to add an attribute that has no associated
1474methods is almost always an error.)
1475
36741534 1476=item B<< $attr->remove_accessors >>
d5c30e52 1477
93a708fd 1478This method overrides the parent to also remove delegation methods.
d5c30e52 1479
e06951bb 1480=item B<< $attr->inline_set($instance_var, $value_var) >>
d67398ab 1481
e06951bb 1482This method return a code snippet suitable for inlining the relevant
1483operation. It expect strings containing variable names to be used in the
1484inlining, like C<'$self'> or C<'$_[1]'>.
d67398ab 1485
93a708fd 1486=item B<< $attr->install_delegation >>
1487
1488This method adds its delegation methods to the attribute's associated
1489class, if it has any to add.
1490
1491=item B<< $attr->remove_delegation >>
1492
1493This method remove its delegation methods from the attribute's
1494associated class.
d5c30e52 1495
93a708fd 1496=item B<< $attr->accessor_metaclass >>
9e93dd19 1497
93a708fd 1498Returns the accessor metaclass name, which defaults to
1499L<Moose::Meta::Method::Accessor>.
1500
1501=item B<< $attr->delegation_metaclass >>
1502
1503Returns the delegation metaclass name, which defaults to
1504L<Moose::Meta::Method::Delegation>.
1505
1506=back
1507
1508=head2 Additional Moose features
1509
1510These methods are not found in the superclass. They support features
1511provided by Moose.
1512
36741534 1513=over 4
1514
93a708fd 1515=item B<< $attr->does($role) >>
1516
1517This indicates whether the I<attribute itself> does the given
36741534 1518role. The role can be given as a full class name, or as a resolvable
93a708fd 1519trait name.
1520
1521Note that this checks the attribute itself, not its type constraint,
1522so it is checking the attribute's metaclass and any traits applied to
1523the attribute.
1524
1525=item B<< Moose::Meta::Class->interpolate_class_and_new($name, %options) >>
1526
1527This is an alternate constructor that handles the C<metaclass> and
1528C<traits> options.
9e93dd19 1529
93a708fd 1530Effectively, this method is a factory that finds or creates the
36741534 1531appropriate class for the given C<metaclass> and/or C<traits>.
e606ae5f 1532
93a708fd 1533Once it has the appropriate class, it will call C<< $class->new($name,
1534%options) >> on that class.
e606ae5f 1535
93a708fd 1536=item B<< $attr->clone_and_inherit_options(%options) >>
a15dff8d 1537
93a708fd 1538This method supports the C<has '+foo'> feature. It does various bits
1539of processing on the supplied C<%options> before ultimately calling
1540the C<clone> method.
6ba6d68c 1541
93a708fd 1542One of its main tasks is to make sure that the C<%options> provided
7782e1da 1543does not include the options returned by the
1544C<illegal_options_for_inheritance> method.
a15dff8d 1545
7782e1da 1546=item B<< $attr->illegal_options_for_inheritance >>
a15dff8d 1547
7782e1da 1548This returns a blacklist of options that can not be overridden in a
93a708fd 1549subclass's attribute definition.
2b86e02b 1550
93a708fd 1551This exists to allow a custom metaclass to change or add to the list
7782e1da 1552of options which can not be changed.
2b86e02b 1553
93a708fd 1554=item B<< $attr->type_constraint >>
452bac1b 1555
93a708fd 1556Returns the L<Moose::Meta::TypeConstraint> object for this attribute,
1557if it has one.
452bac1b 1558
93a708fd 1559=item B<< $attr->has_type_constraint >>
452bac1b 1560
93a708fd 1561Returns true if this attribute has a type constraint.
452bac1b 1562
93a708fd 1563=item B<< $attr->verify_against_type_constraint($value) >>
a15dff8d 1564
93a708fd 1565Given a value, this method returns true if the value is valid for the
1566attribute's type constraint. If the value is not valid, it throws an
1567error.
4b598ea3 1568
93a708fd 1569=item B<< $attr->handles >>
ca01a97b 1570
93a708fd 1571This returns the value of the C<handles> option passed to the
1572constructor.
ca01a97b 1573
93a708fd 1574=item B<< $attr->has_handles >>
ca01a97b 1575
93a708fd 1576Returns true if this attribute performs delegation.
ca01a97b 1577
93a708fd 1578=item B<< $attr->is_weak_ref >>
26fbace8 1579
93a708fd 1580Returns true if this attribute stores its value as a weak reference.
26fbace8 1581
93a708fd 1582=item B<< $attr->is_required >>
26fbace8 1583
93a708fd 1584Returns true if this attribute is required to have a value.
26fbace8 1585
93a708fd 1586=item B<< $attr->is_lazy >>
58f85113 1587
93a708fd 1588Returns true if this attribute is lazy.
26fbace8 1589
93a708fd 1590=item B<< $attr->is_lazy_build >>
ca01a97b 1591
93a708fd 1592Returns true if the C<lazy_build> option was true when passed to the
1593constructor.
4b598ea3 1594
93a708fd 1595=item B<< $attr->should_coerce >>
6ba6d68c 1596
93a708fd 1597Returns true if the C<coerce> option passed to the constructor was
1598true.
536f0b17 1599
93a708fd 1600=item B<< $attr->should_auto_deref >>
536f0b17 1601
93a708fd 1602Returns true if the C<auto_deref> option passed to the constructor was
1603true.
536f0b17 1604
93a708fd 1605=item B<< $attr->trigger >>
8c9d74e7 1606
93a708fd 1607This is the subroutine reference that was in the C<trigger> option
1608passed to the constructor, if any.
02a0fb52 1609
36741534 1610=item B<< $attr->has_trigger >>
8c9d74e7 1611
93a708fd 1612Returns true if this attribute has a trigger set.
02a0fb52 1613
93a708fd 1614=item B<< $attr->documentation >>
ddbdc0cb 1615
93a708fd 1616Returns the value that was in the C<documentation> option passed to
1617the constructor, if any.
ddbdc0cb 1618
93a708fd 1619=item B<< $attr->has_documentation >>
ddbdc0cb 1620
93a708fd 1621Returns true if this attribute has any documentation.
ddbdc0cb 1622
93a708fd 1623=item B<< $attr->applied_traits >>
88f23977 1624
93a708fd 1625This returns an array reference of all the traits which were applied
1626to this attribute. If none were applied, this returns C<undef>.
88f23977 1627
93a708fd 1628=item B<< $attr->has_applied_traits >>
88f23977 1629
93a708fd 1630Returns true if this attribute has any traits applied.
88f23977 1631
c0e30cf5 1632=back
1633
1634=head1 BUGS
1635
d4048ef3 1636See L<Moose/BUGS> for details on reporting bugs.
c0e30cf5 1637
8a7a9c53 1638=cut