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