Make the POD formatting match other Moose POD
[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
4b2189ce 10our $VERSION = '0.72';
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',
43 predicate => 'has_handles',
44));
ddbdc0cb 45__PACKAGE__->meta->add_attribute('documentation' => (
46 reader => 'documentation',
47 predicate => 'has_documentation',
48));
82a5b1a7 49__PACKAGE__->meta->add_attribute('traits' => (
50 reader => 'applied_traits',
51 predicate => 'has_applied_traits',
52));
82168dbb 53
587e457d 54# we need to have a ->does method in here to
55# more easily support traits, and the introspection
0db4f1d7 56# of those traits. We extend the does check to look
57# for metatrait aliases.
58sub does {
59 my ($self, $role_name) = @_;
60 my $name = eval {
61 Moose::Util::resolve_metatrait_alias(Attribute => $role_name)
62 };
63 return 0 if !defined($name); # failed to load class
e8895723 64 return $self->Moose::Object::does($name);
0db4f1d7 65}
587e457d 66
be05faea 67sub throw_error {
68 my $self = shift;
69 my $class = ( ref $self && $self->associated_class ) || "Moose::Meta::Class";
70 unshift @_, "message" if @_ % 2 == 1;
71 unshift @_, attr => $self if ref $self;
72 unshift @_, $class;
18748ad6 73 my $handler = $class->can("throw_error"); # to avoid incrementing depth by 1
74 goto $handler;
be05faea 75}
76
78cd1d3b 77sub new {
f3c4e20e 78 my ($class, $name, %options) = @_;
c32c2c61 79 $class->_process_options($name, \%options) unless $options{__hack_no_process_options}; # used from clone()... YECHKKK FIXME ICKY YUCK GROSS
f3c4e20e 80 return $class->SUPER::new($name, %options);
1d768fb1 81}
82
d5c30e52 83sub interpolate_class_and_new {
84 my ($class, $name, @args) = @_;
85
c32c2c61 86 my ( $new_class, @traits ) = $class->interpolate_class(@args);
87
88 $new_class->new($name, @args, ( scalar(@traits) ? ( traits => \@traits ) : () ) );
d5c30e52 89}
90
91sub interpolate_class {
92 my ($class, %options) = @_;
93
c32c2c61 94 $class = ref($class) || $class;
95
96 if ( my $metaclass_name = delete $options{metaclass} ) {
97 my $new_class = Moose::Util::resolve_metaclass_alias( Attribute => $metaclass_name );
98
99 if ( $class ne $new_class ) {
100 if ( $new_class->can("interpolate_class") ) {
101 return $new_class->interpolate_class(%options);
102 } else {
103 $class = $new_class;
104 }
105 }
d5c30e52 106 }
107
c32c2c61 108 my @traits;
109
d5c30e52 110 if (my $traits = $options{traits}) {
8974015d 111 my $i = 0;
112 while ($i < @$traits) {
113 my $trait = $traits->[$i++];
114 next if ref($trait); # options to a trait we discarded
115
116 $trait = Moose::Util::resolve_metatrait_alias(Attribute => $trait)
117 || $trait;
118
119 next if $class->does($trait);
120
121 push @traits, $trait;
122
123 # are there options?
124 push @traits, $traits->[$i++]
125 if $traits->[$i] && ref($traits->[$i]);
126 }
965743fb 127
128 if (@traits) {
c32c2c61 129 my $anon_class = Moose::Meta::Class->create_anon_class(
130 superclasses => [ $class ],
131 roles => [ @traits ],
132 cache => 1,
133 );
134
135 $class = $anon_class->name;
136 }
d5c30e52 137 }
c32c2c61 138
139 return ( wantarray ? ( $class, @traits ) : $class );
d5c30e52 140}
141
e606ae5f 142# ...
143
144my @legal_options_for_inheritance = qw(
145 default coerce required
146 documentation lazy handles
147 builder type_constraint
5f06098e 148 definition_context
449559bf 149 lazy_build
e606ae5f 150);
151
152sub legal_options_for_inheritance { @legal_options_for_inheritance }
153
154# NOTE/TODO
155# This method *must* be able to handle
156# Class::MOP::Attribute instances as
157# well. Yes, I know that is wrong, but
158# apparently we didn't realize it was
159# doing that and now we have some code
160# which is dependent on it. The real
161# solution of course is to push this
162# feature back up into Class::MOP::Attribute
163# but I not right now, I am too lazy.
164# However if you are reading this and
165# looking for something to do,.. please
166# be my guest.
167# - stevan
ce0e8d63 168sub clone_and_inherit_options {
169 my ($self, %options) = @_;
e606ae5f 170
c32c2c61 171 my %copy = %options;
e606ae5f 172
ce0e8d63 173 my %actual_options;
e606ae5f 174
175 # NOTE:
176 # we may want to extends a Class::MOP::Attribute
177 # in which case we need to be able to use the
178 # core set of legal options that have always
179 # been here. But we allows Moose::Meta::Attribute
180 # instances to changes them.
181 # - SL
182 my @legal_options = $self->can('legal_options_for_inheritance')
183 ? $self->legal_options_for_inheritance
184 : @legal_options_for_inheritance;
185
186 foreach my $legal_option (@legal_options) {
ce0e8d63 187 if (exists $options{$legal_option}) {
188 $actual_options{$legal_option} = $options{$legal_option};
189 delete $options{$legal_option};
190 }
e606ae5f 191 }
26fbace8 192
ce0e8d63 193 if ($options{isa}) {
194 my $type_constraint;
8de73ff1 195 if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
196 $type_constraint = $options{isa};
197 }
198 else {
d40ce9d5 199 $type_constraint = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options{isa});
8de73ff1 200 (defined $type_constraint)
be05faea 201 || $self->throw_error("Could not find the type constraint '" . $options{isa} . "'", data => $options{isa});
8de73ff1 202 }
5e98d2b6 203
8de73ff1 204 $actual_options{type_constraint} = $type_constraint;
ce0e8d63 205 delete $options{isa};
206 }
2ea379cb 207
208 if ($options{does}) {
209 my $type_constraint;
210 if (blessed($options{does}) && $options{does}->isa('Moose::Meta::TypeConstraint')) {
211 $type_constraint = $options{does};
212 }
213 else {
d40ce9d5 214 $type_constraint = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options{does});
2ea379cb 215 (defined $type_constraint)
be05faea 216 || $self->throw_error("Could not find the type constraint '" . $options{does} . "'", data => $options{does});
2ea379cb 217 }
218
219 $actual_options{type_constraint} = $type_constraint;
220 delete $options{does};
221 }
c32c2c61 222
cbd141ca 223 # NOTE:
224 # this doesn't apply to Class::MOP::Attributes,
225 # so we can ignore it for them.
226 # - SL
227 if ($self->can('interpolate_class')) {
228 ( $actual_options{metaclass}, my @traits ) = $self->interpolate_class(%options);
c32c2c61 229
cbd141ca 230 my %seen;
231 my @all_traits = grep { $seen{$_}++ } @{ $self->applied_traits || [] }, @traits;
232 $actual_options{traits} = \@all_traits if @all_traits;
c32c2c61 233
cbd141ca 234 delete @options{qw(metaclass traits)};
235 }
c32c2c61 236
26fbace8 237 (scalar keys %options == 0)
be05faea 238 || $self->throw_error("Illegal inherited options => (" . (join ', ' => keys %options) . ")", data => \%options);
c32c2c61 239
240
ce0e8d63 241 $self->clone(%actual_options);
1d768fb1 242}
243
c32c2c61 244sub clone {
245 my ( $self, %params ) = @_;
246
247 my $class = $params{metaclass} || ref $self;
248
249 if ( 0 and $class eq ref $self ) {
250 return $self->SUPER::clone(%params);
251 } else {
252 my ( @init, @non_init );
253
254 foreach my $attr ( grep { $_->has_value($self) } $self->meta->compute_all_applicable_attributes ) {
255 push @{ $attr->has_init_arg ? \@init : \@non_init }, $attr;
256 }
257
258 my %new_params = ( ( map { $_->init_arg => $_->get_value($self) } @init ), %params );
259
260 my $name = delete $new_params{name};
261
262 my $clone = $class->new($name, %new_params, __hack_no_process_options => 1 );
263
264 foreach my $attr ( @non_init ) {
265 $attr->set_value($clone, $attr->get_value($self));
266 }
267
268
269 return $clone;
270 }
271}
272
1d768fb1 273sub _process_options {
274 my ($class, $name, $options) = @_;
8de73ff1 275
f3c4e20e 276 if (exists $options->{is}) {
21f1e231 277
012fcbd1 278 ### -------------------------
279 ## is => ro, writer => _foo # turns into (reader => foo, writer => _foo) as before
280 ## is => rw, writer => _foo # turns into (reader => foo, writer => _foo)
281 ## is => rw, accessor => _foo # turns into (accessor => _foo)
282 ## is => ro, accessor => _foo # error, accesor is rw
283 ### -------------------------
21f1e231 284
8de73ff1 285 if ($options->{is} eq 'ro') {
be05faea 286 $class->throw_error("Cannot define an accessor name on a read-only attribute, accessors are read/write", data => $options)
21f1e231 287 if exists $options->{accessor};
8de73ff1 288 $options->{reader} ||= $name;
8de73ff1 289 }
290 elsif ($options->{is} eq 'rw') {
21f1e231 291 if ($options->{writer}) {
292 $options->{reader} ||= $name;
293 }
294 else {
295 $options->{accessor} ||= $name;
296 }
8de73ff1 297 }
298 else {
e606ae5f 299 $class->throw_error("I do not understand this option (is => " . $options->{is} . ") on attribute ($name)", data => $options->{is});
8de73ff1 300 }
f3c4e20e 301 }
8de73ff1 302
f3c4e20e 303 if (exists $options->{isa}) {
f3c4e20e 304 if (exists $options->{does}) {
305 if (eval { $options->{isa}->can('does') }) {
306 ($options->{isa}->does($options->{does}))
e606ae5f 307 || $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 308 }
309 else {
e606ae5f 310 $class->throw_error("Cannot have an isa option which cannot ->does() on attribute ($name)", data => $options);
26fbace8 311 }
26fbace8 312 }
8de73ff1 313
f3c4e20e 314 # allow for anon-subtypes here ...
315 if (blessed($options->{isa}) && $options->{isa}->isa('Moose::Meta::TypeConstraint')) {
8de73ff1 316 $options->{type_constraint} = $options->{isa};
317 }
318 else {
620db045 319 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($options->{isa});
8de73ff1 320 }
f3c4e20e 321 }
322 elsif (exists $options->{does}) {
323 # allow for anon-subtypes here ...
324 if (blessed($options->{does}) && $options->{does}->isa('Moose::Meta::TypeConstraint')) {
238b424d 325 $options->{type_constraint} = $options->{does};
8de73ff1 326 }
327 else {
620db045 328 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_does_type_constraint($options->{does});
8de73ff1 329 }
f3c4e20e 330 }
8de73ff1 331
f3c4e20e 332 if (exists $options->{coerce} && $options->{coerce}) {
333 (exists $options->{type_constraint})
e606ae5f 334 || $class->throw_error("You cannot have coercion without specifying a type constraint on attribute ($name)", data => $options);
335 $class->throw_error("You cannot have a weak reference to a coerced value on attribute ($name)", data => $options)
8de73ff1 336 if $options->{weak_ref};
f3c4e20e 337 }
8de73ff1 338
0b7df53c 339 if (exists $options->{trigger}) {
21f1e231 340 ('CODE' eq ref $options->{trigger})
e606ae5f 341 || $class->throw_error("Trigger must be a CODE ref on attribute ($name)", data => $options->{trigger});
0b7df53c 342 }
343
f3c4e20e 344 if (exists $options->{auto_deref} && $options->{auto_deref}) {
345 (exists $options->{type_constraint})
e606ae5f 346 || $class->throw_error("You cannot auto-dereference without specifying a type constraint on attribute ($name)", data => $options);
f3c4e20e 347 ($options->{type_constraint}->is_a_type_of('ArrayRef') ||
8de73ff1 348 $options->{type_constraint}->is_a_type_of('HashRef'))
e606ae5f 349 || $class->throw_error("You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute ($name)", data => $options);
f3c4e20e 350 }
8de73ff1 351
f3c4e20e 352 if (exists $options->{lazy_build} && $options->{lazy_build} == 1) {
e606ae5f 353 $class->throw_error("You can not use lazy_build and default for the same attribute ($name)", data => $options)
8de73ff1 354 if exists $options->{default};
a6c84c69 355 $options->{lazy} = 1;
356 $options->{required} = 1;
357 $options->{builder} ||= "_build_${name}";
358 if ($name =~ /^_/) {
f3c4e20e 359 $options->{clearer} ||= "_clear${name}";
360 $options->{predicate} ||= "_has${name}";
a6c84c69 361 }
362 else {
f3c4e20e 363 $options->{clearer} ||= "clear_${name}";
364 $options->{predicate} ||= "has_${name}";
26fbace8 365 }
f3c4e20e 366 }
8de73ff1 367
f3c4e20e 368 if (exists $options->{lazy} && $options->{lazy}) {
9edba990 369 (exists $options->{default} || defined $options->{builder} )
be05faea 370 || $class->throw_error("You cannot have lazy attribute ($name) without specifying a default value for it", data => $options);
f3c4e20e 371 }
26fbace8 372
9edba990 373 if ( $options->{required} && !( ( !exists $options->{init_arg} || defined $options->{init_arg} ) || exists $options->{default} || defined $options->{builder} ) ) {
be05faea 374 $class->throw_error("You cannot have a required attribute ($name) without a default, builder, or an init_arg", data => $options);
9edba990 375 }
376
78cd1d3b 377}
c0e30cf5 378
d500266f 379sub initialize_instance_slot {
ddd0ec20 380 my ($self, $meta_instance, $instance, $params) = @_;
d500266f 381 my $init_arg = $self->init_arg();
382 # try to fetch the init arg from the %params ...
ddd0ec20 383
26fbace8 384 my $val;
1ed0b94f 385 my $value_is_set;
625d571f 386 if ( defined($init_arg) and exists $params->{$init_arg}) {
d500266f 387 $val = $params->{$init_arg};
2c78d811 388 $value_is_set = 1;
d500266f 389 }
390 else {
391 # skip it if it's lazy
392 return if $self->is_lazy;
393 # and die if it's required and doesn't have a default value
be05faea 394 $self->throw_error("Attribute (" . $self->name . ") is required", object => $instance, data => $params)
26fbace8 395 if $self->is_required && !$self->has_default && !$self->has_builder;
ddd0ec20 396
1ed0b94f 397 # if nothing was in the %params, we can use the
398 # attribute's default value (if it has one)
399 if ($self->has_default) {
400 $val = $self->default($instance);
401 $value_is_set = 1;
a6c84c69 402 }
403 elsif ($self->has_builder) {
e606ae5f 404 $val = $self->_call_builder($instance);
405 $value_is_set = 1;
a0748c37 406 }
26fbace8 407 }
408
1ed0b94f 409 return unless $value_is_set;
410
411 if ($self->has_type_constraint) {
412 my $type_constraint = $self->type_constraint;
413 if ($self->should_coerce && $type_constraint->has_coercion) {
414 $val = $type_constraint->coerce($val);
d500266f 415 }
5755a9b2 416 $self->verify_against_type_constraint($val, instance => $instance);
1ed0b94f 417 }
ddd0ec20 418
759e4e8f 419 $self->set_initial_value($instance, $val);
26fbace8 420 $meta_instance->weaken_slot_value($instance, $self->name)
a6c84c69 421 if ref $val && $self->is_weak_ref;
d500266f 422}
423
e606ae5f 424sub _call_builder {
425 my ( $self, $instance ) = @_;
426
427 my $builder = $self->builder();
428
429 return $instance->$builder()
430 if $instance->can( $self->builder );
431
432 $self->throw_error( blessed($instance)
433 . " does not support builder method '"
434 . $self->builder
435 . "' for attribute '"
436 . $self->name
437 . "'",
438 object => $instance,
439 );
440}
441
d617b644 442## Slot management
9e93dd19 443
8abe9636 444# FIXME:
445# this duplicates too much code from
446# Class::MOP::Attribute, we need to
447# refactor these bits eventually.
448# - SL
449sub _set_initial_slot_value {
450 my ($self, $meta_instance, $instance, $value) = @_;
451
452 my $slot_name = $self->name;
453
454 return $meta_instance->set_slot_value($instance, $slot_name, $value)
455 unless $self->has_initializer;
456
457 my ($type_constraint, $can_coerce);
458 if ($self->has_type_constraint) {
459 $type_constraint = $self->type_constraint;
460 $can_coerce = ($self->should_coerce && $type_constraint->has_coercion);
461 }
462
463 my $callback = sub {
464 my $val = shift;
465 if ($type_constraint) {
466 $val = $type_constraint->coerce($val)
467 if $can_coerce;
5755a9b2 468 $self->verify_against_type_constraint($val, object => $instance);
8abe9636 469 }
470 $meta_instance->set_slot_value($instance, $slot_name, $val);
471 };
472
473 my $initializer = $self->initializer;
474
475 # most things will just want to set a value, so make it first arg
476 $instance->$initializer($value, $callback, $self);
477}
478
946289d1 479sub set_value {
b6af66f8 480 my ($self, $instance, @args) = @_;
481 my $value = $args[0];
26fbace8 482
946289d1 483 my $attr_name = $self->name;
26fbace8 484
b6af66f8 485 if ($self->is_required and not @args) {
be05faea 486 $self->throw_error("Attribute ($attr_name) is required", object => $instance);
946289d1 487 }
26fbace8 488
946289d1 489 if ($self->has_type_constraint) {
26fbace8 490
946289d1 491 my $type_constraint = $self->type_constraint;
26fbace8 492
946289d1 493 if ($self->should_coerce) {
26fbace8 494 $value = $type_constraint->coerce($value);
688fcdda 495 }
42bc21a4 496 $type_constraint->_compiled_type_constraint->($value)
be05faea 497 || $self->throw_error("Attribute ("
688fcdda 498 . $self->name
499 . ") does not pass the type constraint because "
be05faea 500 . $type_constraint->get_message($value), object => $instance, data => $value);
946289d1 501 }
26fbace8 502
946289d1 503 my $meta_instance = Class::MOP::Class->initialize(blessed($instance))
504 ->get_meta_instance;
26fbace8 505
506 $meta_instance->set_slot_value($instance, $attr_name, $value);
507
946289d1 508 if (ref $value && $self->is_weak_ref) {
26fbace8 509 $meta_instance->weaken_slot_value($instance, $attr_name);
946289d1 510 }
26fbace8 511
946289d1 512 if ($self->has_trigger) {
525129a5 513 $self->trigger->($instance, $value);
946289d1 514 }
515}
516
517sub get_value {
518 my ($self, $instance) = @_;
26fbace8 519
946289d1 520 if ($self->is_lazy) {
8de73ff1 521 unless ($self->has_value($instance)) {
e606ae5f 522 my $value;
8de73ff1 523 if ($self->has_default) {
e606ae5f 524 $value = $self->default($instance);
3f11800d 525 } elsif ( $self->has_builder ) {
e606ae5f 526 $value = $self->_call_builder($instance);
527 }
528 if ($self->has_type_constraint) {
529 my $type_constraint = $self->type_constraint;
530 $value = $type_constraint->coerce($value)
531 if ($self->should_coerce);
5755a9b2 532 $self->verify_against_type_constraint($value);
26fbace8 533 }
e606ae5f 534 $self->set_initial_value($instance, $value);
8de73ff1 535 }
946289d1 536 }
26fbace8 537
946289d1 538 if ($self->should_auto_deref) {
26fbace8 539
946289d1 540 my $type_constraint = $self->type_constraint;
541
542 if ($type_constraint->is_a_type_of('ArrayRef')) {
543 my $rv = $self->SUPER::get_value($instance);
544 return unless defined $rv;
545 return wantarray ? @{ $rv } : $rv;
26fbace8 546 }
946289d1 547 elsif ($type_constraint->is_a_type_of('HashRef')) {
548 my $rv = $self->SUPER::get_value($instance);
549 return unless defined $rv;
550 return wantarray ? %{ $rv } : $rv;
26fbace8 551 }
946289d1 552 else {
46cb090f 553 $self->throw_error("Can not auto de-reference the type constraint '" . $type_constraint->name . "'", object => $instance, type_constraint => $type_constraint);
946289d1 554 }
26fbace8 555
946289d1 556 }
557 else {
26fbace8 558
946289d1 559 return $self->SUPER::get_value($instance);
26fbace8 560 }
946289d1 561}
a15dff8d 562
26fbace8 563## installing accessors
c0e30cf5 564
d617b644 565sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
d7f17ebb 566
452bac1b 567sub install_accessors {
568 my $self = shift;
26fbace8 569 $self->SUPER::install_accessors(@_);
e606ae5f 570 $self->install_delegation if $self->has_handles;
571 return;
572}
26fbace8 573
e1d6f0a3 574sub remove_accessors {
575 my $self = shift;
576 $self->SUPER::remove_accessors(@_);
577 $self->remove_delegation if $self->has_handles;
578 return;
579}
580
e606ae5f 581sub install_delegation {
582 my $self = shift;
26fbace8 583
e606ae5f 584 # NOTE:
585 # Here we canonicalize the 'handles' option
586 # this will sort out any details and always
587 # return an hash of methods which we want
588 # to delagate to, see that method for details
589 my %handles = $self->_canonicalize_handles;
590
e606ae5f 591
592 # install the delegation ...
593 my $associated_class = $self->associated_class;
594 foreach my $handle (keys %handles) {
595 my $method_to_call = $handles{$handle};
596 my $class_name = $associated_class->name;
597 my $name = "${class_name}::${handle}";
26fbace8 598
452bac1b 599 (!$associated_class->has_method($handle))
cee532a1 600 || $self->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation", method_name => $handle);
26fbace8 601
e606ae5f 602 # NOTE:
603 # handles is not allowed to delegate
604 # any of these methods, as they will
605 # override the ones in your class, which
606 # is almost certainly not what you want.
4fe78472 607
e606ae5f 608 # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
609 #cluck("Not delegating method '$handle' because it is a core method") and
610 next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 611
46f7e6a5 612 my $method = $self->_make_delegation_method($handle, $method_to_call);
a05f85c1 613
614 $self->associated_class->add_method($method->name, $method);
e606ae5f 615 }
452bac1b 616}
617
e1d6f0a3 618sub remove_delegation {
619 my $self = shift;
620 my %handles = $self->_canonicalize_handles;
621 my $associated_class = $self->associated_class;
622 foreach my $handle (keys %handles) {
623 $self->associated_class->remove_method($handle);
624 }
625}
626
98aae381 627# private methods to help delegation ...
628
452bac1b 629sub _canonicalize_handles {
630 my $self = shift;
631 my $handles = $self->handles;
c84f324f 632 if (my $handle_type = ref($handles)) {
633 if ($handle_type eq 'HASH') {
634 return %{$handles};
635 }
636 elsif ($handle_type eq 'ARRAY') {
637 return map { $_ => $_ } @{$handles};
638 }
639 elsif ($handle_type eq 'Regexp') {
640 ($self->has_type_constraint)
0286711b 641 || $self->throw_error("Cannot delegate methods based on a Regexp without a type constraint (isa)", data => $handles);
26fbace8 642 return map { ($_ => $_) }
c84f324f 643 grep { /$handles/ } $self->_get_delegate_method_list;
644 }
645 elsif ($handle_type eq 'CODE') {
646 return $handles->($self, $self->_find_delegate_metaclass);
647 }
648 else {
be05faea 649 $self->throw_error("Unable to canonicalize the 'handles' option with $handles", data => $handles);
c84f324f 650 }
452bac1b 651 }
652 else {
9fa39240 653 Class::MOP::load_class($handles)
654 unless Class::MOP::is_class_loaded($handles);
655
c84f324f 656 my $role_meta = eval { $handles->meta };
657 if ($@) {
be05faea 658 $self->throw_error("Unable to canonicalize the 'handles' option with $handles because : $@", data => $handles, error => $@);
c84f324f 659 }
660
661 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
be05faea 662 || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role", data => $handles);
9fa39240 663
c84f324f 664 return map { $_ => $_ } (
26fbace8 665 $role_meta->get_method_list,
c84f324f 666 $role_meta->get_required_method_list
667 );
452bac1b 668 }
669}
670
671sub _find_delegate_metaclass {
672 my $self = shift;
98aae381 673 if (my $class = $self->_isa_metadata) {
26fbace8 674 # if the class does have
452bac1b 675 # a meta method, use it
676 return $class->meta if $class->can('meta');
26fbace8 677 # otherwise we might be
452bac1b 678 # dealing with a non-Moose
26fbace8 679 # class, and need to make
452bac1b 680 # our own metaclass
681 return Moose::Meta::Class->initialize($class);
682 }
98aae381 683 elsif (my $role = $self->_does_metadata) {
26fbace8 684 # our role will always have
452bac1b 685 # a meta method
98aae381 686 return $role->meta;
452bac1b 687 }
688 else {
be05faea 689 $self->throw_error("Cannot find delegate metaclass for attribute " . $self->name);
452bac1b 690 }
691}
692
693sub _get_delegate_method_list {
694 my $self = shift;
695 my $meta = $self->_find_delegate_metaclass;
696 if ($meta->isa('Class::MOP::Class')) {
e606ae5f 697 return map { $_->name } # NOTE: !never! delegate &meta
698 grep { $_->package_name ne 'Moose::Object' && $_->name ne 'meta' }
699 $meta->get_all_methods;
452bac1b 700 }
701 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 702 return $meta->get_method_list;
452bac1b 703 }
704 else {
be05faea 705 $self->throw_error("Unable to recognize the delegate metaclass '$meta'", data => $meta);
452bac1b 706 }
707}
708
bd1226e2 709sub delegation_metaclass { 'Moose::Meta::Method::Delegation' }
710
a05f85c1 711sub _make_delegation_method {
46f7e6a5 712 my ( $self, $handle_name, $method_to_call ) = @_;
a05f85c1 713
714 my $method_body;
715
46f7e6a5 716 $method_body = $method_to_call
717 if 'CODE' eq ref($method_to_call);
a05f85c1 718
bd1226e2 719 return $self->delegation_metaclass->new(
46f7e6a5 720 name => $handle_name,
721 package_name => $self->associated_class->name,
722 attribute => $self,
723 delegate_to_method => $method_to_call,
a05f85c1 724 );
725}
726
5755a9b2 727sub verify_against_type_constraint {
2b86e02b 728 my $self = shift;
729 my $val = shift;
730
731 return 1 if !$self->has_type_constraint;
732
733 my $type_constraint = $self->type_constraint;
734
735 $type_constraint->check($val)
736 || $self->throw_error("Attribute ("
737 . $self->name
738 . ") does not pass the type constraint because: "
739 . $type_constraint->get_message($val), data => $val, @_);
740}
741
21f1e231 742package Moose::Meta::Attribute::Custom::Moose;
743sub register_implementation { 'Moose::Meta::Attribute' }
744
c0e30cf5 7451;
746
747__END__
748
749=pod
750
751=head1 NAME
752
6ba6d68c 753Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 754
755=head1 DESCRIPTION
756
26fbace8 757This is a subclass of L<Class::MOP::Attribute> with Moose specific
758extensions.
6ba6d68c 759
26fbace8 760For the most part, the only time you will ever encounter an
761instance of this class is if you are doing some serious deep
762introspection. To really understand this class, you need to refer
6ba6d68c 763to the L<Class::MOP::Attribute> documentation.
e522431d 764
c0e30cf5 765=head1 METHODS
766
6ba6d68c 767=head2 Overridden methods
768
26fbace8 769These methods override methods in L<Class::MOP::Attribute> and add
770Moose specific features. You can safely assume though that they
6ba6d68c 771will behave just as L<Class::MOP::Attribute> does.
772
c0e30cf5 773=over 4
774
775=item B<new>
776
c32c2c61 777=item B<clone>
778
6e2840b7 779=item B<does>
780
d500266f 781=item B<initialize_instance_slot>
782
452bac1b 783=item B<install_accessors>
784
e1d6f0a3 785=item B<remove_accessors>
786
e606ae5f 787=item B<install_delegation>
788
e1d6f0a3 789=item B<remove_delegation>
790
39b3bc94 791=item B<accessor_metaclass>
792
bd1226e2 793=item B<delegation_metaclass>
794
946289d1 795=item B<get_value>
796
797=item B<set_value>
798
6549b0d1 799 eval { $point->meta->get_attribute('x')->set_value($point, 'forty-two') };
bcbaa845 800 if($@) {
801 print "Oops: $@\n";
802 }
803
6549b0d1 804I<Attribute (x) does not pass the type constraint (Int) with 'forty-two'>
bcbaa845 805
806Before setting the value, a check is made on the type constraint of
807the attribute, if it has one, to see if the value passes it. If the
46cb090f 808value fails to pass, the set operation dies with a L<throw_error>.
bcbaa845 809
810Any coercion to convert values is done before checking the type constraint.
811
812To check a value against a type constraint before setting it, fetch the
ec00fa75 813attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 814fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
e606ae5f 815and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::Basics::Recipe4>
bcbaa845 816for an example.
817
a15dff8d 818=back
819
6ba6d68c 820=head2 Additional Moose features
821
26fbace8 822Moose attributes support type-constraint checking, weak reference
823creation and type coercion.
6ba6d68c 824
a15dff8d 825=over 4
826
be05faea 827=item B<throw_error>
828
829Delegates to C<associated_class> or C<Moose::Meta::Class> if there is none.
830
d5c30e52 831=item B<interpolate_class_and_new>
832
833=item B<interpolate_class>
834
835When called as a class method causes interpretation of the C<metaclass> and
836C<traits> options.
837
9e93dd19 838=item B<clone_and_inherit_options>
839
26fbace8 840This is to support the C<has '+foo'> feature, it clones an attribute
841from a superclass and allows a very specific set of changes to be made
9e93dd19 842to the attribute.
843
e606ae5f 844=item B<legal_options_for_inheritance>
845
846Whitelist with options you can change. You can overload it in your custom
847metaclass to allow your options be inheritable.
848
a15dff8d 849=item B<has_type_constraint>
850
6ba6d68c 851Returns true if this meta-attribute has a type constraint.
852
a15dff8d 853=item B<type_constraint>
854
26fbace8 855A read-only accessor for this meta-attribute's type constraint. For
856more information on what you can do with this, see the documentation
6ba6d68c 857for L<Moose::Meta::TypeConstraint>.
a15dff8d 858
5755a9b2 859=item B<verify_against_type_constraint>
2b86e02b 860
43cb5dad 861Verifies that the given value is valid under this attribute's type
2b86e02b 862constraint, otherwise throws an error.
863
452bac1b 864=item B<has_handles>
865
866Returns true if this meta-attribute performs delegation.
867
868=item B<handles>
869
870This returns the value which was passed into the handles option.
871
6ba6d68c 872=item B<is_weak_ref>
a15dff8d 873
02a0fb52 874Returns true if this meta-attribute produces a weak reference.
4b598ea3 875
ca01a97b 876=item B<is_required>
877
02a0fb52 878Returns true if this meta-attribute is required to have a value.
ca01a97b 879
880=item B<is_lazy>
881
02a0fb52 882Returns true if this meta-attribute should be initialized lazily.
ca01a97b 883
26fbace8 884NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
885
886=item B<is_lazy_build>
887
888Returns true if this meta-attribute should be initialized lazily through
889the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
890make your attribute required and lazy. In addition it will set the builder, clearer
891and predicate options for you using the following convention.
892
893 #If your attribute name starts with an underscore:
894 has '_foo' => (lazy_build => 1);
895 #is the same as
e606ae5f 896 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo');
26fbace8 897 # or
58f85113 898 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
26fbace8 899
900 #If your attribute name does not start with an underscore:
58f85113 901 has 'foo' => (lazy_build => 1);
902 #is the same as
e606ae5f 903 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo');
26fbace8 904 # or
58f85113 905 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
906
907The reason for the different naming of the C<builder> is that the C<builder>
908method is a private method while the C<clearer> and C<predicate> methods
909are public methods.
26fbace8 910
911NOTE: This means your class should provide a method whose name matches the value
58f85113 912of the builder part, in this case _build__foo or _build_foo.
ca01a97b 913
34a66aa3 914=item B<should_coerce>
4b598ea3 915
02a0fb52 916Returns true if this meta-attribute should perform type coercion.
6ba6d68c 917
536f0b17 918=item B<should_auto_deref>
919
26fbace8 920Returns true if this meta-attribute should perform automatic
921auto-dereferencing.
536f0b17 922
26fbace8 923NOTE: This can only be done for attributes whose type constraint is
536f0b17 924either I<ArrayRef> or I<HashRef>.
925
8c9d74e7 926=item B<has_trigger>
927
02a0fb52 928Returns true if this meta-attribute has a trigger set.
929
8c9d74e7 930=item B<trigger>
931
26fbace8 932This is a CODE reference which will be executed every time the
933value of an attribute is assigned. The CODE ref will get two values,
934the invocant and the new value. This can be used to handle I<basic>
02a0fb52 935bi-directional relations.
936
ddbdc0cb 937=item B<documentation>
938
26fbace8 939This is a string which contains the documentation for this attribute.
ddbdc0cb 940It serves no direct purpose right now, but it might in the future
941in some kind of automated documentation system perhaps.
942
943=item B<has_documentation>
944
945Returns true if this meta-attribute has any documentation.
946
88f23977 947=item B<applied_traits>
948
949This will return the ARRAY ref of all the traits applied to this
950attribute, or if no traits have been applied, it returns C<undef>.
951
952=item B<has_applied_traits>
953
954Returns true if this meta-attribute has any traits applied.
955
c0e30cf5 956=back
957
958=head1 BUGS
959
26fbace8 960All complex software has bugs lurking in it, and this module is no
c0e30cf5 961exception. If you find a bug please either email me, or add the bug
962to cpan-RT.
963
c0e30cf5 964=head1 AUTHOR
965
966Stevan Little E<lt>stevan@iinteractive.comE<gt>
967
98aae381 968Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
969
c0e30cf5 970=head1 COPYRIGHT AND LICENSE
971
2840a3b2 972Copyright 2006-2009 by Infinity Interactive, Inc.
c0e30cf5 973
974L<http://www.iinteractive.com>
975
976This library is free software; you can redistribute it and/or modify
26fbace8 977it under the same terms as Perl itself.
c0e30cf5 978
8a7a9c53 979=cut