work in progress on getting rt 48985 changes working with moose
[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
6e56c6e0 10our $VERSION = '0.89_02';
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
3b6e2290 585sub _process_accessors {
586 my $self = shift;
587 my ($type, $accessor, $generate_as_inline_methods) = @_;
588 $accessor = (keys %$accessor)[0] if (ref($accessor)||'') eq 'HASH';
99541dfd 589 my $method = $self->associated_class->get_method($accessor);
590 if ($method && !$method->isa('Class::MOP::Method::Accessor')
591 && (!$self->definition_context
592 || $method->package_name eq $self->definition_context->{package})) {
3b6e2290 593 Carp::cluck(
1d18c898 594 "You are overwriting a locally defined method ($accessor) with "
3b6e2290 595 . "an accessor"
596 );
597 }
598 $self->SUPER::_process_accessors(@_);
e606ae5f 599}
26fbace8 600
e1d6f0a3 601sub remove_accessors {
602 my $self = shift;
603 $self->SUPER::remove_accessors(@_);
604 $self->remove_delegation if $self->has_handles;
605 return;
606}
607
e606ae5f 608sub install_delegation {
609 my $self = shift;
26fbace8 610
e606ae5f 611 # NOTE:
612 # Here we canonicalize the 'handles' option
613 # this will sort out any details and always
614 # return an hash of methods which we want
615 # to delagate to, see that method for details
616 my %handles = $self->_canonicalize_handles;
617
e606ae5f 618
619 # install the delegation ...
620 my $associated_class = $self->associated_class;
621 foreach my $handle (keys %handles) {
622 my $method_to_call = $handles{$handle};
623 my $class_name = $associated_class->name;
624 my $name = "${class_name}::${handle}";
26fbace8 625
452bac1b 626 (!$associated_class->has_method($handle))
cee532a1 627 || $self->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation", method_name => $handle);
26fbace8 628
e606ae5f 629 # NOTE:
630 # handles is not allowed to delegate
631 # any of these methods, as they will
632 # override the ones in your class, which
633 # is almost certainly not what you want.
4fe78472 634
e606ae5f 635 # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
636 #cluck("Not delegating method '$handle' because it is a core method") and
637 next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 638
46f7e6a5 639 my $method = $self->_make_delegation_method($handle, $method_to_call);
a05f85c1 640
641 $self->associated_class->add_method($method->name, $method);
0bbd378f 642 $self->associate_method($method);
d03bd989 643 }
452bac1b 644}
645
e1d6f0a3 646sub remove_delegation {
647 my $self = shift;
648 my %handles = $self->_canonicalize_handles;
649 my $associated_class = $self->associated_class;
650 foreach my $handle (keys %handles) {
651 $self->associated_class->remove_method($handle);
652 }
653}
654
98aae381 655# private methods to help delegation ...
656
452bac1b 657sub _canonicalize_handles {
658 my $self = shift;
659 my $handles = $self->handles;
c84f324f 660 if (my $handle_type = ref($handles)) {
661 if ($handle_type eq 'HASH') {
662 return %{$handles};
663 }
664 elsif ($handle_type eq 'ARRAY') {
665 return map { $_ => $_ } @{$handles};
666 }
667 elsif ($handle_type eq 'Regexp') {
668 ($self->has_type_constraint)
0286711b 669 || $self->throw_error("Cannot delegate methods based on a Regexp without a type constraint (isa)", data => $handles);
26fbace8 670 return map { ($_ => $_) }
c84f324f 671 grep { /$handles/ } $self->_get_delegate_method_list;
672 }
673 elsif ($handle_type eq 'CODE') {
674 return $handles->($self, $self->_find_delegate_metaclass);
675 }
6cbf4a23 676 elsif (blessed($handles) && $handles->isa('Moose::Meta::TypeConstraint::DuckType')) {
677 return map { $_ => $_ } @{ $handles->methods };
678 }
c84f324f 679 else {
be05faea 680 $self->throw_error("Unable to canonicalize the 'handles' option with $handles", data => $handles);
c84f324f 681 }
452bac1b 682 }
683 else {
c8d9f1e2 684 Class::MOP::load_class($handles);
685 my $role_meta = Class::MOP::class_of($handles);
c84f324f 686
687 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
425ca605 688 || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because its metaclass is not a Moose::Meta::Role", data => $handles);
d03bd989 689
c84f324f 690 return map { $_ => $_ } (
26fbace8 691 $role_meta->get_method_list,
b07a4e6d 692 map { $_->name } $role_meta->get_required_method_list,
c84f324f 693 );
452bac1b 694 }
695}
696
697sub _find_delegate_metaclass {
698 my $self = shift;
98aae381 699 if (my $class = $self->_isa_metadata) {
9031e2c4 700 # we might be dealing with a non-Moose class,
701 # and need to make our own metaclass. if there's
702 # already a metaclass, it will be returned
452bac1b 703 return Moose::Meta::Class->initialize($class);
704 }
98aae381 705 elsif (my $role = $self->_does_metadata) {
91e6653b 706 return Class::MOP::class_of($role);
452bac1b 707 }
708 else {
be05faea 709 $self->throw_error("Cannot find delegate metaclass for attribute " . $self->name);
452bac1b 710 }
711}
712
713sub _get_delegate_method_list {
714 my $self = shift;
715 my $meta = $self->_find_delegate_metaclass;
716 if ($meta->isa('Class::MOP::Class')) {
e606ae5f 717 return map { $_->name } # NOTE: !never! delegate &meta
718 grep { $_->package_name ne 'Moose::Object' && $_->name ne 'meta' }
719 $meta->get_all_methods;
452bac1b 720 }
721 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 722 return $meta->get_method_list;
452bac1b 723 }
724 else {
be05faea 725 $self->throw_error("Unable to recognize the delegate metaclass '$meta'", data => $meta);
452bac1b 726 }
727}
728
bd1226e2 729sub delegation_metaclass { 'Moose::Meta::Method::Delegation' }
730
a05f85c1 731sub _make_delegation_method {
46f7e6a5 732 my ( $self, $handle_name, $method_to_call ) = @_;
a05f85c1 733
734 my $method_body;
735
46f7e6a5 736 $method_body = $method_to_call
737 if 'CODE' eq ref($method_to_call);
a05f85c1 738
3c573ca4 739 my @curried_arguments;
2de18801 740
3c573ca4 741 ($method_to_call, @curried_arguments) = @$method_to_call
2de18801 742 if 'ARRAY' eq ref($method_to_call);
743
bd1226e2 744 return $self->delegation_metaclass->new(
46f7e6a5 745 name => $handle_name,
746 package_name => $self->associated_class->name,
747 attribute => $self,
748 delegate_to_method => $method_to_call,
3c573ca4 749 curried_arguments => \@curried_arguments,
a05f85c1 750 );
751}
752
9c9563c7 753sub _coerce_and_verify {
754 my $self = shift;
755 my $val = shift;
756 my $instance = shift;
757
758 return $val unless $self->has_type_constraint;
759
760 my $type_constraint = $self->type_constraint;
761 if ($self->should_coerce && $type_constraint->has_coercion) {
762 $val = $type_constraint->coerce($val);
763 }
764
765 $self->verify_against_type_constraint($val, instance => $instance);
766
767 return $val;
768}
769
5755a9b2 770sub verify_against_type_constraint {
2b86e02b 771 my $self = shift;
772 my $val = shift;
773
774 return 1 if !$self->has_type_constraint;
775
776 my $type_constraint = $self->type_constraint;
777
778 $type_constraint->check($val)
779 || $self->throw_error("Attribute ("
780 . $self->name
781 . ") does not pass the type constraint because: "
782 . $type_constraint->get_message($val), data => $val, @_);
783}
784
21f1e231 785package Moose::Meta::Attribute::Custom::Moose;
786sub register_implementation { 'Moose::Meta::Attribute' }
787
c0e30cf5 7881;
789
790__END__
791
792=pod
793
794=head1 NAME
795
6ba6d68c 796Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 797
798=head1 DESCRIPTION
799
93a708fd 800This class is a subclass of L<Class::MOP::Attribute> that provides
801additional Moose-specific functionality.
6ba6d68c 802
7854b409 803To really understand this class, you will need to start with the
804L<Class::MOP::Attribute> documentation. This class can be understood
805as a set of additional features on top of the basic feature provided
806by that parent class.
e522431d 807
d4b1449e 808=head1 INHERITANCE
809
810C<Moose::Meta::Attribute> is a subclass of L<Class::MOP::Attribute>.
811
c0e30cf5 812=head1 METHODS
813
93a708fd 814Many of the documented below override methods in
815L<Class::MOP::Attribute> and add Moose specific features.
6ba6d68c 816
93a708fd 817=head2 Creation
6ba6d68c 818
c0e30cf5 819=over 4
820
93a708fd 821=item B<< Moose::Meta::Attribute->new(%options) >>
c0e30cf5 822
93a708fd 823This method overrides the L<Class::MOP::Attribute> constructor.
c32c2c61 824
93a708fd 825Many of the options below are described in more detail in the
826L<Moose::Manual::Attributes> document.
6e2840b7 827
93a708fd 828It adds the following options to the constructor:
d500266f 829
93a708fd 830=over 8
452bac1b 831
996b8c8d 832=item * is => 'ro', 'rw', 'bare'
e1d6f0a3 833
93a708fd 834This provides a shorthand for specifying the C<reader>, C<writer>, or
835C<accessor> names. If the attribute is read-only ('ro') then it will
836have a C<reader> method with the same attribute as the name.
e606ae5f 837
93a708fd 838If it is read-write ('rw') then it will have an C<accessor> method
839with the same name. If you provide an explicit C<writer> for a
840read-write attribute, then you will have a C<reader> with the same
841name as the attribute, and a C<writer> with the name you provided.
e1d6f0a3 842
996b8c8d 843Use 'bare' when you are deliberately not installing any methods
844(accessor, reader, etc.) associated with this attribute; otherwise,
845Moose will issue a deprecation warning when this attribute is added to a
9340e346 846metaclass.
996b8c8d 847
93a708fd 848=item * isa => $type
39b3bc94 849
93a708fd 850This option accepts a type. The type can be a string, which should be
851a type name. If the type name is unknown, it is assumed to be a class
852name.
853
854This option can also accept a L<Moose::Meta::TypeConstraint> object.
855
856If you I<also> provide a C<does> option, then your C<isa> option must
857be a class name, and that class must do the role specified with
858C<does>.
859
860=item * does => $role
861
862This is short-hand for saying that the attribute's type must be an
863object which does the named role.
864
865=item * coerce => $bool
866
867This option is only valid for objects with a type constraint
868(C<isa>). If this is true, then coercions will be applied whenever
869this attribute is set.
870
871You can make both this and the C<weak_ref> option true.
872
873=item * trigger => $sub
874
875This option accepts a subroutine reference, which will be called after
876the attribute is set.
877
878=item * required => $bool
879
880An attribute which is required must be provided to the constructor. An
881attribute which is required can also have a C<default> or C<builder>,
36741534 882which will satisfy its required-ness.
93a708fd 883
884A required attribute must have a C<default>, C<builder> or a
885non-C<undef> C<init_arg>
886
887=item * lazy => $bool
888
889A lazy attribute must have a C<default> or C<builder>. When an
890attribute is lazy, the default value will not be calculated until the
891attribute is read.
892
893=item * weak_ref => $bool
894
895If this is true, the attribute's value will be stored as a weak
896reference.
897
898=item * auto_deref => $bool
899
900If this is true, then the reader will dereference the value when it is
901called. The attribute must have a type constraint which defines the
902attribute as an array or hash reference.
903
904=item * lazy_build => $bool
905
906Setting this to true makes the attribute lazy and provides a number of
907default methods.
908
909 has 'size' => (
910 is => 'ro',
911 lazy_build => 1,
912 );
913
914is equivalent to this:
915
916 has 'size' => (
917 is => 'ro',
918 lazy => 1,
919 builder => '_build_size',
920 clearer => 'clear_size',
921 predicate => 'has_size',
922 );
923
924=item * documentation
925
926An arbitrary string that can be retrieved later by calling C<<
927$attr->documentation >>.
928
929=back
930
931=item B<< $attr->clone(%options) >>
932
933This creates a new attribute based on attribute being cloned. You must
934supply a C<name> option to provide a new name for the attribute.
935
936The C<%options> can only specify options handled by
937L<Class::MOP::Attribute>.
938
36741534 939=back
940
93a708fd 941=head2 Value management
942
36741534 943=over 4
944
93a708fd 945=item B<< $attr->initialize_instance_slot($meta_instance, $instance, $params) >>
946
947This method is used internally to initialize the attribute's slot in
948the object C<$instance>.
949
950This overrides the L<Class::MOP::Attribute> method to handle lazy
951attributes, weak references, and type constraints.
bd1226e2 952
946289d1 953=item B<get_value>
954
955=item B<set_value>
956
6549b0d1 957 eval { $point->meta->get_attribute('x')->set_value($point, 'forty-two') };
bcbaa845 958 if($@) {
959 print "Oops: $@\n";
960 }
961
6549b0d1 962I<Attribute (x) does not pass the type constraint (Int) with 'forty-two'>
bcbaa845 963
964Before setting the value, a check is made on the type constraint of
965the attribute, if it has one, to see if the value passes it. If the
46cb090f 966value fails to pass, the set operation dies with a L<throw_error>.
bcbaa845 967
968Any coercion to convert values is done before checking the type constraint.
969
970To check a value against a type constraint before setting it, fetch the
ec00fa75 971attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 972fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
e606ae5f 973and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Recipe4>
bcbaa845 974for an example.
975
a15dff8d 976=back
977
93a708fd 978=head2 Attribute Accessor generation
6ba6d68c 979
a15dff8d 980=over 4
981
93a708fd 982=item B<< $attr->install_accessors >>
be05faea 983
93a708fd 984This method overrides the parent to also install delegation methods.
be05faea 985
7a582117 986If, after installing all methods, the attribute object has no associated
987methods, it throws an error unless C<< is => 'bare' >> was passed to the
988attribute constructor. (Trying to add an attribute that has no associated
989methods is almost always an error.)
990
36741534 991=item B<< $attr->remove_accessors >>
d5c30e52 992
93a708fd 993This method overrides the parent to also remove delegation methods.
d5c30e52 994
93a708fd 995=item B<< $attr->install_delegation >>
996
997This method adds its delegation methods to the attribute's associated
998class, if it has any to add.
999
1000=item B<< $attr->remove_delegation >>
1001
1002This method remove its delegation methods from the attribute's
1003associated class.
d5c30e52 1004
93a708fd 1005=item B<< $attr->accessor_metaclass >>
9e93dd19 1006
93a708fd 1007Returns the accessor metaclass name, which defaults to
1008L<Moose::Meta::Method::Accessor>.
1009
1010=item B<< $attr->delegation_metaclass >>
1011
1012Returns the delegation metaclass name, which defaults to
1013L<Moose::Meta::Method::Delegation>.
1014
1015=back
1016
1017=head2 Additional Moose features
1018
1019These methods are not found in the superclass. They support features
1020provided by Moose.
1021
36741534 1022=over 4
1023
93a708fd 1024=item B<< $attr->does($role) >>
1025
1026This indicates whether the I<attribute itself> does the given
36741534 1027role. The role can be given as a full class name, or as a resolvable
93a708fd 1028trait name.
1029
1030Note that this checks the attribute itself, not its type constraint,
1031so it is checking the attribute's metaclass and any traits applied to
1032the attribute.
1033
1034=item B<< Moose::Meta::Class->interpolate_class_and_new($name, %options) >>
1035
1036This is an alternate constructor that handles the C<metaclass> and
1037C<traits> options.
9e93dd19 1038
93a708fd 1039Effectively, this method is a factory that finds or creates the
36741534 1040appropriate class for the given C<metaclass> and/or C<traits>.
e606ae5f 1041
93a708fd 1042Once it has the appropriate class, it will call C<< $class->new($name,
1043%options) >> on that class.
e606ae5f 1044
93a708fd 1045=item B<< $attr->clone_and_inherit_options(%options) >>
a15dff8d 1046
93a708fd 1047This method supports the C<has '+foo'> feature. It does various bits
1048of processing on the supplied C<%options> before ultimately calling
1049the C<clone> method.
6ba6d68c 1050
93a708fd 1051One of its main tasks is to make sure that the C<%options> provided
1052only includes the options returned by the
1053C<legal_options_for_inheritance> method.
a15dff8d 1054
93a708fd 1055=item B<< $attr->legal_options_for_inheritance >>
a15dff8d 1056
93a708fd 1057This returns a whitelist of options that can be overridden in a
1058subclass's attribute definition.
2b86e02b 1059
93a708fd 1060This exists to allow a custom metaclass to change or add to the list
1061of options which can be changed.
2b86e02b 1062
93a708fd 1063=item B<< $attr->type_constraint >>
452bac1b 1064
93a708fd 1065Returns the L<Moose::Meta::TypeConstraint> object for this attribute,
1066if it has one.
452bac1b 1067
93a708fd 1068=item B<< $attr->has_type_constraint >>
452bac1b 1069
93a708fd 1070Returns true if this attribute has a type constraint.
452bac1b 1071
93a708fd 1072=item B<< $attr->verify_against_type_constraint($value) >>
a15dff8d 1073
93a708fd 1074Given a value, this method returns true if the value is valid for the
1075attribute's type constraint. If the value is not valid, it throws an
1076error.
4b598ea3 1077
93a708fd 1078=item B<< $attr->handles >>
ca01a97b 1079
93a708fd 1080This returns the value of the C<handles> option passed to the
1081constructor.
ca01a97b 1082
93a708fd 1083=item B<< $attr->has_handles >>
ca01a97b 1084
93a708fd 1085Returns true if this attribute performs delegation.
ca01a97b 1086
93a708fd 1087=item B<< $attr->is_weak_ref >>
26fbace8 1088
93a708fd 1089Returns true if this attribute stores its value as a weak reference.
26fbace8 1090
93a708fd 1091=item B<< $attr->is_required >>
26fbace8 1092
93a708fd 1093Returns true if this attribute is required to have a value.
26fbace8 1094
93a708fd 1095=item B<< $attr->is_lazy >>
58f85113 1096
93a708fd 1097Returns true if this attribute is lazy.
26fbace8 1098
93a708fd 1099=item B<< $attr->is_lazy_build >>
ca01a97b 1100
93a708fd 1101Returns true if the C<lazy_build> option was true when passed to the
1102constructor.
4b598ea3 1103
93a708fd 1104=item B<< $attr->should_coerce >>
6ba6d68c 1105
93a708fd 1106Returns true if the C<coerce> option passed to the constructor was
1107true.
536f0b17 1108
93a708fd 1109=item B<< $attr->should_auto_deref >>
536f0b17 1110
93a708fd 1111Returns true if the C<auto_deref> option passed to the constructor was
1112true.
536f0b17 1113
93a708fd 1114=item B<< $attr->trigger >>
8c9d74e7 1115
93a708fd 1116This is the subroutine reference that was in the C<trigger> option
1117passed to the constructor, if any.
02a0fb52 1118
36741534 1119=item B<< $attr->has_trigger >>
8c9d74e7 1120
93a708fd 1121Returns true if this attribute has a trigger set.
02a0fb52 1122
93a708fd 1123=item B<< $attr->documentation >>
ddbdc0cb 1124
93a708fd 1125Returns the value that was in the C<documentation> option passed to
1126the constructor, if any.
ddbdc0cb 1127
93a708fd 1128=item B<< $attr->has_documentation >>
ddbdc0cb 1129
93a708fd 1130Returns true if this attribute has any documentation.
ddbdc0cb 1131
93a708fd 1132=item B<< $attr->applied_traits >>
88f23977 1133
93a708fd 1134This returns an array reference of all the traits which were applied
1135to this attribute. If none were applied, this returns C<undef>.
88f23977 1136
93a708fd 1137=item B<< $attr->has_applied_traits >>
88f23977 1138
93a708fd 1139Returns true if this attribute has any traits applied.
88f23977 1140
c0e30cf5 1141=back
1142
1143=head1 BUGS
1144
26fbace8 1145All complex software has bugs lurking in it, and this module is no
c0e30cf5 1146exception. If you find a bug please either email me, or add the bug
1147to cpan-RT.
1148
c0e30cf5 1149=head1 AUTHOR
1150
1151Stevan Little E<lt>stevan@iinteractive.comE<gt>
1152
98aae381 1153Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
1154
c0e30cf5 1155=head1 COPYRIGHT AND LICENSE
1156
2840a3b2 1157Copyright 2006-2009 by Infinity Interactive, Inc.
c0e30cf5 1158
1159L<http://www.iinteractive.com>
1160
1161This library is free software; you can redistribute it and/or modify
26fbace8 1162it under the same terms as Perl itself.
c0e30cf5 1163
8a7a9c53 1164=cut