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