update Changes
[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';
a909a4df 8use overload ();
a15dff8d 9
e6ab9ca5 10our $VERSION = '0.83';
d44714be 11our $AUTHORITY = 'cpan:STEVAN';
78cd1d3b 12
8ee73eeb 13use Moose::Meta::Method::Accessor;
a05f85c1 14use Moose::Meta::Method::Delegation;
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
d03bd989 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
e8895723 64 return $self->Moose::Object::does($name);
0db4f1d7 65}
587e457d 66
be05faea 67sub throw_error {
68 my $self = shift;
69 my $class = ( ref $self && $self->associated_class ) || "Moose::Meta::Class";
70 unshift @_, "message" if @_ % 2 == 1;
71 unshift @_, attr => $self if ref $self;
72 unshift @_, $class;
18748ad6 73 my $handler = $class->can("throw_error"); # to avoid incrementing depth by 1
74 goto $handler;
be05faea 75}
76
78cd1d3b 77sub new {
f3c4e20e 78 my ($class, $name, %options) = @_;
c32c2c61 79 $class->_process_options($name, \%options) unless $options{__hack_no_process_options}; # used from clone()... YECHKKK FIXME ICKY YUCK GROSS
f3c4e20e 80 return $class->SUPER::new($name, %options);
1d768fb1 81}
82
d5c30e52 83sub interpolate_class_and_new {
84 my ($class, $name, @args) = @_;
85
c32c2c61 86 my ( $new_class, @traits ) = $class->interpolate_class(@args);
d03bd989 87
c32c2c61 88 $new_class->new($name, @args, ( scalar(@traits) ? ( traits => \@traits ) : () ) );
d5c30e52 89}
90
91sub interpolate_class {
92 my ($class, %options) = @_;
93
c32c2c61 94 $class = ref($class) || $class;
95
96 if ( my $metaclass_name = delete $options{metaclass} ) {
97 my $new_class = Moose::Util::resolve_metaclass_alias( Attribute => $metaclass_name );
d03bd989 98
c32c2c61 99 if ( $class ne $new_class ) {
100 if ( $new_class->can("interpolate_class") ) {
101 return $new_class->interpolate_class(%options);
102 } else {
103 $class = $new_class;
104 }
105 }
d5c30e52 106 }
107
c32c2c61 108 my @traits;
109
d5c30e52 110 if (my $traits = $options{traits}) {
8974015d 111 my $i = 0;
112 while ($i < @$traits) {
113 my $trait = $traits->[$i++];
114 next if ref($trait); # options to a trait we discarded
115
116 $trait = Moose::Util::resolve_metatrait_alias(Attribute => $trait)
117 || $trait;
118
119 next if $class->does($trait);
120
121 push @traits, $trait;
122
123 # are there options?
124 push @traits, $traits->[$i++]
125 if $traits->[$i] && ref($traits->[$i]);
126 }
965743fb 127
128 if (@traits) {
c32c2c61 129 my $anon_class = Moose::Meta::Class->create_anon_class(
130 superclasses => [ $class ],
131 roles => [ @traits ],
132 cache => 1,
133 );
134
135 $class = $anon_class->name;
136 }
d5c30e52 137 }
c32c2c61 138
139 return ( wantarray ? ( $class, @traits ) : $class );
d5c30e52 140}
141
e606ae5f 142# ...
143
144my @legal_options_for_inheritance = qw(
d03bd989 145 default coerce required
146 documentation lazy handles
e606ae5f 147 builder type_constraint
5f06098e 148 definition_context
449559bf 149 lazy_build
e606ae5f 150);
151
152sub legal_options_for_inheritance { @legal_options_for_inheritance }
153
154# NOTE/TODO
d03bd989 155# This method *must* be able to handle
156# Class::MOP::Attribute instances as
157# well. Yes, I know that is wrong, but
158# apparently we didn't realize it was
159# doing that and now we have some code
160# which is dependent on it. The real
161# solution of course is to push this
e606ae5f 162# feature back up into Class::MOP::Attribute
163# but I not right now, I am too lazy.
d03bd989 164# However if you are reading this and
165# looking for something to do,.. please
e606ae5f 166# be my guest.
167# - stevan
ce0e8d63 168sub clone_and_inherit_options {
169 my ($self, %options) = @_;
d03bd989 170
c32c2c61 171 my %copy = %options;
d03bd989 172
ce0e8d63 173 my %actual_options;
d03bd989 174
e606ae5f 175 # NOTE:
176 # we may want to extends a Class::MOP::Attribute
d03bd989 177 # in which case we need to be able to use the
178 # core set of legal options that have always
e606ae5f 179 # been here. But we allows Moose::Meta::Attribute
180 # instances to changes them.
181 # - SL
182 my @legal_options = $self->can('legal_options_for_inheritance')
183 ? $self->legal_options_for_inheritance
184 : @legal_options_for_inheritance;
d03bd989 185
e606ae5f 186 foreach my $legal_option (@legal_options) {
ce0e8d63 187 if (exists $options{$legal_option}) {
188 $actual_options{$legal_option} = $options{$legal_option};
189 delete $options{$legal_option};
190 }
d03bd989 191 }
26fbace8 192
ce0e8d63 193 if ($options{isa}) {
194 my $type_constraint;
8de73ff1 195 if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
196 $type_constraint = $options{isa};
197 }
198 else {
d40ce9d5 199 $type_constraint = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options{isa});
8de73ff1 200 (defined $type_constraint)
be05faea 201 || $self->throw_error("Could not find the type constraint '" . $options{isa} . "'", data => $options{isa});
8de73ff1 202 }
5e98d2b6 203
8de73ff1 204 $actual_options{type_constraint} = $type_constraint;
ce0e8d63 205 delete $options{isa};
206 }
d03bd989 207
2ea379cb 208 if ($options{does}) {
209 my $type_constraint;
210 if (blessed($options{does}) && $options{does}->isa('Moose::Meta::TypeConstraint')) {
211 $type_constraint = $options{does};
212 }
213 else {
d40ce9d5 214 $type_constraint = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options{does});
2ea379cb 215 (defined $type_constraint)
be05faea 216 || $self->throw_error("Could not find the type constraint '" . $options{does} . "'", data => $options{does});
2ea379cb 217 }
218
219 $actual_options{type_constraint} = $type_constraint;
220 delete $options{does};
d03bd989 221 }
c32c2c61 222
cbd141ca 223 # NOTE:
d03bd989 224 # this doesn't apply to Class::MOP::Attributes,
cbd141ca 225 # so we can ignore it for them.
226 # - SL
227 if ($self->can('interpolate_class')) {
228 ( $actual_options{metaclass}, my @traits ) = $self->interpolate_class(%options);
c32c2c61 229
cbd141ca 230 my %seen;
231 my @all_traits = grep { $seen{$_}++ } @{ $self->applied_traits || [] }, @traits;
232 $actual_options{traits} = \@all_traits if @all_traits;
c32c2c61 233
cbd141ca 234 delete @options{qw(metaclass traits)};
235 }
c32c2c61 236
26fbace8 237 (scalar keys %options == 0)
be05faea 238 || $self->throw_error("Illegal inherited options => (" . (join ', ' => keys %options) . ")", data => \%options);
c32c2c61 239
240
ce0e8d63 241 $self->clone(%actual_options);
1d768fb1 242}
243
c32c2c61 244sub clone {
245 my ( $self, %params ) = @_;
246
247 my $class = $params{metaclass} || ref $self;
248
db72153d 249 my ( @init, @non_init );
c32c2c61 250
0772362a 251 foreach my $attr ( grep { $_->has_value($self) } Class::MOP::class_of($self)->get_all_attributes ) {
db72153d 252 push @{ $attr->has_init_arg ? \@init : \@non_init }, $attr;
253 }
c32c2c61 254
db72153d 255 my %new_params = ( ( map { $_->init_arg => $_->get_value($self) } @init ), %params );
c32c2c61 256
db72153d 257 my $name = delete $new_params{name};
c32c2c61 258
db72153d 259 my $clone = $class->new($name, %new_params, __hack_no_process_options => 1 );
c32c2c61 260
db72153d 261 foreach my $attr ( @non_init ) {
262 $attr->set_value($clone, $attr->get_value($self));
c32c2c61 263 }
db72153d 264
265 return $clone;
c32c2c61 266}
267
1d768fb1 268sub _process_options {
269 my ($class, $name, $options) = @_;
8de73ff1 270
f3c4e20e 271 if (exists $options->{is}) {
21f1e231 272
012fcbd1 273 ### -------------------------
274 ## is => ro, writer => _foo # turns into (reader => foo, writer => _foo) as before
275 ## is => rw, writer => _foo # turns into (reader => foo, writer => _foo)
276 ## is => rw, accessor => _foo # turns into (accessor => _foo)
277 ## is => ro, accessor => _foo # error, accesor is rw
278 ### -------------------------
d03bd989 279
8de73ff1 280 if ($options->{is} eq 'ro') {
be05faea 281 $class->throw_error("Cannot define an accessor name on a read-only attribute, accessors are read/write", data => $options)
21f1e231 282 if exists $options->{accessor};
8de73ff1 283 $options->{reader} ||= $name;
8de73ff1 284 }
285 elsif ($options->{is} eq 'rw') {
21f1e231 286 if ($options->{writer}) {
287 $options->{reader} ||= $name;
288 }
289 else {
290 $options->{accessor} ||= $name;
291 }
8de73ff1 292 }
ccd4cff9 293 elsif ($options->{is} eq 'bare') {
294 # do nothing, but don't complain (later) about missing methods
295 }
8de73ff1 296 else {
e606ae5f 297 $class->throw_error("I do not understand this option (is => " . $options->{is} . ") on attribute ($name)", data => $options->{is});
8de73ff1 298 }
f3c4e20e 299 }
8de73ff1 300
f3c4e20e 301 if (exists $options->{isa}) {
f3c4e20e 302 if (exists $options->{does}) {
303 if (eval { $options->{isa}->can('does') }) {
304 ($options->{isa}->does($options->{does}))
e606ae5f 305 || $class->throw_error("Cannot have an isa option and a does option if the isa does not do the does on attribute ($name)", data => $options);
f3c4e20e 306 }
307 else {
e606ae5f 308 $class->throw_error("Cannot have an isa option which cannot ->does() on attribute ($name)", data => $options);
26fbace8 309 }
26fbace8 310 }
8de73ff1 311
f3c4e20e 312 # allow for anon-subtypes here ...
313 if (blessed($options->{isa}) && $options->{isa}->isa('Moose::Meta::TypeConstraint')) {
8de73ff1 314 $options->{type_constraint} = $options->{isa};
315 }
316 else {
620db045 317 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options->{isa});
8de73ff1 318 }
f3c4e20e 319 }
320 elsif (exists $options->{does}) {
321 # allow for anon-subtypes here ...
322 if (blessed($options->{does}) && $options->{does}->isa('Moose::Meta::TypeConstraint')) {
238b424d 323 $options->{type_constraint} = $options->{does};
8de73ff1 324 }
325 else {
620db045 326 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options->{does});
8de73ff1 327 }
f3c4e20e 328 }
8de73ff1 329
f3c4e20e 330 if (exists $options->{coerce} && $options->{coerce}) {
331 (exists $options->{type_constraint})
e606ae5f 332 || $class->throw_error("You cannot have coercion without specifying a type constraint on attribute ($name)", data => $options);
333 $class->throw_error("You cannot have a weak reference to a coerced value on attribute ($name)", data => $options)
8de73ff1 334 if $options->{weak_ref};
f3c4e20e 335 }
8de73ff1 336
0b7df53c 337 if (exists $options->{trigger}) {
21f1e231 338 ('CODE' eq ref $options->{trigger})
e606ae5f 339 || $class->throw_error("Trigger must be a CODE ref on attribute ($name)", data => $options->{trigger});
0b7df53c 340 }
341
f3c4e20e 342 if (exists $options->{auto_deref} && $options->{auto_deref}) {
343 (exists $options->{type_constraint})
e606ae5f 344 || $class->throw_error("You cannot auto-dereference without specifying a type constraint on attribute ($name)", data => $options);
f3c4e20e 345 ($options->{type_constraint}->is_a_type_of('ArrayRef') ||
8de73ff1 346 $options->{type_constraint}->is_a_type_of('HashRef'))
e606ae5f 347 || $class->throw_error("You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute ($name)", data => $options);
f3c4e20e 348 }
8de73ff1 349
f3c4e20e 350 if (exists $options->{lazy_build} && $options->{lazy_build} == 1) {
e606ae5f 351 $class->throw_error("You can not use lazy_build and default for the same attribute ($name)", data => $options)
8de73ff1 352 if exists $options->{default};
a6c84c69 353 $options->{lazy} = 1;
a6c84c69 354 $options->{builder} ||= "_build_${name}";
355 if ($name =~ /^_/) {
f3c4e20e 356 $options->{clearer} ||= "_clear${name}";
357 $options->{predicate} ||= "_has${name}";
d03bd989 358 }
a6c84c69 359 else {
f3c4e20e 360 $options->{clearer} ||= "clear_${name}";
361 $options->{predicate} ||= "has_${name}";
26fbace8 362 }
f3c4e20e 363 }
8de73ff1 364
f3c4e20e 365 if (exists $options->{lazy} && $options->{lazy}) {
9edba990 366 (exists $options->{default} || defined $options->{builder} )
be05faea 367 || $class->throw_error("You cannot have lazy attribute ($name) without specifying a default value for it", data => $options);
f3c4e20e 368 }
26fbace8 369
9edba990 370 if ( $options->{required} && !( ( !exists $options->{init_arg} || defined $options->{init_arg} ) || exists $options->{default} || defined $options->{builder} ) ) {
be05faea 371 $class->throw_error("You cannot have a required attribute ($name) without a default, builder, or an init_arg", data => $options);
9edba990 372 }
373
78cd1d3b 374}
c0e30cf5 375
d500266f 376sub initialize_instance_slot {
ddd0ec20 377 my ($self, $meta_instance, $instance, $params) = @_;
d500266f 378 my $init_arg = $self->init_arg();
379 # try to fetch the init arg from the %params ...
ddd0ec20 380
26fbace8 381 my $val;
1ed0b94f 382 my $value_is_set;
625d571f 383 if ( defined($init_arg) and exists $params->{$init_arg}) {
d500266f 384 $val = $params->{$init_arg};
d03bd989 385 $value_is_set = 1;
d500266f 386 }
387 else {
388 # skip it if it's lazy
389 return if $self->is_lazy;
390 # and die if it's required and doesn't have a default value
be05faea 391 $self->throw_error("Attribute (" . $self->name . ") is required", object => $instance, data => $params)
26fbace8 392 if $self->is_required && !$self->has_default && !$self->has_builder;
ddd0ec20 393
1ed0b94f 394 # if nothing was in the %params, we can use the
395 # attribute's default value (if it has one)
396 if ($self->has_default) {
397 $val = $self->default($instance);
398 $value_is_set = 1;
d03bd989 399 }
a6c84c69 400 elsif ($self->has_builder) {
e606ae5f 401 $val = $self->_call_builder($instance);
402 $value_is_set = 1;
a0748c37 403 }
26fbace8 404 }
405
1ed0b94f 406 return unless $value_is_set;
407
9c9563c7 408 $val = $self->_coerce_and_verify( $val, $instance );
ddd0ec20 409
759e4e8f 410 $self->set_initial_value($instance, $val);
26fbace8 411 $meta_instance->weaken_slot_value($instance, $self->name)
a6c84c69 412 if ref $val && $self->is_weak_ref;
d500266f 413}
414
e606ae5f 415sub _call_builder {
416 my ( $self, $instance ) = @_;
417
418 my $builder = $self->builder();
419
420 return $instance->$builder()
421 if $instance->can( $self->builder );
422
423 $self->throw_error( blessed($instance)
424 . " does not support builder method '"
425 . $self->builder
426 . "' for attribute '"
427 . $self->name
428 . "'",
429 object => $instance,
430 );
431}
432
d617b644 433## Slot management
9e93dd19 434
8abe9636 435# FIXME:
d03bd989 436# this duplicates too much code from
437# Class::MOP::Attribute, we need to
8abe9636 438# refactor these bits eventually.
439# - SL
440sub _set_initial_slot_value {
441 my ($self, $meta_instance, $instance, $value) = @_;
442
443 my $slot_name = $self->name;
444
445 return $meta_instance->set_slot_value($instance, $slot_name, $value)
446 unless $self->has_initializer;
447
448 my ($type_constraint, $can_coerce);
449 if ($self->has_type_constraint) {
450 $type_constraint = $self->type_constraint;
451 $can_coerce = ($self->should_coerce && $type_constraint->has_coercion);
452 }
453
454 my $callback = sub {
9c9563c7 455 my $val = $self->_coerce_and_verify( shift, $instance );;
456
8abe9636 457 $meta_instance->set_slot_value($instance, $slot_name, $val);
458 };
d03bd989 459
8abe9636 460 my $initializer = $self->initializer;
461
462 # most things will just want to set a value, so make it first arg
463 $instance->$initializer($value, $callback, $self);
464}
465
946289d1 466sub set_value {
b6af66f8 467 my ($self, $instance, @args) = @_;
468 my $value = $args[0];
26fbace8 469
946289d1 470 my $attr_name = $self->name;
26fbace8 471
b6af66f8 472 if ($self->is_required and not @args) {
be05faea 473 $self->throw_error("Attribute ($attr_name) is required", object => $instance);
946289d1 474 }
26fbace8 475
9c9563c7 476 $value = $self->_coerce_and_verify( $value, $instance );
26fbace8 477
946289d1 478 my $meta_instance = Class::MOP::Class->initialize(blessed($instance))
479 ->get_meta_instance;
26fbace8 480
481 $meta_instance->set_slot_value($instance, $attr_name, $value);
482
946289d1 483 if (ref $value && $self->is_weak_ref) {
26fbace8 484 $meta_instance->weaken_slot_value($instance, $attr_name);
946289d1 485 }
26fbace8 486
946289d1 487 if ($self->has_trigger) {
525129a5 488 $self->trigger->($instance, $value);
946289d1 489 }
490}
491
492sub get_value {
493 my ($self, $instance) = @_;
26fbace8 494
946289d1 495 if ($self->is_lazy) {
8de73ff1 496 unless ($self->has_value($instance)) {
e606ae5f 497 my $value;
8de73ff1 498 if ($self->has_default) {
e606ae5f 499 $value = $self->default($instance);
3f11800d 500 } elsif ( $self->has_builder ) {
e606ae5f 501 $value = $self->_call_builder($instance);
502 }
9c9563c7 503
504 $value = $self->_coerce_and_verify( $value, $instance );
505
e606ae5f 506 $self->set_initial_value($instance, $value);
8de73ff1 507 }
946289d1 508 }
26fbace8 509
946289d1 510 if ($self->should_auto_deref) {
26fbace8 511
946289d1 512 my $type_constraint = $self->type_constraint;
513
514 if ($type_constraint->is_a_type_of('ArrayRef')) {
515 my $rv = $self->SUPER::get_value($instance);
516 return unless defined $rv;
517 return wantarray ? @{ $rv } : $rv;
26fbace8 518 }
946289d1 519 elsif ($type_constraint->is_a_type_of('HashRef')) {
520 my $rv = $self->SUPER::get_value($instance);
521 return unless defined $rv;
522 return wantarray ? %{ $rv } : $rv;
26fbace8 523 }
946289d1 524 else {
46cb090f 525 $self->throw_error("Can not auto de-reference the type constraint '" . $type_constraint->name . "'", object => $instance, type_constraint => $type_constraint);
946289d1 526 }
26fbace8 527
946289d1 528 }
529 else {
26fbace8 530
946289d1 531 return $self->SUPER::get_value($instance);
26fbace8 532 }
946289d1 533}
a15dff8d 534
26fbace8 535## installing accessors
c0e30cf5 536
246bbeef 537sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
538
539sub install_accessors {
ae907ae0 540 my $self = shift;
246bbeef 541 $self->SUPER::install_accessors(@_);
542 $self->install_delegation if $self->has_handles;
86cf196b 543 unless (
0bbd378f 544 @{ $self->associated_methods }
86cf196b 545 || ($self->_is_metadata || '') eq 'bare'
546 ) {
547 Carp::cluck(
548 'Attribute (' . $self->name . ') has no associated methods'
549 . ' (did you mean to provide an "is" argument?)'
550 . "\n"
551 )
552 }
e606ae5f 553 return;
554}
26fbace8 555
3b6e2290 556sub _process_accessors {
557 my $self = shift;
558 my ($type, $accessor, $generate_as_inline_methods) = @_;
559 $accessor = (keys %$accessor)[0] if (ref($accessor)||'') eq 'HASH';
560 if ($self->associated_class->has_method($accessor)
561 && !$self->associated_class->get_method($accessor)->isa('Class::MOP::Method::Accessor')) {
562 Carp::cluck(
563 "You cannot overwrite a locally defined method ($accessor) with "
564 . "an accessor"
565 );
566 }
567 $self->SUPER::_process_accessors(@_);
568}
569
e1d6f0a3 570sub remove_accessors {
571 my $self = shift;
572 $self->SUPER::remove_accessors(@_);
573 $self->remove_delegation if $self->has_handles;
574 return;
575}
576
e606ae5f 577sub install_delegation {
578 my $self = shift;
26fbace8 579
e606ae5f 580 # NOTE:
581 # Here we canonicalize the 'handles' option
582 # this will sort out any details and always
583 # return an hash of methods which we want
584 # to delagate to, see that method for details
585 my %handles = $self->_canonicalize_handles;
586
e606ae5f 587
588 # install the delegation ...
589 my $associated_class = $self->associated_class;
590 foreach my $handle (keys %handles) {
591 my $method_to_call = $handles{$handle};
592 my $class_name = $associated_class->name;
593 my $name = "${class_name}::${handle}";
26fbace8 594
452bac1b 595 (!$associated_class->has_method($handle))
cee532a1 596 || $self->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation", method_name => $handle);
26fbace8 597
e606ae5f 598 # NOTE:
599 # handles is not allowed to delegate
600 # any of these methods, as they will
601 # override the ones in your class, which
602 # is almost certainly not what you want.
4fe78472 603
e606ae5f 604 # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
605 #cluck("Not delegating method '$handle' because it is a core method") and
606 next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 607
46f7e6a5 608 my $method = $self->_make_delegation_method($handle, $method_to_call);
a05f85c1 609
610 $self->associated_class->add_method($method->name, $method);
0bbd378f 611 $self->associate_method($method);
d03bd989 612 }
452bac1b 613}
614
e1d6f0a3 615sub remove_delegation {
616 my $self = shift;
617 my %handles = $self->_canonicalize_handles;
618 my $associated_class = $self->associated_class;
619 foreach my $handle (keys %handles) {
620 $self->associated_class->remove_method($handle);
621 }
622}
623
98aae381 624# private methods to help delegation ...
625
452bac1b 626sub _canonicalize_handles {
627 my $self = shift;
628 my $handles = $self->handles;
c84f324f 629 if (my $handle_type = ref($handles)) {
630 if ($handle_type eq 'HASH') {
631 return %{$handles};
632 }
633 elsif ($handle_type eq 'ARRAY') {
634 return map { $_ => $_ } @{$handles};
635 }
636 elsif ($handle_type eq 'Regexp') {
637 ($self->has_type_constraint)
0286711b 638 || $self->throw_error("Cannot delegate methods based on a Regexp without a type constraint (isa)", data => $handles);
26fbace8 639 return map { ($_ => $_) }
c84f324f 640 grep { /$handles/ } $self->_get_delegate_method_list;
641 }
642 elsif ($handle_type eq 'CODE') {
643 return $handles->($self, $self->_find_delegate_metaclass);
644 }
6cbf4a23 645 elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::DuckType')) {
646 return map { $_ => $_ } @{ $handles->methods };
647 }
c84f324f 648 else {
be05faea 649 $self->throw_error("Unable to canonicalize the 'handles' option with $handles", data => $handles);
c84f324f 650 }
452bac1b 651 }
652 else {
c8d9f1e2 653 Class::MOP::load_class($handles);
654 my $role_meta = Class::MOP::class_of($handles);
c84f324f 655
656 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
425ca605 657 || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because its metaclass is not a Moose::Meta::Role", data => $handles);
d03bd989 658
c84f324f 659 return map { $_ => $_ } (
26fbace8 660 $role_meta->get_method_list,
b07a4e6d 661 map { $_->name } $role_meta->get_required_method_list,
c84f324f 662 );
452bac1b 663 }
664}
665
666sub _find_delegate_metaclass {
667 my $self = shift;
98aae381 668 if (my $class = $self->_isa_metadata) {
9031e2c4 669 # we might be dealing with a non-Moose class,
670 # and need to make our own metaclass. if there's
671 # already a metaclass, it will be returned
452bac1b 672 return Moose::Meta::Class->initialize($class);
673 }
98aae381 674 elsif (my $role = $self->_does_metadata) {
91e6653b 675 return Class::MOP::class_of($role);
452bac1b 676 }
677 else {
be05faea 678 $self->throw_error("Cannot find delegate metaclass for attribute " . $self->name);
452bac1b 679 }
680}
681
682sub _get_delegate_method_list {
683 my $self = shift;
684 my $meta = $self->_find_delegate_metaclass;
685 if ($meta->isa('Class::MOP::Class')) {
e606ae5f 686 return map { $_->name } # NOTE: !never! delegate &meta
687 grep { $_->package_name ne 'Moose::Object' && $_->name ne 'meta' }
688 $meta->get_all_methods;
452bac1b 689 }
690 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 691 return $meta->get_method_list;
452bac1b 692 }
693 else {
be05faea 694 $self->throw_error("Unable to recognize the delegate metaclass '$meta'", data => $meta);
452bac1b 695 }
696}
697
bd1226e2 698sub delegation_metaclass { 'Moose::Meta::Method::Delegation' }
699
a05f85c1 700sub _make_delegation_method {
46f7e6a5 701 my ( $self, $handle_name, $method_to_call ) = @_;
a05f85c1 702
703 my $method_body;
704
46f7e6a5 705 $method_body = $method_to_call
706 if 'CODE' eq ref($method_to_call);
a05f85c1 707
bd1226e2 708 return $self->delegation_metaclass->new(
46f7e6a5 709 name => $handle_name,
710 package_name => $self->associated_class->name,
711 attribute => $self,
712 delegate_to_method => $method_to_call,
a05f85c1 713 );
714}
715
9c9563c7 716sub _coerce_and_verify {
717 my $self = shift;
718 my $val = shift;
719 my $instance = shift;
720
721 return $val unless $self->has_type_constraint;
722
723 my $type_constraint = $self->type_constraint;
724 if ($self->should_coerce && $type_constraint->has_coercion) {
725 $val = $type_constraint->coerce($val);
726 }
727
728 $self->verify_against_type_constraint($val, instance => $instance);
729
730 return $val;
731}
732
5755a9b2 733sub verify_against_type_constraint {
2b86e02b 734 my $self = shift;
735 my $val = shift;
736
737 return 1 if !$self->has_type_constraint;
738
739 my $type_constraint = $self->type_constraint;
740
741 $type_constraint->check($val)
742 || $self->throw_error("Attribute ("
743 . $self->name
744 . ") does not pass the type constraint because: "
745 . $type_constraint->get_message($val), data => $val, @_);
746}
747
21f1e231 748package Moose::Meta::Attribute::Custom::Moose;
749sub register_implementation { 'Moose::Meta::Attribute' }
750
c0e30cf5 7511;
752
753__END__
754
755=pod
756
757=head1 NAME
758
6ba6d68c 759Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 760
761=head1 DESCRIPTION
762
93a708fd 763This class is a subclass of L<Class::MOP::Attribute> that provides
764additional Moose-specific functionality.
6ba6d68c 765
7854b409 766To really understand this class, you will need to start with the
767L<Class::MOP::Attribute> documentation. This class can be understood
768as a set of additional features on top of the basic feature provided
769by that parent class.
e522431d 770
d4b1449e 771=head1 INHERITANCE
772
773C<Moose::Meta::Attribute> is a subclass of L<Class::MOP::Attribute>.
774
c0e30cf5 775=head1 METHODS
776
93a708fd 777Many of the documented below override methods in
778L<Class::MOP::Attribute> and add Moose specific features.
6ba6d68c 779
93a708fd 780=head2 Creation
6ba6d68c 781
c0e30cf5 782=over 4
783
93a708fd 784=item B<< Moose::Meta::Attribute->new(%options) >>
c0e30cf5 785
93a708fd 786This method overrides the L<Class::MOP::Attribute> constructor.
c32c2c61 787
93a708fd 788Many of the options below are described in more detail in the
789L<Moose::Manual::Attributes> document.
6e2840b7 790
93a708fd 791It adds the following options to the constructor:
d500266f 792
93a708fd 793=over 8
452bac1b 794
996b8c8d 795=item * is => 'ro', 'rw', 'bare'
e1d6f0a3 796
93a708fd 797This provides a shorthand for specifying the C<reader>, C<writer>, or
798C<accessor> names. If the attribute is read-only ('ro') then it will
799have a C<reader> method with the same attribute as the name.
e606ae5f 800
93a708fd 801If it is read-write ('rw') then it will have an C<accessor> method
802with the same name. If you provide an explicit C<writer> for a
803read-write attribute, then you will have a C<reader> with the same
804name as the attribute, and a C<writer> with the name you provided.
e1d6f0a3 805
996b8c8d 806Use 'bare' when you are deliberately not installing any methods
807(accessor, reader, etc.) associated with this attribute; otherwise,
808Moose will issue a deprecation warning when this attribute is added to a
809metaclass.
810
93a708fd 811=item * isa => $type
39b3bc94 812
93a708fd 813This option accepts a type. The type can be a string, which should be
814a type name. If the type name is unknown, it is assumed to be a class
815name.
816
817This option can also accept a L<Moose::Meta::TypeConstraint> object.
818
819If you I<also> provide a C<does> option, then your C<isa> option must
820be a class name, and that class must do the role specified with
821C<does>.
822
823=item * does => $role
824
825This is short-hand for saying that the attribute's type must be an
826object which does the named role.
827
828=item * coerce => $bool
829
830This option is only valid for objects with a type constraint
831(C<isa>). If this is true, then coercions will be applied whenever
832this attribute is set.
833
834You can make both this and the C<weak_ref> option true.
835
836=item * trigger => $sub
837
838This option accepts a subroutine reference, which will be called after
839the attribute is set.
840
841=item * required => $bool
842
843An attribute which is required must be provided to the constructor. An
844attribute which is required can also have a C<default> or C<builder>,
36741534 845which will satisfy its required-ness.
93a708fd 846
847A required attribute must have a C<default>, C<builder> or a
848non-C<undef> C<init_arg>
849
850=item * lazy => $bool
851
852A lazy attribute must have a C<default> or C<builder>. When an
853attribute is lazy, the default value will not be calculated until the
854attribute is read.
855
856=item * weak_ref => $bool
857
858If this is true, the attribute's value will be stored as a weak
859reference.
860
861=item * auto_deref => $bool
862
863If this is true, then the reader will dereference the value when it is
864called. The attribute must have a type constraint which defines the
865attribute as an array or hash reference.
866
867=item * lazy_build => $bool
868
869Setting this to true makes the attribute lazy and provides a number of
870default methods.
871
872 has 'size' => (
873 is => 'ro',
874 lazy_build => 1,
875 );
876
877is equivalent to this:
878
879 has 'size' => (
880 is => 'ro',
881 lazy => 1,
882 builder => '_build_size',
883 clearer => 'clear_size',
884 predicate => 'has_size',
885 );
886
887=item * documentation
888
889An arbitrary string that can be retrieved later by calling C<<
890$attr->documentation >>.
891
892=back
893
894=item B<< $attr->clone(%options) >>
895
896This creates a new attribute based on attribute being cloned. You must
897supply a C<name> option to provide a new name for the attribute.
898
899The C<%options> can only specify options handled by
900L<Class::MOP::Attribute>.
901
36741534 902=back
903
93a708fd 904=head2 Value management
905
36741534 906=over 4
907
93a708fd 908=item B<< $attr->initialize_instance_slot($meta_instance, $instance, $params) >>
909
910This method is used internally to initialize the attribute's slot in
911the object C<$instance>.
912
913This overrides the L<Class::MOP::Attribute> method to handle lazy
914attributes, weak references, and type constraints.
bd1226e2 915
946289d1 916=item B<get_value>
917
918=item B<set_value>
919
6549b0d1 920 eval { $point->meta->get_attribute('x')->set_value($point, 'forty-two') };
bcbaa845 921 if($@) {
922 print "Oops: $@\n";
923 }
924
6549b0d1 925I<Attribute (x) does not pass the type constraint (Int) with 'forty-two'>
bcbaa845 926
927Before setting the value, a check is made on the type constraint of
928the attribute, if it has one, to see if the value passes it. If the
46cb090f 929value fails to pass, the set operation dies with a L<throw_error>.
bcbaa845 930
931Any coercion to convert values is done before checking the type constraint.
932
933To check a value against a type constraint before setting it, fetch the
ec00fa75 934attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 935fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
e606ae5f 936and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Recipe4>
bcbaa845 937for an example.
938
a15dff8d 939=back
940
93a708fd 941=head2 Attribute Accessor generation
6ba6d68c 942
a15dff8d 943=over 4
944
93a708fd 945=item B<< $attr->install_accessors >>
be05faea 946
93a708fd 947This method overrides the parent to also install delegation methods.
be05faea 948
7a582117 949If, after installing all methods, the attribute object has no associated
950methods, it throws an error unless C<< is => 'bare' >> was passed to the
951attribute constructor. (Trying to add an attribute that has no associated
952methods is almost always an error.)
953
36741534 954=item B<< $attr->remove_accessors >>
d5c30e52 955
93a708fd 956This method overrides the parent to also remove delegation methods.
d5c30e52 957
93a708fd 958=item B<< $attr->install_delegation >>
959
960This method adds its delegation methods to the attribute's associated
961class, if it has any to add.
962
963=item B<< $attr->remove_delegation >>
964
965This method remove its delegation methods from the attribute's
966associated class.
d5c30e52 967
93a708fd 968=item B<< $attr->accessor_metaclass >>
9e93dd19 969
93a708fd 970Returns the accessor metaclass name, which defaults to
971L<Moose::Meta::Method::Accessor>.
972
973=item B<< $attr->delegation_metaclass >>
974
975Returns the delegation metaclass name, which defaults to
976L<Moose::Meta::Method::Delegation>.
977
978=back
979
980=head2 Additional Moose features
981
982These methods are not found in the superclass. They support features
983provided by Moose.
984
36741534 985=over 4
986
93a708fd 987=item B<< $attr->does($role) >>
988
989This indicates whether the I<attribute itself> does the given
36741534 990role. The role can be given as a full class name, or as a resolvable
93a708fd 991trait name.
992
993Note that this checks the attribute itself, not its type constraint,
994so it is checking the attribute's metaclass and any traits applied to
995the attribute.
996
997=item B<< Moose::Meta::Class->interpolate_class_and_new($name, %options) >>
998
999This is an alternate constructor that handles the C<metaclass> and
1000C<traits> options.
9e93dd19 1001
93a708fd 1002Effectively, this method is a factory that finds or creates the
36741534 1003appropriate class for the given C<metaclass> and/or C<traits>.
e606ae5f 1004
93a708fd 1005Once it has the appropriate class, it will call C<< $class->new($name,
1006%options) >> on that class.
e606ae5f 1007
93a708fd 1008=item B<< $attr->clone_and_inherit_options(%options) >>
a15dff8d 1009
93a708fd 1010This method supports the C<has '+foo'> feature. It does various bits
1011of processing on the supplied C<%options> before ultimately calling
1012the C<clone> method.
6ba6d68c 1013
93a708fd 1014One of its main tasks is to make sure that the C<%options> provided
1015only includes the options returned by the
1016C<legal_options_for_inheritance> method.
a15dff8d 1017
93a708fd 1018=item B<< $attr->legal_options_for_inheritance >>
a15dff8d 1019
93a708fd 1020This returns a whitelist of options that can be overridden in a
1021subclass's attribute definition.
2b86e02b 1022
93a708fd 1023This exists to allow a custom metaclass to change or add to the list
1024of options which can be changed.
2b86e02b 1025
93a708fd 1026=item B<< $attr->type_constraint >>
452bac1b 1027
93a708fd 1028Returns the L<Moose::Meta::TypeConstraint> object for this attribute,
1029if it has one.
452bac1b 1030
93a708fd 1031=item B<< $attr->has_type_constraint >>
452bac1b 1032
93a708fd 1033Returns true if this attribute has a type constraint.
452bac1b 1034
93a708fd 1035=item B<< $attr->verify_against_type_constraint($value) >>
a15dff8d 1036
93a708fd 1037Given a value, this method returns true if the value is valid for the
1038attribute's type constraint. If the value is not valid, it throws an
1039error.
4b598ea3 1040
93a708fd 1041=item B<< $attr->handles >>
ca01a97b 1042
93a708fd 1043This returns the value of the C<handles> option passed to the
1044constructor.
ca01a97b 1045
93a708fd 1046=item B<< $attr->has_handles >>
ca01a97b 1047
93a708fd 1048Returns true if this attribute performs delegation.
ca01a97b 1049
93a708fd 1050=item B<< $attr->is_weak_ref >>
26fbace8 1051
93a708fd 1052Returns true if this attribute stores its value as a weak reference.
26fbace8 1053
93a708fd 1054=item B<< $attr->is_required >>
26fbace8 1055
93a708fd 1056Returns true if this attribute is required to have a value.
26fbace8 1057
93a708fd 1058=item B<< $attr->is_lazy >>
58f85113 1059
93a708fd 1060Returns true if this attribute is lazy.
26fbace8 1061
93a708fd 1062=item B<< $attr->is_lazy_build >>
ca01a97b 1063
93a708fd 1064Returns true if the C<lazy_build> option was true when passed to the
1065constructor.
4b598ea3 1066
93a708fd 1067=item B<< $attr->should_coerce >>
6ba6d68c 1068
93a708fd 1069Returns true if the C<coerce> option passed to the constructor was
1070true.
536f0b17 1071
93a708fd 1072=item B<< $attr->should_auto_deref >>
536f0b17 1073
93a708fd 1074Returns true if the C<auto_deref> option passed to the constructor was
1075true.
536f0b17 1076
93a708fd 1077=item B<< $attr->trigger >>
8c9d74e7 1078
93a708fd 1079This is the subroutine reference that was in the C<trigger> option
1080passed to the constructor, if any.
02a0fb52 1081
36741534 1082=item B<< $attr->has_trigger >>
8c9d74e7 1083
93a708fd 1084Returns true if this attribute has a trigger set.
02a0fb52 1085
93a708fd 1086=item B<< $attr->documentation >>
ddbdc0cb 1087
93a708fd 1088Returns the value that was in the C<documentation> option passed to
1089the constructor, if any.
ddbdc0cb 1090
93a708fd 1091=item B<< $attr->has_documentation >>
ddbdc0cb 1092
93a708fd 1093Returns true if this attribute has any documentation.
ddbdc0cb 1094
93a708fd 1095=item B<< $attr->applied_traits >>
88f23977 1096
93a708fd 1097This returns an array reference of all the traits which were applied
1098to this attribute. If none were applied, this returns C<undef>.
88f23977 1099
93a708fd 1100=item B<< $attr->has_applied_traits >>
88f23977 1101
93a708fd 1102Returns true if this attribute has any traits applied.
88f23977 1103
c0e30cf5 1104=back
1105
1106=head1 BUGS
1107
26fbace8 1108All complex software has bugs lurking in it, and this module is no
c0e30cf5 1109exception. If you find a bug please either email me, or add the bug
1110to cpan-RT.
1111
c0e30cf5 1112=head1 AUTHOR
1113
1114Stevan Little E<lt>stevan@iinteractive.comE<gt>
1115
98aae381 1116Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
1117
c0e30cf5 1118=head1 COPYRIGHT AND LICENSE
1119
2840a3b2 1120Copyright 2006-2009 by Infinity Interactive, Inc.
c0e30cf5 1121
1122L<http://www.iinteractive.com>
1123
1124This library is free software; you can redistribute it and/or modify
26fbace8 1125it under the same terms as Perl itself.
c0e30cf5 1126
8a7a9c53 1127=cut