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