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