Always use verify_against_type_constraint to check attribute value
[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
56d7c745 10our $VERSION = '0.73';
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
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
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);
87
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 );
98
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(
145 default coerce required
146 documentation lazy handles
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
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
162# feature back up into Class::MOP::Attribute
163# but I not right now, I am too lazy.
164# However if you are reading this and
165# looking for something to do,.. please
166# be my guest.
167# - stevan
ce0e8d63 168sub clone_and_inherit_options {
169 my ($self, %options) = @_;
e606ae5f 170
c32c2c61 171 my %copy = %options;
e606ae5f 172
ce0e8d63 173 my %actual_options;
e606ae5f 174
175 # NOTE:
176 # we may want to extends a Class::MOP::Attribute
177 # in which case we need to be able to use the
178 # core set of legal options that have always
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;
185
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 }
e606ae5f 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 }
2ea379cb 207
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};
221 }
c32c2c61 222
cbd141ca 223 # NOTE:
224 # this doesn't apply to Class::MOP::Attributes,
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
db72153d 251 foreach my $attr ( grep { $_->has_value($self) } $self->meta->compute_all_applicable_attributes ) {
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 ### -------------------------
21f1e231 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 }
293 else {
e606ae5f 294 $class->throw_error("I do not understand this option (is => " . $options->{is} . ") on attribute ($name)", data => $options->{is});
8de73ff1 295 }
f3c4e20e 296 }
8de73ff1 297
f3c4e20e 298 if (exists $options->{isa}) {
f3c4e20e 299 if (exists $options->{does}) {
300 if (eval { $options->{isa}->can('does') }) {
301 ($options->{isa}->does($options->{does}))
e606ae5f 302 || $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 303 }
304 else {
e606ae5f 305 $class->throw_error("Cannot have an isa option which cannot ->does() on attribute ($name)", data => $options);
26fbace8 306 }
26fbace8 307 }
8de73ff1 308
f3c4e20e 309 # allow for anon-subtypes here ...
310 if (blessed($options->{isa}) && $options->{isa}->isa('Moose::Meta::TypeConstraint')) {
8de73ff1 311 $options->{type_constraint} = $options->{isa};
312 }
313 else {
620db045 314 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options->{isa});
8de73ff1 315 }
f3c4e20e 316 }
317 elsif (exists $options->{does}) {
318 # allow for anon-subtypes here ...
319 if (blessed($options->{does}) && $options->{does}->isa('Moose::Meta::TypeConstraint')) {
238b424d 320 $options->{type_constraint} = $options->{does};
8de73ff1 321 }
322 else {
620db045 323 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options->{does});
8de73ff1 324 }
f3c4e20e 325 }
8de73ff1 326
f3c4e20e 327 if (exists $options->{coerce} && $options->{coerce}) {
328 (exists $options->{type_constraint})
e606ae5f 329 || $class->throw_error("You cannot have coercion without specifying a type constraint on attribute ($name)", data => $options);
330 $class->throw_error("You cannot have a weak reference to a coerced value on attribute ($name)", data => $options)
8de73ff1 331 if $options->{weak_ref};
f3c4e20e 332 }
8de73ff1 333
0b7df53c 334 if (exists $options->{trigger}) {
21f1e231 335 ('CODE' eq ref $options->{trigger})
e606ae5f 336 || $class->throw_error("Trigger must be a CODE ref on attribute ($name)", data => $options->{trigger});
0b7df53c 337 }
338
f3c4e20e 339 if (exists $options->{auto_deref} && $options->{auto_deref}) {
340 (exists $options->{type_constraint})
e606ae5f 341 || $class->throw_error("You cannot auto-dereference without specifying a type constraint on attribute ($name)", data => $options);
f3c4e20e 342 ($options->{type_constraint}->is_a_type_of('ArrayRef') ||
8de73ff1 343 $options->{type_constraint}->is_a_type_of('HashRef'))
e606ae5f 344 || $class->throw_error("You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute ($name)", data => $options);
f3c4e20e 345 }
8de73ff1 346
f3c4e20e 347 if (exists $options->{lazy_build} && $options->{lazy_build} == 1) {
e606ae5f 348 $class->throw_error("You can not use lazy_build and default for the same attribute ($name)", data => $options)
8de73ff1 349 if exists $options->{default};
a6c84c69 350 $options->{lazy} = 1;
351 $options->{required} = 1;
352 $options->{builder} ||= "_build_${name}";
353 if ($name =~ /^_/) {
f3c4e20e 354 $options->{clearer} ||= "_clear${name}";
355 $options->{predicate} ||= "_has${name}";
a6c84c69 356 }
357 else {
f3c4e20e 358 $options->{clearer} ||= "clear_${name}";
359 $options->{predicate} ||= "has_${name}";
26fbace8 360 }
f3c4e20e 361 }
8de73ff1 362
f3c4e20e 363 if (exists $options->{lazy} && $options->{lazy}) {
9edba990 364 (exists $options->{default} || defined $options->{builder} )
be05faea 365 || $class->throw_error("You cannot have lazy attribute ($name) without specifying a default value for it", data => $options);
f3c4e20e 366 }
26fbace8 367
9edba990 368 if ( $options->{required} && !( ( !exists $options->{init_arg} || defined $options->{init_arg} ) || exists $options->{default} || defined $options->{builder} ) ) {
be05faea 369 $class->throw_error("You cannot have a required attribute ($name) without a default, builder, or an init_arg", data => $options);
9edba990 370 }
371
78cd1d3b 372}
c0e30cf5 373
d500266f 374sub initialize_instance_slot {
ddd0ec20 375 my ($self, $meta_instance, $instance, $params) = @_;
d500266f 376 my $init_arg = $self->init_arg();
377 # try to fetch the init arg from the %params ...
ddd0ec20 378
26fbace8 379 my $val;
1ed0b94f 380 my $value_is_set;
625d571f 381 if ( defined($init_arg) and exists $params->{$init_arg}) {
d500266f 382 $val = $params->{$init_arg};
2c78d811 383 $value_is_set = 1;
d500266f 384 }
385 else {
386 # skip it if it's lazy
387 return if $self->is_lazy;
388 # and die if it's required and doesn't have a default value
be05faea 389 $self->throw_error("Attribute (" . $self->name . ") is required", object => $instance, data => $params)
26fbace8 390 if $self->is_required && !$self->has_default && !$self->has_builder;
ddd0ec20 391
1ed0b94f 392 # if nothing was in the %params, we can use the
393 # attribute's default value (if it has one)
394 if ($self->has_default) {
395 $val = $self->default($instance);
396 $value_is_set = 1;
a6c84c69 397 }
398 elsif ($self->has_builder) {
e606ae5f 399 $val = $self->_call_builder($instance);
400 $value_is_set = 1;
a0748c37 401 }
26fbace8 402 }
403
1ed0b94f 404 return unless $value_is_set;
405
406 if ($self->has_type_constraint) {
407 my $type_constraint = $self->type_constraint;
408 if ($self->should_coerce && $type_constraint->has_coercion) {
409 $val = $type_constraint->coerce($val);
d500266f 410 }
5755a9b2 411 $self->verify_against_type_constraint($val, instance => $instance);
1ed0b94f 412 }
ddd0ec20 413
759e4e8f 414 $self->set_initial_value($instance, $val);
26fbace8 415 $meta_instance->weaken_slot_value($instance, $self->name)
a6c84c69 416 if ref $val && $self->is_weak_ref;
d500266f 417}
418
e606ae5f 419sub _call_builder {
420 my ( $self, $instance ) = @_;
421
422 my $builder = $self->builder();
423
424 return $instance->$builder()
425 if $instance->can( $self->builder );
426
427 $self->throw_error( blessed($instance)
428 . " does not support builder method '"
429 . $self->builder
430 . "' for attribute '"
431 . $self->name
432 . "'",
433 object => $instance,
434 );
435}
436
d617b644 437## Slot management
9e93dd19 438
8abe9636 439# FIXME:
440# this duplicates too much code from
441# Class::MOP::Attribute, we need to
442# refactor these bits eventually.
443# - SL
444sub _set_initial_slot_value {
445 my ($self, $meta_instance, $instance, $value) = @_;
446
447 my $slot_name = $self->name;
448
449 return $meta_instance->set_slot_value($instance, $slot_name, $value)
450 unless $self->has_initializer;
451
452 my ($type_constraint, $can_coerce);
453 if ($self->has_type_constraint) {
454 $type_constraint = $self->type_constraint;
455 $can_coerce = ($self->should_coerce && $type_constraint->has_coercion);
456 }
457
458 my $callback = sub {
459 my $val = shift;
460 if ($type_constraint) {
461 $val = $type_constraint->coerce($val)
462 if $can_coerce;
5755a9b2 463 $self->verify_against_type_constraint($val, object => $instance);
8abe9636 464 }
465 $meta_instance->set_slot_value($instance, $slot_name, $val);
466 };
467
468 my $initializer = $self->initializer;
469
470 # most things will just want to set a value, so make it first arg
471 $instance->$initializer($value, $callback, $self);
472}
473
946289d1 474sub set_value {
b6af66f8 475 my ($self, $instance, @args) = @_;
476 my $value = $args[0];
26fbace8 477
946289d1 478 my $attr_name = $self->name;
26fbace8 479
b6af66f8 480 if ($self->is_required and not @args) {
be05faea 481 $self->throw_error("Attribute ($attr_name) is required", object => $instance);
946289d1 482 }
26fbace8 483
a1a41ab5 484 my $type_constraint = $self->type_constraint;
485 if ($self->should_coerce && $type_constraint->has_coercion) {
486 $value = $type_constraint->coerce($value);
946289d1 487 }
a1a41ab5 488 $self->verify_against_type_constraint($value, instance => $instance);
26fbace8 489
946289d1 490 my $meta_instance = Class::MOP::Class->initialize(blessed($instance))
491 ->get_meta_instance;
26fbace8 492
493 $meta_instance->set_slot_value($instance, $attr_name, $value);
494
946289d1 495 if (ref $value && $self->is_weak_ref) {
26fbace8 496 $meta_instance->weaken_slot_value($instance, $attr_name);
946289d1 497 }
26fbace8 498
946289d1 499 if ($self->has_trigger) {
525129a5 500 $self->trigger->($instance, $value);
946289d1 501 }
502}
503
504sub get_value {
505 my ($self, $instance) = @_;
26fbace8 506
946289d1 507 if ($self->is_lazy) {
8de73ff1 508 unless ($self->has_value($instance)) {
e606ae5f 509 my $value;
8de73ff1 510 if ($self->has_default) {
e606ae5f 511 $value = $self->default($instance);
3f11800d 512 } elsif ( $self->has_builder ) {
e606ae5f 513 $value = $self->_call_builder($instance);
514 }
515 if ($self->has_type_constraint) {
516 my $type_constraint = $self->type_constraint;
517 $value = $type_constraint->coerce($value)
518 if ($self->should_coerce);
5755a9b2 519 $self->verify_against_type_constraint($value);
26fbace8 520 }
e606ae5f 521 $self->set_initial_value($instance, $value);
8de73ff1 522 }
946289d1 523 }
26fbace8 524
946289d1 525 if ($self->should_auto_deref) {
26fbace8 526
946289d1 527 my $type_constraint = $self->type_constraint;
528
529 if ($type_constraint->is_a_type_of('ArrayRef')) {
530 my $rv = $self->SUPER::get_value($instance);
531 return unless defined $rv;
532 return wantarray ? @{ $rv } : $rv;
26fbace8 533 }
946289d1 534 elsif ($type_constraint->is_a_type_of('HashRef')) {
535 my $rv = $self->SUPER::get_value($instance);
536 return unless defined $rv;
537 return wantarray ? %{ $rv } : $rv;
26fbace8 538 }
946289d1 539 else {
46cb090f 540 $self->throw_error("Can not auto de-reference the type constraint '" . $type_constraint->name . "'", object => $instance, type_constraint => $type_constraint);
946289d1 541 }
26fbace8 542
946289d1 543 }
544 else {
26fbace8 545
946289d1 546 return $self->SUPER::get_value($instance);
26fbace8 547 }
946289d1 548}
a15dff8d 549
26fbace8 550## installing accessors
c0e30cf5 551
d617b644 552sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
d7f17ebb 553
452bac1b 554sub install_accessors {
555 my $self = shift;
26fbace8 556 $self->SUPER::install_accessors(@_);
e606ae5f 557 $self->install_delegation if $self->has_handles;
558 return;
559}
26fbace8 560
e1d6f0a3 561sub remove_accessors {
562 my $self = shift;
563 $self->SUPER::remove_accessors(@_);
564 $self->remove_delegation if $self->has_handles;
565 return;
566}
567
e606ae5f 568sub install_delegation {
569 my $self = shift;
26fbace8 570
e606ae5f 571 # NOTE:
572 # Here we canonicalize the 'handles' option
573 # this will sort out any details and always
574 # return an hash of methods which we want
575 # to delagate to, see that method for details
576 my %handles = $self->_canonicalize_handles;
577
e606ae5f 578
579 # install the delegation ...
580 my $associated_class = $self->associated_class;
581 foreach my $handle (keys %handles) {
582 my $method_to_call = $handles{$handle};
583 my $class_name = $associated_class->name;
584 my $name = "${class_name}::${handle}";
26fbace8 585
452bac1b 586 (!$associated_class->has_method($handle))
cee532a1 587 || $self->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation", method_name => $handle);
26fbace8 588
e606ae5f 589 # NOTE:
590 # handles is not allowed to delegate
591 # any of these methods, as they will
592 # override the ones in your class, which
593 # is almost certainly not what you want.
4fe78472 594
e606ae5f 595 # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
596 #cluck("Not delegating method '$handle' because it is a core method") and
597 next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 598
46f7e6a5 599 my $method = $self->_make_delegation_method($handle, $method_to_call);
a05f85c1 600
601 $self->associated_class->add_method($method->name, $method);
e606ae5f 602 }
452bac1b 603}
604
e1d6f0a3 605sub remove_delegation {
606 my $self = shift;
607 my %handles = $self->_canonicalize_handles;
608 my $associated_class = $self->associated_class;
609 foreach my $handle (keys %handles) {
610 $self->associated_class->remove_method($handle);
611 }
612}
613
98aae381 614# private methods to help delegation ...
615
452bac1b 616sub _canonicalize_handles {
617 my $self = shift;
618 my $handles = $self->handles;
c84f324f 619 if (my $handle_type = ref($handles)) {
620 if ($handle_type eq 'HASH') {
621 return %{$handles};
622 }
623 elsif ($handle_type eq 'ARRAY') {
624 return map { $_ => $_ } @{$handles};
625 }
626 elsif ($handle_type eq 'Regexp') {
627 ($self->has_type_constraint)
0286711b 628 || $self->throw_error("Cannot delegate methods based on a Regexp without a type constraint (isa)", data => $handles);
26fbace8 629 return map { ($_ => $_) }
c84f324f 630 grep { /$handles/ } $self->_get_delegate_method_list;
631 }
632 elsif ($handle_type eq 'CODE') {
633 return $handles->($self, $self->_find_delegate_metaclass);
634 }
635 else {
be05faea 636 $self->throw_error("Unable to canonicalize the 'handles' option with $handles", data => $handles);
c84f324f 637 }
452bac1b 638 }
639 else {
9fa39240 640 Class::MOP::load_class($handles)
641 unless Class::MOP::is_class_loaded($handles);
642
c84f324f 643 my $role_meta = eval { $handles->meta };
644 if ($@) {
be05faea 645 $self->throw_error("Unable to canonicalize the 'handles' option with $handles because : $@", data => $handles, error => $@);
c84f324f 646 }
647
648 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
be05faea 649 || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role", data => $handles);
9fa39240 650
c84f324f 651 return map { $_ => $_ } (
26fbace8 652 $role_meta->get_method_list,
c84f324f 653 $role_meta->get_required_method_list
654 );
452bac1b 655 }
656}
657
658sub _find_delegate_metaclass {
659 my $self = shift;
98aae381 660 if (my $class = $self->_isa_metadata) {
26fbace8 661 # if the class does have
452bac1b 662 # a meta method, use it
663 return $class->meta if $class->can('meta');
26fbace8 664 # otherwise we might be
452bac1b 665 # dealing with a non-Moose
26fbace8 666 # class, and need to make
452bac1b 667 # our own metaclass
668 return Moose::Meta::Class->initialize($class);
669 }
98aae381 670 elsif (my $role = $self->_does_metadata) {
26fbace8 671 # our role will always have
452bac1b 672 # a meta method
98aae381 673 return $role->meta;
452bac1b 674 }
675 else {
be05faea 676 $self->throw_error("Cannot find delegate metaclass for attribute " . $self->name);
452bac1b 677 }
678}
679
680sub _get_delegate_method_list {
681 my $self = shift;
682 my $meta = $self->_find_delegate_metaclass;
683 if ($meta->isa('Class::MOP::Class')) {
e606ae5f 684 return map { $_->name } # NOTE: !never! delegate &meta
685 grep { $_->package_name ne 'Moose::Object' && $_->name ne 'meta' }
686 $meta->get_all_methods;
452bac1b 687 }
688 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 689 return $meta->get_method_list;
452bac1b 690 }
691 else {
be05faea 692 $self->throw_error("Unable to recognize the delegate metaclass '$meta'", data => $meta);
452bac1b 693 }
694}
695
bd1226e2 696sub delegation_metaclass { 'Moose::Meta::Method::Delegation' }
697
a05f85c1 698sub _make_delegation_method {
46f7e6a5 699 my ( $self, $handle_name, $method_to_call ) = @_;
a05f85c1 700
701 my $method_body;
702
46f7e6a5 703 $method_body = $method_to_call
704 if 'CODE' eq ref($method_to_call);
a05f85c1 705
bd1226e2 706 return $self->delegation_metaclass->new(
46f7e6a5 707 name => $handle_name,
708 package_name => $self->associated_class->name,
709 attribute => $self,
710 delegate_to_method => $method_to_call,
a05f85c1 711 );
712}
713
5755a9b2 714sub verify_against_type_constraint {
2b86e02b 715 my $self = shift;
716 my $val = shift;
717
718 return 1 if !$self->has_type_constraint;
719
720 my $type_constraint = $self->type_constraint;
721
722 $type_constraint->check($val)
723 || $self->throw_error("Attribute ("
724 . $self->name
725 . ") does not pass the type constraint because: "
726 . $type_constraint->get_message($val), data => $val, @_);
727}
728
21f1e231 729package Moose::Meta::Attribute::Custom::Moose;
730sub register_implementation { 'Moose::Meta::Attribute' }
731
c0e30cf5 7321;
733
734__END__
735
736=pod
737
738=head1 NAME
739
6ba6d68c 740Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 741
742=head1 DESCRIPTION
743
93a708fd 744This class is a subclass of L<Class::MOP::Attribute> that provides
745additional Moose-specific functionality.
6ba6d68c 746
7854b409 747To really understand this class, you will need to start with the
748L<Class::MOP::Attribute> documentation. This class can be understood
749as a set of additional features on top of the basic feature provided
750by that parent class.
e522431d 751
d4b1449e 752=head1 INHERITANCE
753
754C<Moose::Meta::Attribute> is a subclass of L<Class::MOP::Attribute>.
755
c0e30cf5 756=head1 METHODS
757
93a708fd 758Many of the documented below override methods in
759L<Class::MOP::Attribute> and add Moose specific features.
6ba6d68c 760
93a708fd 761=head2 Creation
6ba6d68c 762
c0e30cf5 763=over 4
764
93a708fd 765=item B<< Moose::Meta::Attribute->new(%options) >>
c0e30cf5 766
93a708fd 767This method overrides the L<Class::MOP::Attribute> constructor.
c32c2c61 768
93a708fd 769Many of the options below are described in more detail in the
770L<Moose::Manual::Attributes> document.
6e2840b7 771
93a708fd 772It adds the following options to the constructor:
d500266f 773
93a708fd 774=over 8
452bac1b 775
93a708fd 776=item * is => 'ro' or 'rw'
e1d6f0a3 777
93a708fd 778This provides a shorthand for specifying the C<reader>, C<writer>, or
779C<accessor> names. If the attribute is read-only ('ro') then it will
780have a C<reader> method with the same attribute as the name.
e606ae5f 781
93a708fd 782If it is read-write ('rw') then it will have an C<accessor> method
783with the same name. If you provide an explicit C<writer> for a
784read-write attribute, then you will have a C<reader> with the same
785name as the attribute, and a C<writer> with the name you provided.
e1d6f0a3 786
93a708fd 787=item * isa => $type
39b3bc94 788
93a708fd 789This option accepts a type. The type can be a string, which should be
790a type name. If the type name is unknown, it is assumed to be a class
791name.
792
793This option can also accept a L<Moose::Meta::TypeConstraint> object.
794
795If you I<also> provide a C<does> option, then your C<isa> option must
796be a class name, and that class must do the role specified with
797C<does>.
798
799=item * does => $role
800
801This is short-hand for saying that the attribute's type must be an
802object which does the named role.
803
804=item * coerce => $bool
805
806This option is only valid for objects with a type constraint
807(C<isa>). If this is true, then coercions will be applied whenever
808this attribute is set.
809
810You can make both this and the C<weak_ref> option true.
811
812=item * trigger => $sub
813
814This option accepts a subroutine reference, which will be called after
815the attribute is set.
816
817=item * required => $bool
818
819An attribute which is required must be provided to the constructor. An
820attribute which is required can also have a C<default> or C<builder>,
36741534 821which will satisfy its required-ness.
93a708fd 822
823A required attribute must have a C<default>, C<builder> or a
824non-C<undef> C<init_arg>
825
826=item * lazy => $bool
827
828A lazy attribute must have a C<default> or C<builder>. When an
829attribute is lazy, the default value will not be calculated until the
830attribute is read.
831
832=item * weak_ref => $bool
833
834If this is true, the attribute's value will be stored as a weak
835reference.
836
837=item * auto_deref => $bool
838
839If this is true, then the reader will dereference the value when it is
840called. The attribute must have a type constraint which defines the
841attribute as an array or hash reference.
842
843=item * lazy_build => $bool
844
845Setting this to true makes the attribute lazy and provides a number of
846default methods.
847
848 has 'size' => (
849 is => 'ro',
850 lazy_build => 1,
851 );
852
853is equivalent to this:
854
855 has 'size' => (
856 is => 'ro',
857 lazy => 1,
858 builder => '_build_size',
859 clearer => 'clear_size',
860 predicate => 'has_size',
861 );
862
863=item * documentation
864
865An arbitrary string that can be retrieved later by calling C<<
866$attr->documentation >>.
867
868=back
869
870=item B<< $attr->clone(%options) >>
871
872This creates a new attribute based on attribute being cloned. You must
873supply a C<name> option to provide a new name for the attribute.
874
875The C<%options> can only specify options handled by
876L<Class::MOP::Attribute>.
877
36741534 878=back
879
93a708fd 880=head2 Value management
881
36741534 882=over 4
883
93a708fd 884=item B<< $attr->initialize_instance_slot($meta_instance, $instance, $params) >>
885
886This method is used internally to initialize the attribute's slot in
887the object C<$instance>.
888
889This overrides the L<Class::MOP::Attribute> method to handle lazy
890attributes, weak references, and type constraints.
bd1226e2 891
946289d1 892=item B<get_value>
893
894=item B<set_value>
895
6549b0d1 896 eval { $point->meta->get_attribute('x')->set_value($point, 'forty-two') };
bcbaa845 897 if($@) {
898 print "Oops: $@\n";
899 }
900
6549b0d1 901I<Attribute (x) does not pass the type constraint (Int) with 'forty-two'>
bcbaa845 902
903Before setting the value, a check is made on the type constraint of
904the attribute, if it has one, to see if the value passes it. If the
46cb090f 905value fails to pass, the set operation dies with a L<throw_error>.
bcbaa845 906
907Any coercion to convert values is done before checking the type constraint.
908
909To check a value against a type constraint before setting it, fetch the
ec00fa75 910attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 911fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
e606ae5f 912and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Recipe4>
bcbaa845 913for an example.
914
a15dff8d 915=back
916
93a708fd 917=head2 Attribute Accessor generation
6ba6d68c 918
a15dff8d 919=over 4
920
93a708fd 921=item B<< $attr->install_accessors >>
be05faea 922
93a708fd 923This method overrides the parent to also install delegation methods.
be05faea 924
36741534 925=item B<< $attr->remove_accessors >>
d5c30e52 926
93a708fd 927This method overrides the parent to also remove delegation methods.
d5c30e52 928
93a708fd 929=item B<< $attr->install_delegation >>
930
931This method adds its delegation methods to the attribute's associated
932class, if it has any to add.
933
934=item B<< $attr->remove_delegation >>
935
936This method remove its delegation methods from the attribute's
937associated class.
d5c30e52 938
93a708fd 939=item B<< $attr->accessor_metaclass >>
9e93dd19 940
93a708fd 941Returns the accessor metaclass name, which defaults to
942L<Moose::Meta::Method::Accessor>.
943
944=item B<< $attr->delegation_metaclass >>
945
946Returns the delegation metaclass name, which defaults to
947L<Moose::Meta::Method::Delegation>.
948
949=back
950
951=head2 Additional Moose features
952
953These methods are not found in the superclass. They support features
954provided by Moose.
955
36741534 956=over 4
957
93a708fd 958=item B<< $attr->does($role) >>
959
960This indicates whether the I<attribute itself> does the given
36741534 961role. The role can be given as a full class name, or as a resolvable
93a708fd 962trait name.
963
964Note that this checks the attribute itself, not its type constraint,
965so it is checking the attribute's metaclass and any traits applied to
966the attribute.
967
968=item B<< Moose::Meta::Class->interpolate_class_and_new($name, %options) >>
969
970This is an alternate constructor that handles the C<metaclass> and
971C<traits> options.
9e93dd19 972
93a708fd 973Effectively, this method is a factory that finds or creates the
36741534 974appropriate class for the given C<metaclass> and/or C<traits>.
e606ae5f 975
93a708fd 976Once it has the appropriate class, it will call C<< $class->new($name,
977%options) >> on that class.
e606ae5f 978
93a708fd 979=item B<< $attr->clone_and_inherit_options(%options) >>
a15dff8d 980
93a708fd 981This method supports the C<has '+foo'> feature. It does various bits
982of processing on the supplied C<%options> before ultimately calling
983the C<clone> method.
6ba6d68c 984
93a708fd 985One of its main tasks is to make sure that the C<%options> provided
986only includes the options returned by the
987C<legal_options_for_inheritance> method.
a15dff8d 988
93a708fd 989=item B<< $attr->legal_options_for_inheritance >>
a15dff8d 990
93a708fd 991This returns a whitelist of options that can be overridden in a
992subclass's attribute definition.
2b86e02b 993
93a708fd 994This exists to allow a custom metaclass to change or add to the list
995of options which can be changed.
2b86e02b 996
93a708fd 997=item B<< $attr->type_constraint >>
452bac1b 998
93a708fd 999Returns the L<Moose::Meta::TypeConstraint> object for this attribute,
1000if it has one.
452bac1b 1001
93a708fd 1002=item B<< $attr->has_type_constraint >>
452bac1b 1003
93a708fd 1004Returns true if this attribute has a type constraint.
452bac1b 1005
93a708fd 1006=item B<< $attr->verify_against_type_constraint($value) >>
a15dff8d 1007
93a708fd 1008Given a value, this method returns true if the value is valid for the
1009attribute's type constraint. If the value is not valid, it throws an
1010error.
4b598ea3 1011
93a708fd 1012=item B<< $attr->handles >>
ca01a97b 1013
93a708fd 1014This returns the value of the C<handles> option passed to the
1015constructor.
ca01a97b 1016
93a708fd 1017=item B<< $attr->has_handles >>
ca01a97b 1018
93a708fd 1019Returns true if this attribute performs delegation.
ca01a97b 1020
93a708fd 1021=item B<< $attr->is_weak_ref >>
26fbace8 1022
93a708fd 1023Returns true if this attribute stores its value as a weak reference.
26fbace8 1024
93a708fd 1025=item B<< $attr->is_required >>
26fbace8 1026
93a708fd 1027Returns true if this attribute is required to have a value.
26fbace8 1028
93a708fd 1029=item B<< $attr->is_lazy >>
58f85113 1030
93a708fd 1031Returns true if this attribute is lazy.
26fbace8 1032
93a708fd 1033=item B<< $attr->is_lazy_build >>
ca01a97b 1034
93a708fd 1035Returns true if the C<lazy_build> option was true when passed to the
1036constructor.
4b598ea3 1037
93a708fd 1038=item B<< $attr->should_coerce >>
6ba6d68c 1039
93a708fd 1040Returns true if the C<coerce> option passed to the constructor was
1041true.
536f0b17 1042
93a708fd 1043=item B<< $attr->should_auto_deref >>
536f0b17 1044
93a708fd 1045Returns true if the C<auto_deref> option passed to the constructor was
1046true.
536f0b17 1047
93a708fd 1048=item B<< $attr->trigger >>
8c9d74e7 1049
93a708fd 1050This is the subroutine reference that was in the C<trigger> option
1051passed to the constructor, if any.
02a0fb52 1052
36741534 1053=item B<< $attr->has_trigger >>
8c9d74e7 1054
93a708fd 1055Returns true if this attribute has a trigger set.
02a0fb52 1056
93a708fd 1057=item B<< $attr->documentation >>
ddbdc0cb 1058
93a708fd 1059Returns the value that was in the C<documentation> option passed to
1060the constructor, if any.
ddbdc0cb 1061
93a708fd 1062=item B<< $attr->has_documentation >>
ddbdc0cb 1063
93a708fd 1064Returns true if this attribute has any documentation.
ddbdc0cb 1065
93a708fd 1066=item B<< $attr->applied_traits >>
88f23977 1067
93a708fd 1068This returns an array reference of all the traits which were applied
1069to this attribute. If none were applied, this returns C<undef>.
88f23977 1070
93a708fd 1071=item B<< $attr->has_applied_traits >>
88f23977 1072
93a708fd 1073Returns true if this attribute has any traits applied.
88f23977 1074
c0e30cf5 1075=back
1076
1077=head1 BUGS
1078
26fbace8 1079All complex software has bugs lurking in it, and this module is no
c0e30cf5 1080exception. If you find a bug please either email me, or add the bug
1081to cpan-RT.
1082
c0e30cf5 1083=head1 AUTHOR
1084
1085Stevan Little E<lt>stevan@iinteractive.comE<gt>
1086
98aae381 1087Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
1088
c0e30cf5 1089=head1 COPYRIGHT AND LICENSE
1090
2840a3b2 1091Copyright 2006-2009 by Infinity Interactive, Inc.
c0e30cf5 1092
1093L<http://www.iinteractive.com>
1094
1095This library is free software; you can redistribute it and/or modify
26fbace8 1096it under the same terms as Perl itself.
c0e30cf5 1097
8a7a9c53 1098=cut