support traits/metaclasses in clone_and_inherit_whatever_id_dont_remember_the_name_of...
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
CommitLineData
c0e30cf5 1
2package Moose::Meta::Attribute;
3
4use strict;
5use warnings;
6
78cd1d3b 7use Scalar::Util 'blessed', 'weaken', 'reftype';
a15dff8d 8use Carp 'confess';
7dbbdcab 9use Sub::Name 'subname';
a909a4df 10use overload ();
a15dff8d 11
80d955e4 12our $VERSION = '0.22';
d44714be 13our $AUTHORITY = 'cpan:STEVAN';
78cd1d3b 14
8ee73eeb 15use Moose::Meta::Method::Accessor;
d5c30e52 16use Moose::Util ();
a3c7e2fe 17use Moose::Util::TypeConstraints ();
bc1e29b5 18
c0e30cf5 19use base 'Class::MOP::Attribute';
20
452bac1b 21# options which are not directly used
22# but we store them for metadata purposes
98aae381 23__PACKAGE__->meta->add_attribute('isa' => (reader => '_isa_metadata'));
24__PACKAGE__->meta->add_attribute('does' => (reader => '_does_metadata'));
25__PACKAGE__->meta->add_attribute('is' => (reader => '_is_metadata'));
452bac1b 26
27# these are actual options for the attrs
1a563243 28__PACKAGE__->meta->add_attribute('required' => (reader => 'is_required' ));
29__PACKAGE__->meta->add_attribute('lazy' => (reader => 'is_lazy' ));
26fbace8 30__PACKAGE__->meta->add_attribute('lazy_build' => (reader => 'is_lazy_build' ));
1a563243 31__PACKAGE__->meta->add_attribute('coerce' => (reader => 'should_coerce' ));
32__PACKAGE__->meta->add_attribute('weak_ref' => (reader => 'is_weak_ref' ));
33__PACKAGE__->meta->add_attribute('auto_deref' => (reader => 'should_auto_deref'));
82168dbb 34__PACKAGE__->meta->add_attribute('type_constraint' => (
35 reader => 'type_constraint',
36 predicate => 'has_type_constraint',
37));
8c9d74e7 38__PACKAGE__->meta->add_attribute('trigger' => (
39 reader => 'trigger',
40 predicate => 'has_trigger',
41));
452bac1b 42__PACKAGE__->meta->add_attribute('handles' => (
43 reader => 'handles',
44 predicate => 'has_handles',
45));
ddbdc0cb 46__PACKAGE__->meta->add_attribute('documentation' => (
47 reader => 'documentation',
48 predicate => 'has_documentation',
49));
82a5b1a7 50__PACKAGE__->meta->add_attribute('traits' => (
51 reader => 'applied_traits',
52 predicate => 'has_applied_traits',
53));
82168dbb 54
587e457d 55# NOTE:
56# we need to have a ->does method in here to
57# more easily support traits, and the introspection
58# of those traits. So in order to do this we
59# just alias Moose::Object's version of it.
60# - SL
61*does = \&Moose::Object::does;
62
78cd1d3b 63sub new {
f3c4e20e 64 my ($class, $name, %options) = @_;
c32c2c61 65 $class->_process_options($name, \%options) unless $options{__hack_no_process_options}; # used from clone()... YECHKKK FIXME ICKY YUCK GROSS
f3c4e20e 66 return $class->SUPER::new($name, %options);
1d768fb1 67}
68
d5c30e52 69sub interpolate_class_and_new {
70 my ($class, $name, @args) = @_;
71
c32c2c61 72 my ( $new_class, @traits ) = $class->interpolate_class(@args);
73
74 $new_class->new($name, @args, ( scalar(@traits) ? ( traits => \@traits ) : () ) );
d5c30e52 75}
76
77sub interpolate_class {
78 my ($class, %options) = @_;
79
c32c2c61 80 $class = ref($class) || $class;
81
82 if ( my $metaclass_name = delete $options{metaclass} ) {
83 my $new_class = Moose::Util::resolve_metaclass_alias( Attribute => $metaclass_name );
84
85 if ( $class ne $new_class ) {
86 if ( $new_class->can("interpolate_class") ) {
87 return $new_class->interpolate_class(%options);
88 } else {
89 $class = $new_class;
90 }
91 }
d5c30e52 92 }
93
c32c2c61 94 my @traits;
95
d5c30e52 96 if (my $traits = $options{traits}) {
c32c2c61 97 if ( @traits = grep { not $class->does($_) } map {
d5c30e52 98 Moose::Util::resolve_metatrait_alias( Attribute => $_ )
99 or
100 $_
c32c2c61 101 } @$traits ) {
102 my $anon_class = Moose::Meta::Class->create_anon_class(
103 superclasses => [ $class ],
104 roles => [ @traits ],
105 cache => 1,
106 );
107
108 $class = $anon_class->name;
109 }
d5c30e52 110 }
c32c2c61 111
112 return ( wantarray ? ( $class, @traits ) : $class );
d5c30e52 113}
114
ce0e8d63 115sub clone_and_inherit_options {
116 my ($self, %options) = @_;
c32c2c61 117 my %copy = %options;
118 # you can change default, required, coerce, documentation, lazy, handles, builder, type_constraint (explicitly or using isa/does), metaclass and traits
ce0e8d63 119 my %actual_options;
c32c2c61 120 foreach my $legal_option (qw(default coerce required documentation lazy handles builder type_constraint)) {
ce0e8d63 121 if (exists $options{$legal_option}) {
122 $actual_options{$legal_option} = $options{$legal_option};
123 delete $options{$legal_option};
124 }
125 }
26fbace8 126
ce0e8d63 127 if ($options{isa}) {
128 my $type_constraint;
8de73ff1 129 if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
130 $type_constraint = $options{isa};
131 }
132 else {
d40ce9d5 133 $type_constraint = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options{isa});
8de73ff1 134 (defined $type_constraint)
135 || confess "Could not find the type constraint '" . $options{isa} . "'";
136 }
5e98d2b6 137
8de73ff1 138 $actual_options{type_constraint} = $type_constraint;
ce0e8d63 139 delete $options{isa};
140 }
2ea379cb 141
142 if ($options{does}) {
143 my $type_constraint;
144 if (blessed($options{does}) && $options{does}->isa('Moose::Meta::TypeConstraint')) {
145 $type_constraint = $options{does};
146 }
147 else {
d40ce9d5 148 $type_constraint = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options{does});
2ea379cb 149 (defined $type_constraint)
150 || confess "Could not find the type constraint '" . $options{does} . "'";
151 }
152
153 $actual_options{type_constraint} = $type_constraint;
154 delete $options{does};
155 }
c32c2c61 156
157 ( $actual_options{metaclass}, my @traits ) = $self->interpolate_class(%options);
158
159 my %seen;
160 my @all_traits = grep { $seen{$_}++ } @{ $self->applied_traits || [] }, @traits;
161 $actual_options{traits} = \@all_traits if @all_traits;
162
163 delete @options{qw(metaclass traits)};
164
26fbace8 165 (scalar keys %options == 0)
ce0e8d63 166 || confess "Illegal inherited options => (" . (join ', ' => keys %options) . ")";
c32c2c61 167
168
ce0e8d63 169 $self->clone(%actual_options);
1d768fb1 170}
171
c32c2c61 172sub clone {
173 my ( $self, %params ) = @_;
174
175 my $class = $params{metaclass} || ref $self;
176
177 if ( 0 and $class eq ref $self ) {
178 return $self->SUPER::clone(%params);
179 } else {
180 my ( @init, @non_init );
181
182 foreach my $attr ( grep { $_->has_value($self) } $self->meta->compute_all_applicable_attributes ) {
183 push @{ $attr->has_init_arg ? \@init : \@non_init }, $attr;
184 }
185
186 my %new_params = ( ( map { $_->init_arg => $_->get_value($self) } @init ), %params );
187
188 my $name = delete $new_params{name};
189
190 my $clone = $class->new($name, %new_params, __hack_no_process_options => 1 );
191
192 foreach my $attr ( @non_init ) {
193 $attr->set_value($clone, $attr->get_value($self));
194 }
195
196
197 return $clone;
198 }
199}
200
1d768fb1 201sub _process_options {
202 my ($class, $name, $options) = @_;
8de73ff1 203
f3c4e20e 204 if (exists $options->{is}) {
8de73ff1 205 if ($options->{is} eq 'ro') {
206 $options->{reader} ||= $name;
207 (!exists $options->{trigger})
7dbda458 208 || confess "Cannot have a trigger on a read-only attribute $name";
8de73ff1 209 }
210 elsif ($options->{is} eq 'rw') {
211 $options->{accessor} = $name;
212 ((reftype($options->{trigger}) || '') eq 'CODE')
213 || confess "Trigger must be a CODE ref"
214 if exists $options->{trigger};
215 }
216 else {
7dbda458 217 confess "I do not understand this option (is => " . $options->{is} . ") on attribute $name"
8de73ff1 218 }
f3c4e20e 219 }
8de73ff1 220
f3c4e20e 221 if (exists $options->{isa}) {
f3c4e20e 222 if (exists $options->{does}) {
223 if (eval { $options->{isa}->can('does') }) {
224 ($options->{isa}->does($options->{does}))
7dbda458 225 || confess "Cannot have an isa option and a does option if the isa does not do the does on attribute $name";
f3c4e20e 226 }
227 else {
7dbda458 228 confess "Cannot have an isa option which cannot ->does() on attribute $name";
26fbace8 229 }
26fbace8 230 }
8de73ff1 231
f3c4e20e 232 # allow for anon-subtypes here ...
233 if (blessed($options->{isa}) && $options->{isa}->isa('Moose::Meta::TypeConstraint')) {
8de73ff1 234 $options->{type_constraint} = $options->{isa};
235 }
236 else {
620db045 237 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options->{isa});
8de73ff1 238 }
f3c4e20e 239 }
240 elsif (exists $options->{does}) {
241 # allow for anon-subtypes here ...
242 if (blessed($options->{does}) && $options->{does}->isa('Moose::Meta::TypeConstraint')) {
238b424d 243 $options->{type_constraint} = $options->{does};
8de73ff1 244 }
245 else {
620db045 246 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options->{does});
8de73ff1 247 }
f3c4e20e 248 }
8de73ff1 249
f3c4e20e 250 if (exists $options->{coerce} && $options->{coerce}) {
251 (exists $options->{type_constraint})
7dbda458 252 || confess "You cannot have coercion without specifying a type constraint on attribute $name";
253 confess "You cannot have a weak reference to a coerced value on attribute $name"
8de73ff1 254 if $options->{weak_ref};
f3c4e20e 255 }
8de73ff1 256
f3c4e20e 257 if (exists $options->{auto_deref} && $options->{auto_deref}) {
258 (exists $options->{type_constraint})
7dbda458 259 || confess "You cannot auto-dereference without specifying a type constraint on attribute $name";
f3c4e20e 260 ($options->{type_constraint}->is_a_type_of('ArrayRef') ||
8de73ff1 261 $options->{type_constraint}->is_a_type_of('HashRef'))
7dbda458 262 || confess "You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute $name";
f3c4e20e 263 }
8de73ff1 264
f3c4e20e 265 if (exists $options->{lazy_build} && $options->{lazy_build} == 1) {
7dbda458 266 confess("You can not use lazy_build and default for the same attribute $name")
8de73ff1 267 if exists $options->{default};
a6c84c69 268 $options->{lazy} = 1;
269 $options->{required} = 1;
270 $options->{builder} ||= "_build_${name}";
271 if ($name =~ /^_/) {
f3c4e20e 272 $options->{clearer} ||= "_clear${name}";
273 $options->{predicate} ||= "_has${name}";
a6c84c69 274 }
275 else {
f3c4e20e 276 $options->{clearer} ||= "clear_${name}";
277 $options->{predicate} ||= "has_${name}";
26fbace8 278 }
f3c4e20e 279 }
8de73ff1 280
f3c4e20e 281 if (exists $options->{lazy} && $options->{lazy}) {
9edba990 282 (exists $options->{default} || defined $options->{builder} )
7dbda458 283 || confess "You cannot have lazy attribute ($name) without specifying a default value for it";
f3c4e20e 284 }
26fbace8 285
9edba990 286 if ( $options->{required} && !( ( !exists $options->{init_arg} || defined $options->{init_arg} ) || exists $options->{default} || defined $options->{builder} ) ) {
7dbda458 287 confess "You cannot have a required attribute ($name) without a default, builder, or an init_arg";
9edba990 288 }
289
78cd1d3b 290}
c0e30cf5 291
d500266f 292sub initialize_instance_slot {
ddd0ec20 293 my ($self, $meta_instance, $instance, $params) = @_;
d500266f 294 my $init_arg = $self->init_arg();
295 # try to fetch the init arg from the %params ...
ddd0ec20 296
26fbace8 297 my $val;
1ed0b94f 298 my $value_is_set;
625d571f 299 if ( defined($init_arg) and exists $params->{$init_arg}) {
d500266f 300 $val = $params->{$init_arg};
2c78d811 301 $value_is_set = 1;
d500266f 302 }
303 else {
304 # skip it if it's lazy
305 return if $self->is_lazy;
306 # and die if it's required and doesn't have a default value
26fbace8 307 confess "Attribute (" . $self->name . ") is required"
308 if $self->is_required && !$self->has_default && !$self->has_builder;
ddd0ec20 309
1ed0b94f 310 # if nothing was in the %params, we can use the
311 # attribute's default value (if it has one)
312 if ($self->has_default) {
313 $val = $self->default($instance);
314 $value_is_set = 1;
a6c84c69 315 }
316 elsif ($self->has_builder) {
317 if (my $builder = $instance->can($self->builder)){
1ed0b94f 318 $val = $instance->$builder;
319 $value_is_set = 1;
a6c84c69 320 }
321 else {
0b26305c 322 confess(blessed($instance)." does not support builder method '".$self->builder."' for attribute '" . $self->name . "'");
1ed0b94f 323 }
a0748c37 324 }
26fbace8 325 }
326
1ed0b94f 327 return unless $value_is_set;
328
329 if ($self->has_type_constraint) {
330 my $type_constraint = $self->type_constraint;
331 if ($self->should_coerce && $type_constraint->has_coercion) {
332 $val = $type_constraint->coerce($val);
d500266f 333 }
ab76842e 334 $type_constraint->check($val)
688fcdda 335 || confess "Attribute ("
336 . $self->name
337 . ") does not pass the type constraint because: "
338 . $type_constraint->get_message($val);
1ed0b94f 339 }
ddd0ec20 340
759e4e8f 341 $self->set_initial_value($instance, $val);
26fbace8 342 $meta_instance->weaken_slot_value($instance, $self->name)
a6c84c69 343 if ref $val && $self->is_weak_ref;
d500266f 344}
345
d617b644 346## Slot management
9e93dd19 347
8abe9636 348# FIXME:
349# this duplicates too much code from
350# Class::MOP::Attribute, we need to
351# refactor these bits eventually.
352# - SL
353sub _set_initial_slot_value {
354 my ($self, $meta_instance, $instance, $value) = @_;
355
356 my $slot_name = $self->name;
357
358 return $meta_instance->set_slot_value($instance, $slot_name, $value)
359 unless $self->has_initializer;
360
361 my ($type_constraint, $can_coerce);
362 if ($self->has_type_constraint) {
363 $type_constraint = $self->type_constraint;
364 $can_coerce = ($self->should_coerce && $type_constraint->has_coercion);
365 }
366
367 my $callback = sub {
368 my $val = shift;
369 if ($type_constraint) {
370 $val = $type_constraint->coerce($val)
371 if $can_coerce;
372 $type_constraint->check($val)
373 || confess "Attribute ("
374 . $slot_name
375 . ") does not pass the type constraint because: "
376 . $type_constraint->get_message($val);
377 }
378 $meta_instance->set_slot_value($instance, $slot_name, $val);
379 };
380
381 my $initializer = $self->initializer;
382
383 # most things will just want to set a value, so make it first arg
384 $instance->$initializer($value, $callback, $self);
385}
386
946289d1 387sub set_value {
388 my ($self, $instance, $value) = @_;
26fbace8 389
946289d1 390 my $attr_name = $self->name;
26fbace8 391
946289d1 392 if ($self->is_required) {
26fbace8 393 defined($value)
946289d1 394 || confess "Attribute ($attr_name) is required, so cannot be set to undef";
395 }
26fbace8 396
946289d1 397 if ($self->has_type_constraint) {
26fbace8 398
946289d1 399 my $type_constraint = $self->type_constraint;
26fbace8 400
946289d1 401 if ($self->should_coerce) {
26fbace8 402 $value = $type_constraint->coerce($value);
688fcdda 403 }
42bc21a4 404 $type_constraint->_compiled_type_constraint->($value)
688fcdda 405 || confess "Attribute ("
406 . $self->name
407 . ") does not pass the type constraint because "
ab76842e 408 . $type_constraint->get_message($value);
946289d1 409 }
26fbace8 410
946289d1 411 my $meta_instance = Class::MOP::Class->initialize(blessed($instance))
412 ->get_meta_instance;
26fbace8 413
414 $meta_instance->set_slot_value($instance, $attr_name, $value);
415
946289d1 416 if (ref $value && $self->is_weak_ref) {
26fbace8 417 $meta_instance->weaken_slot_value($instance, $attr_name);
946289d1 418 }
26fbace8 419
946289d1 420 if ($self->has_trigger) {
421 $self->trigger->($instance, $value, $self);
422 }
423}
424
425sub get_value {
426 my ($self, $instance) = @_;
26fbace8 427
946289d1 428 if ($self->is_lazy) {
8de73ff1 429 unless ($self->has_value($instance)) {
430 if ($self->has_default) {
431 my $default = $self->default($instance);
759e4e8f 432 $self->set_initial_value($instance, $default);
8de73ff1 433 }
434 if ( $self->has_builder ){
a6c84c69 435 if (my $builder = $instance->can($self->builder)){
759e4e8f 436 $self->set_initial_value($instance, $instance->$builder);
a6c84c69 437 }
438 else {
439 confess(blessed($instance)
440 . " does not support builder method '"
441 . $self->builder
442 . "' for attribute '"
443 . $self->name
444 . "'");
26fbace8 445 }
a6c84c69 446 }
447 else {
759e4e8f 448 $self->set_initial_value($instance, undef);
26fbace8 449 }
8de73ff1 450 }
946289d1 451 }
26fbace8 452
946289d1 453 if ($self->should_auto_deref) {
26fbace8 454
946289d1 455 my $type_constraint = $self->type_constraint;
456
457 if ($type_constraint->is_a_type_of('ArrayRef')) {
458 my $rv = $self->SUPER::get_value($instance);
459 return unless defined $rv;
460 return wantarray ? @{ $rv } : $rv;
26fbace8 461 }
946289d1 462 elsif ($type_constraint->is_a_type_of('HashRef')) {
463 my $rv = $self->SUPER::get_value($instance);
464 return unless defined $rv;
465 return wantarray ? %{ $rv } : $rv;
26fbace8 466 }
946289d1 467 else {
468 confess "Can not auto de-reference the type constraint '" . $type_constraint->name . "'";
469 }
26fbace8 470
946289d1 471 }
472 else {
26fbace8 473
946289d1 474 return $self->SUPER::get_value($instance);
26fbace8 475 }
946289d1 476}
a15dff8d 477
26fbace8 478## installing accessors
c0e30cf5 479
d617b644 480sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
d7f17ebb 481
452bac1b 482sub install_accessors {
483 my $self = shift;
26fbace8 484 $self->SUPER::install_accessors(@_);
485
452bac1b 486 if ($self->has_handles) {
26fbace8 487
452bac1b 488 # NOTE:
489 # Here we canonicalize the 'handles' option
26fbace8 490 # this will sort out any details and always
491 # return an hash of methods which we want
452bac1b 492 # to delagate to, see that method for details
493 my %handles = $self->_canonicalize_handles();
26fbace8 494
f3c4e20e 495 # find the accessor method for this attribute
496 my $accessor = $self->get_read_method_ref;
497 # then unpack it if we need too ...
498 $accessor = $accessor->body if blessed $accessor;
26fbace8 499
452bac1b 500 # install the delegation ...
501 my $associated_class = $self->associated_class;
502 foreach my $handle (keys %handles) {
503 my $method_to_call = $handles{$handle};
7dbbdcab 504 my $class_name = $associated_class->name;
505 my $name = "${class_name}::${handle}";
26fbace8 506
452bac1b 507 (!$associated_class->has_method($handle))
508 || confess "You cannot overwrite a locally defined method ($handle) with a delegation";
26fbace8 509
d022f632 510 # NOTE:
511 # handles is not allowed to delegate
26fbace8 512 # any of these methods, as they will
513 # override the ones in your class, which
d022f632 514 # is almost certainly not what you want.
4fe78472 515
516 # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
517 #cluck("Not delegating method '$handle' because it is a core method") and
518 next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 519
452bac1b 520 if ((reftype($method_to_call) || '') eq 'CODE') {
7dbbdcab 521 $associated_class->add_method($handle => subname $name, $method_to_call);
452bac1b 522 }
523 else {
140001f0 524 # NOTE:
525 # we used to do a goto here, but the
526 # goto didn't handle failure correctly
527 # (it just returned nothing), so I took
528 # that out. However, the more I thought
529 # about it, the less I liked it doing
530 # the goto, and I prefered the act of
531 # delegation being actually represented
532 # in the stack trace.
533 # - SL
7dbbdcab 534 $associated_class->add_method($handle => subname $name, sub {
f3c4e20e 535 my $proxy = (shift)->$accessor();
ccf49e80 536 (defined $proxy)
537 || confess "Cannot delegate $handle to $method_to_call because " .
538 "the value of " . $self->name . " is not defined";
f4f3e701 539 $proxy->$method_to_call(@_);
452bac1b 540 });
541 }
542 }
543 }
26fbace8 544
452bac1b 545 return;
546}
547
98aae381 548# private methods to help delegation ...
549
452bac1b 550sub _canonicalize_handles {
551 my $self = shift;
552 my $handles = $self->handles;
c84f324f 553 if (my $handle_type = ref($handles)) {
554 if ($handle_type eq 'HASH') {
555 return %{$handles};
556 }
557 elsif ($handle_type eq 'ARRAY') {
558 return map { $_ => $_ } @{$handles};
559 }
560 elsif ($handle_type eq 'Regexp') {
561 ($self->has_type_constraint)
562 || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
26fbace8 563 return map { ($_ => $_) }
c84f324f 564 grep { /$handles/ } $self->_get_delegate_method_list;
565 }
566 elsif ($handle_type eq 'CODE') {
567 return $handles->($self, $self->_find_delegate_metaclass);
568 }
569 else {
570 confess "Unable to canonicalize the 'handles' option with $handles";
571 }
452bac1b 572 }
573 else {
c84f324f 574 my $role_meta = eval { $handles->meta };
575 if ($@) {
26fbace8 576 confess "Unable to canonicalize the 'handles' option with $handles because : $@";
c84f324f 577 }
578
579 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
580 || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
26fbace8 581
c84f324f 582 return map { $_ => $_ } (
26fbace8 583 $role_meta->get_method_list,
c84f324f 584 $role_meta->get_required_method_list
585 );
452bac1b 586 }
587}
588
589sub _find_delegate_metaclass {
590 my $self = shift;
98aae381 591 if (my $class = $self->_isa_metadata) {
26fbace8 592 # if the class does have
452bac1b 593 # a meta method, use it
594 return $class->meta if $class->can('meta');
26fbace8 595 # otherwise we might be
452bac1b 596 # dealing with a non-Moose
26fbace8 597 # class, and need to make
452bac1b 598 # our own metaclass
599 return Moose::Meta::Class->initialize($class);
600 }
98aae381 601 elsif (my $role = $self->_does_metadata) {
26fbace8 602 # our role will always have
452bac1b 603 # a meta method
98aae381 604 return $role->meta;
452bac1b 605 }
606 else {
607 confess "Cannot find delegate metaclass for attribute " . $self->name;
608 }
609}
610
611sub _get_delegate_method_list {
612 my $self = shift;
613 my $meta = $self->_find_delegate_metaclass;
614 if ($meta->isa('Class::MOP::Class')) {
093b12c2 615 return map { $_->{name} } # NOTE: !never! delegate &meta
26fbace8 616 grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' }
452bac1b 617 $meta->compute_all_applicable_methods;
618 }
619 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 620 return $meta->get_method_list;
452bac1b 621 }
622 else {
623 confess "Unable to recognize the delegate metaclass '$meta'";
624 }
625}
626
c0e30cf5 6271;
628
629__END__
630
631=pod
632
633=head1 NAME
634
6ba6d68c 635Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 636
637=head1 DESCRIPTION
638
26fbace8 639This is a subclass of L<Class::MOP::Attribute> with Moose specific
640extensions.
6ba6d68c 641
26fbace8 642For the most part, the only time you will ever encounter an
643instance of this class is if you are doing some serious deep
644introspection. To really understand this class, you need to refer
6ba6d68c 645to the L<Class::MOP::Attribute> documentation.
e522431d 646
c0e30cf5 647=head1 METHODS
648
6ba6d68c 649=head2 Overridden methods
650
26fbace8 651These methods override methods in L<Class::MOP::Attribute> and add
652Moose specific features. You can safely assume though that they
6ba6d68c 653will behave just as L<Class::MOP::Attribute> does.
654
c0e30cf5 655=over 4
656
657=item B<new>
658
c32c2c61 659=item B<clone>
660
6e2840b7 661=item B<does>
662
d500266f 663=item B<initialize_instance_slot>
664
452bac1b 665=item B<install_accessors>
666
39b3bc94 667=item B<accessor_metaclass>
668
946289d1 669=item B<get_value>
670
671=item B<set_value>
672
bcbaa845 673 eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
674 if($@) {
675 print "Oops: $@\n";
676 }
677
678I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
679
680Before setting the value, a check is made on the type constraint of
681the attribute, if it has one, to see if the value passes it. If the
682value fails to pass, the set operation dies with a L<Carp/confess>.
683
684Any coercion to convert values is done before checking the type constraint.
685
686To check a value against a type constraint before setting it, fetch the
ec00fa75 687attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 688fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
689and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
690for an example.
691
a15dff8d 692=back
693
6ba6d68c 694=head2 Additional Moose features
695
26fbace8 696Moose attributes support type-constraint checking, weak reference
697creation and type coercion.
6ba6d68c 698
a15dff8d 699=over 4
700
d5c30e52 701=item B<interpolate_class_and_new>
702
703=item B<interpolate_class>
704
705When called as a class method causes interpretation of the C<metaclass> and
706C<traits> options.
707
9e93dd19 708=item B<clone_and_inherit_options>
709
26fbace8 710This is to support the C<has '+foo'> feature, it clones an attribute
711from a superclass and allows a very specific set of changes to be made
9e93dd19 712to the attribute.
713
a15dff8d 714=item B<has_type_constraint>
715
6ba6d68c 716Returns true if this meta-attribute has a type constraint.
717
a15dff8d 718=item B<type_constraint>
719
26fbace8 720A read-only accessor for this meta-attribute's type constraint. For
721more information on what you can do with this, see the documentation
6ba6d68c 722for L<Moose::Meta::TypeConstraint>.
a15dff8d 723
452bac1b 724=item B<has_handles>
725
726Returns true if this meta-attribute performs delegation.
727
728=item B<handles>
729
730This returns the value which was passed into the handles option.
731
6ba6d68c 732=item B<is_weak_ref>
a15dff8d 733
02a0fb52 734Returns true if this meta-attribute produces a weak reference.
4b598ea3 735
ca01a97b 736=item B<is_required>
737
02a0fb52 738Returns true if this meta-attribute is required to have a value.
ca01a97b 739
740=item B<is_lazy>
741
02a0fb52 742Returns true if this meta-attribute should be initialized lazily.
ca01a97b 743
26fbace8 744NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
745
746=item B<is_lazy_build>
747
748Returns true if this meta-attribute should be initialized lazily through
749the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
750make your attribute required and lazy. In addition it will set the builder, clearer
751and predicate options for you using the following convention.
752
753 #If your attribute name starts with an underscore:
754 has '_foo' => (lazy_build => 1);
755 #is the same as
58f85113 756 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo);
26fbace8 757 # or
58f85113 758 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
26fbace8 759
760 #If your attribute name does not start with an underscore:
58f85113 761 has 'foo' => (lazy_build => 1);
762 #is the same as
763 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo);
26fbace8 764 # or
58f85113 765 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
766
767The reason for the different naming of the C<builder> is that the C<builder>
768method is a private method while the C<clearer> and C<predicate> methods
769are public methods.
26fbace8 770
771NOTE: This means your class should provide a method whose name matches the value
58f85113 772of the builder part, in this case _build__foo or _build_foo.
ca01a97b 773
34a66aa3 774=item B<should_coerce>
4b598ea3 775
02a0fb52 776Returns true if this meta-attribute should perform type coercion.
6ba6d68c 777
536f0b17 778=item B<should_auto_deref>
779
26fbace8 780Returns true if this meta-attribute should perform automatic
781auto-dereferencing.
536f0b17 782
26fbace8 783NOTE: This can only be done for attributes whose type constraint is
536f0b17 784either I<ArrayRef> or I<HashRef>.
785
8c9d74e7 786=item B<has_trigger>
787
02a0fb52 788Returns true if this meta-attribute has a trigger set.
789
8c9d74e7 790=item B<trigger>
791
26fbace8 792This is a CODE reference which will be executed every time the
793value of an attribute is assigned. The CODE ref will get two values,
794the invocant and the new value. This can be used to handle I<basic>
02a0fb52 795bi-directional relations.
796
ddbdc0cb 797=item B<documentation>
798
26fbace8 799This is a string which contains the documentation for this attribute.
ddbdc0cb 800It serves no direct purpose right now, but it might in the future
801in some kind of automated documentation system perhaps.
802
803=item B<has_documentation>
804
805Returns true if this meta-attribute has any documentation.
806
88f23977 807=item B<applied_traits>
808
809This will return the ARRAY ref of all the traits applied to this
810attribute, or if no traits have been applied, it returns C<undef>.
811
812=item B<has_applied_traits>
813
814Returns true if this meta-attribute has any traits applied.
815
c0e30cf5 816=back
817
818=head1 BUGS
819
26fbace8 820All complex software has bugs lurking in it, and this module is no
c0e30cf5 821exception. If you find a bug please either email me, or add the bug
822to cpan-RT.
823
c0e30cf5 824=head1 AUTHOR
825
826Stevan Little E<lt>stevan@iinteractive.comE<gt>
827
98aae381 828Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
829
c0e30cf5 830=head1 COPYRIGHT AND LICENSE
831
778db3ac 832Copyright 2006-2008 by Infinity Interactive, Inc.
c0e30cf5 833
834L<http://www.iinteractive.com>
835
836This library is free software; you can redistribute it and/or modify
26fbace8 837it under the same terms as Perl itself.
c0e30cf5 838
8a7a9c53 839=cut