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