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