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