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