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