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