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