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