Give an error message when a handles attribute's object is undefined, so it doesn...
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
1
2 package Moose::Meta::Attribute;
3
4 use strict;
5 use warnings;
6
7 use Scalar::Util 'blessed', 'weaken', 'reftype';
8 use Carp         'confess';
9 use Sub::Name    'subname';
10 use overload     ();
11
12 our $VERSION   = '0.19';
13 our $AUTHORITY = 'cpan:STEVAN';
14
15 use Moose::Meta::Method::Accessor;
16 use Moose::Util::TypeConstraints ();
17
18 use base 'Class::MOP::Attribute';
19
20 # options which are not directly used
21 # but we store them for metadata purposes
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'));
25
26 # these are actual options for the attrs
27 __PACKAGE__->meta->add_attribute('required'   => (reader => 'is_required'      ));
28 __PACKAGE__->meta->add_attribute('lazy'       => (reader => 'is_lazy'          ));
29 __PACKAGE__->meta->add_attribute('lazy_build' => (reader => 'is_lazy_build'    ));
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'));
33 __PACKAGE__->meta->add_attribute('type_constraint' => (
34     reader    => 'type_constraint',
35     predicate => 'has_type_constraint',
36 ));
37 __PACKAGE__->meta->add_attribute('trigger' => (
38     reader    => 'trigger',
39     predicate => 'has_trigger',
40 ));
41 __PACKAGE__->meta->add_attribute('handles' => (
42     reader    => 'handles',
43     predicate => 'has_handles',
44 ));
45 __PACKAGE__->meta->add_attribute('documentation' => (
46     reader    => 'documentation',
47     predicate => 'has_documentation',
48 ));
49
50 sub new {
51     my ($class, $name, %options) = @_;
52     $class->_process_options($name, \%options);
53     return $class->SUPER::new($name, %options);
54 }
55
56 sub clone_and_inherit_options {
57     my ($self, %options) = @_;
58     # you can change default, required, coerce, documentation and lazy
59     my %actual_options;
60     foreach my $legal_option (qw(default coerce required documentation lazy)) {
61         if (exists $options{$legal_option}) {
62             $actual_options{$legal_option} = $options{$legal_option};
63             delete $options{$legal_option};
64         }
65     }
66
67     # handles can only be added, not changed
68     if ($options{handles}) {
69         confess "You can only add the 'handles' option, you cannot change it"
70             if $self->has_handles;
71         $actual_options{handles} = $options{handles};
72         delete $options{handles};
73     }
74
75     # isa can be changed, but only if the
76     # new type is a subtype
77     if ($options{isa}) {
78         my $type_constraint;
79         if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
80             $type_constraint = $options{isa};
81         }
82         else {
83             $type_constraint = Moose::Util::TypeConstraints::find_or_create_type_constraint(
84                 $options{isa}
85             );
86             (defined $type_constraint)
87                 || confess "Could not find the type constraint '" . $options{isa} . "'";
88         }
89         # NOTE:
90         # check here to see if the new type
91         # is a subtype of the old one
92         ($type_constraint->is_subtype_of($self->type_constraint->name))
93             || confess "New type constraint setting must be a subtype of inherited one"
94                 # iff we have a type constraint that is ...
95                 if $self->has_type_constraint;
96         # then we use it :)
97         $actual_options{type_constraint} = $type_constraint;
98         delete $options{isa};
99     }
100     (scalar keys %options == 0)
101         || confess "Illegal inherited options => (" . (join ', ' => keys %options) . ")";
102     $self->clone(%actual_options);
103 }
104
105 sub _process_options {
106     my ($class, $name, $options) = @_;
107
108     if (exists $options->{is}) {
109         if ($options->{is} eq 'ro') {
110             $options->{reader} ||= $name;
111             (!exists $options->{trigger})
112                 || confess "Cannot have a trigger on a read-only attribute";
113         }
114         elsif ($options->{is} eq 'rw') {
115             $options->{accessor} = $name;
116             ((reftype($options->{trigger}) || '') eq 'CODE')
117                 || confess "Trigger must be a CODE ref"
118                     if exists $options->{trigger};
119         }
120         else {
121             confess "I do not understand this option (is => " . $options->{is} . ")"
122         }
123     }
124
125     if (exists $options->{isa}) {
126         if (exists $options->{does}) {
127             if (eval { $options->{isa}->can('does') }) {
128                 ($options->{isa}->does($options->{does}))
129                     || confess "Cannot have an isa option and a does option if the isa does not do the does";
130             }
131             else {
132                 confess "Cannot have an isa option which cannot ->does()";
133             }
134         }
135
136         # allow for anon-subtypes here ...
137         if (blessed($options->{isa}) && $options->{isa}->isa('Moose::Meta::TypeConstraint')) {
138             $options->{type_constraint} = $options->{isa};
139         }
140         else {
141             $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_type_constraint(
142                 $options->{isa} => {
143                     parent     => Moose::Util::TypeConstraints::find_type_constraint('Object'),
144                     constraint => sub { $_[0]->isa($options->{isa}) }
145                 }
146             );
147         }
148     }
149     elsif (exists $options->{does}) {
150         # allow for anon-subtypes here ...
151         if (blessed($options->{does}) && $options->{does}->isa('Moose::Meta::TypeConstraint')) {
152                 $options->{type_constraint} = $options->{does};
153         }
154         else {
155             $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_type_constraint(
156                 $options->{does} => {
157                     parent     => Moose::Util::TypeConstraints::find_type_constraint('Role'),
158                     constraint => sub { 
159                         Moose::Util::does_role($_[0], $options->{does})
160                     }
161                 }
162             );
163         }
164     }
165
166     if (exists $options->{coerce} && $options->{coerce}) {
167         (exists $options->{type_constraint})
168             || confess "You cannot have coercion without specifying a type constraint";
169         confess "You cannot have a weak reference to a coerced value"
170             if $options->{weak_ref};
171     }
172
173     if (exists $options->{auto_deref} && $options->{auto_deref}) {
174         (exists $options->{type_constraint})
175             || confess "You cannot auto-dereference without specifying a type constraint";
176         ($options->{type_constraint}->is_a_type_of('ArrayRef') ||
177          $options->{type_constraint}->is_a_type_of('HashRef'))
178             || confess "You cannot auto-dereference anything other than a ArrayRef or HashRef";
179     }
180
181     if (exists $options->{lazy_build} && $options->{lazy_build} == 1) {
182         confess("You can not use lazy_build and default for the same attribute")
183             if exists $options->{default};
184         $options->{lazy}      = 1;
185         $options->{required}  = 1;
186         $options->{builder} ||= "_build_${name}";
187         if ($name =~ /^_/) {
188             $options->{clearer}   ||= "_clear${name}";
189             $options->{predicate} ||= "_has${name}";
190         } 
191         else {
192             $options->{clearer}   ||= "clear_${name}";
193             $options->{predicate} ||= "has_${name}";
194         }
195     }
196
197     if (exists $options->{lazy} && $options->{lazy}) {
198         (exists $options->{default} || exists $options->{builder} )
199             || confess "You cannot have lazy attribute without specifying a default value for it";
200     }
201
202 }
203
204 sub initialize_instance_slot {
205     my ($self, $meta_instance, $instance, $params) = @_;
206     my $init_arg = $self->init_arg();
207     # try to fetch the init arg from the %params ...
208
209     my $val;
210     my $value_is_set;
211     if (exists $params->{$init_arg}) {
212         $val = $params->{$init_arg};
213         $value_is_set = 1;    
214     }
215     else {
216         # skip it if it's lazy
217         return if $self->is_lazy;
218         # and die if it's required and doesn't have a default value
219         confess "Attribute (" . $self->name . ") is required"
220             if $self->is_required && !$self->has_default && !$self->has_builder;
221
222         # if nothing was in the %params, we can use the
223         # attribute's default value (if it has one)
224         if ($self->has_default) {
225             $val = $self->default($instance);
226             $value_is_set = 1;
227         } 
228         elsif ($self->has_builder) {
229             if (my $builder = $instance->can($self->builder)){
230                 $val = $instance->$builder;
231                 $value_is_set = 1;
232             } 
233             else {
234                 confess(blessed($instance)." does not support builder method '".$self->builder."' for attribute '" . $self->name . "'");
235             }
236         }
237     }
238
239     return unless $value_is_set;
240
241     if ($self->has_type_constraint) {
242         my $type_constraint = $self->type_constraint;
243         if ($self->should_coerce && $type_constraint->has_coercion) {
244             $val = $type_constraint->coerce($val);
245         }
246         (defined($type_constraint->check($val)))
247             || confess "Attribute (" .
248                        $self->name .
249                        ") does not pass the type constraint (" .
250                        $type_constraint->name .
251                        ") with '" .
252                        (defined $val
253                            ? overload::StrVal($val)
254                            : 'undef') .
255                        "'";
256     }
257
258     $meta_instance->set_slot_value($instance, $self->name, $val);
259     $meta_instance->weaken_slot_value($instance, $self->name)
260         if ref $val && $self->is_weak_ref;
261 }
262
263 ## Slot management
264
265 sub set_value {
266     my ($self, $instance, $value) = @_;
267
268     my $attr_name = $self->name;
269
270     if ($self->is_required) {
271         defined($value)
272             || confess "Attribute ($attr_name) is required, so cannot be set to undef";
273     }
274
275     if ($self->has_type_constraint) {
276
277         my $type_constraint = $self->type_constraint;
278
279         if ($self->should_coerce) {
280             $value = $type_constraint->coerce($value);
281         }
282         $type_constraint->_compiled_type_constraint->($value)
283                 || confess "Attribute ($attr_name) does not pass the type constraint ("
284                . $type_constraint->name
285                . ") with "
286                . (defined($value)
287                     ? ("'" . overload::StrVal($value) . "'")
288                     : "undef")
289           if defined($value);
290     }
291
292     my $meta_instance = Class::MOP::Class->initialize(blessed($instance))
293                                          ->get_meta_instance;
294
295     $meta_instance->set_slot_value($instance, $attr_name, $value);
296
297     if (ref $value && $self->is_weak_ref) {
298         $meta_instance->weaken_slot_value($instance, $attr_name);
299     }
300
301     if ($self->has_trigger) {
302         $self->trigger->($instance, $value, $self);
303     }
304 }
305
306 sub get_value {
307     my ($self, $instance) = @_;
308
309     if ($self->is_lazy) {
310         unless ($self->has_value($instance)) {
311             if ($self->has_default) {
312                 my $default = $self->default($instance);
313                 $self->set_value($instance, $default);
314             }
315             if ( $self->has_builder ){
316                 if (my $builder = $instance->can($self->builder)){
317                     $self->set_value($instance, $instance->$builder);
318                 } 
319                 else {
320                     confess(blessed($instance) 
321                           . " does not support builder method '"
322                           . $self->builder 
323                           . "' for attribute '" 
324                           . $self->name 
325                           . "'");
326                 }
327             } 
328             else {
329                 $self->set_value($instance, undef);
330             }
331         }
332     }
333
334     if ($self->should_auto_deref) {
335
336         my $type_constraint = $self->type_constraint;
337
338         if ($type_constraint->is_a_type_of('ArrayRef')) {
339             my $rv = $self->SUPER::get_value($instance);
340             return unless defined $rv;
341             return wantarray ? @{ $rv } : $rv;
342         }
343         elsif ($type_constraint->is_a_type_of('HashRef')) {
344             my $rv = $self->SUPER::get_value($instance);
345             return unless defined $rv;
346             return wantarray ? %{ $rv } : $rv;
347         }
348         else {
349             confess "Can not auto de-reference the type constraint '" . $type_constraint->name . "'";
350         }
351
352     }
353     else {
354
355         return $self->SUPER::get_value($instance);
356     }
357 }
358
359 ## installing accessors
360
361 sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
362
363 sub install_accessors {
364     my $self = shift;
365     $self->SUPER::install_accessors(@_);
366
367     if ($self->has_handles) {
368
369         # NOTE:
370         # Here we canonicalize the 'handles' option
371         # this will sort out any details and always
372         # return an hash of methods which we want
373         # to delagate to, see that method for details
374         my %handles = $self->_canonicalize_handles();
375
376         # find the accessor method for this attribute
377         my $accessor = $self->get_read_method_ref;
378         # then unpack it if we need too ...
379         $accessor = $accessor->body if blessed $accessor;
380
381         # install the delegation ...
382         my $associated_class = $self->associated_class;
383         foreach my $handle (keys %handles) {
384             my $method_to_call = $handles{$handle};
385             my $class_name = $associated_class->name;
386             my $name = "${class_name}::${handle}";
387
388             (!$associated_class->has_method($handle))
389                 || confess "You cannot overwrite a locally defined method ($handle) with a delegation";
390
391             # NOTE:
392             # handles is not allowed to delegate
393             # any of these methods, as they will
394             # override the ones in your class, which
395             # is almost certainly not what you want.
396
397             # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
398             #cluck("Not delegating method '$handle' because it is a core method") and
399             next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
400
401             if ((reftype($method_to_call) || '') eq 'CODE') {
402                 $associated_class->add_method($handle => subname $name, $method_to_call);
403             }
404             else {
405                 $associated_class->add_method($handle => subname $name, sub {
406                     my $proxy = (shift)->$accessor();
407                     @_ = ($proxy, @_);
408
409                     defined($proxy)
410                         or confess "Undefined 'handles' for attribute '".$self->name."' for method '$name'.";
411
412                     goto &{ $proxy->can($method_to_call) || return };
413                 });
414             }
415         }
416     }
417
418     return;
419 }
420
421 # private methods to help delegation ...
422
423 sub _canonicalize_handles {
424     my $self    = shift;
425     my $handles = $self->handles;
426     if (my $handle_type = ref($handles)) {
427         if ($handle_type eq 'HASH') {
428             return %{$handles};
429         }
430         elsif ($handle_type eq 'ARRAY') {
431             return map { $_ => $_ } @{$handles};
432         }
433         elsif ($handle_type eq 'Regexp') {
434             ($self->has_type_constraint)
435                 || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
436             return map  { ($_ => $_) }
437                    grep { /$handles/ } $self->_get_delegate_method_list;
438         }
439         elsif ($handle_type eq 'CODE') {
440             return $handles->($self, $self->_find_delegate_metaclass);
441         }
442         else {
443             confess "Unable to canonicalize the 'handles' option with $handles";
444         }
445     }
446     else {
447         my $role_meta = eval { $handles->meta };
448         if ($@) {
449             confess "Unable to canonicalize the 'handles' option with $handles because : $@";
450         }
451
452         (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
453             || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
454
455         return map { $_ => $_ } (
456             $role_meta->get_method_list,
457             $role_meta->get_required_method_list
458         );
459     }
460 }
461
462 sub _find_delegate_metaclass {
463     my $self = shift;
464     if (my $class = $self->_isa_metadata) {
465         # if the class does have
466         # a meta method, use it
467         return $class->meta if $class->can('meta');
468         # otherwise we might be
469         # dealing with a non-Moose
470         # class, and need to make
471         # our own metaclass
472         return Moose::Meta::Class->initialize($class);
473     }
474     elsif (my $role = $self->_does_metadata) {
475         # our role will always have
476         # a meta method
477         return $role->meta;
478     }
479     else {
480         confess "Cannot find delegate metaclass for attribute " . $self->name;
481     }
482 }
483
484 sub _get_delegate_method_list {
485     my $self = shift;
486     my $meta = $self->_find_delegate_metaclass;
487     if ($meta->isa('Class::MOP::Class')) {
488         return map  { $_->{name}                     }  # NOTE: !never! delegate &meta
489                grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' }
490                     $meta->compute_all_applicable_methods;
491     }
492     elsif ($meta->isa('Moose::Meta::Role')) {
493         return $meta->get_method_list;
494     }
495     else {
496         confess "Unable to recognize the delegate metaclass '$meta'";
497     }
498 }
499
500 1;
501
502 __END__
503
504 =pod
505
506 =head1 NAME
507
508 Moose::Meta::Attribute - The Moose attribute metaclass
509
510 =head1 DESCRIPTION
511
512 This is a subclass of L<Class::MOP::Attribute> with Moose specific
513 extensions.
514
515 For the most part, the only time you will ever encounter an
516 instance of this class is if you are doing some serious deep
517 introspection. To really understand this class, you need to refer
518 to the L<Class::MOP::Attribute> documentation.
519
520 =head1 METHODS
521
522 =head2 Overridden methods
523
524 These methods override methods in L<Class::MOP::Attribute> and add
525 Moose specific features. You can safely assume though that they
526 will behave just as L<Class::MOP::Attribute> does.
527
528 =over 4
529
530 =item B<new>
531
532 =item B<initialize_instance_slot>
533
534 =item B<install_accessors>
535
536 =item B<accessor_metaclass>
537
538 =item B<get_value>
539
540 =item B<set_value>
541
542   eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
543   if($@) {
544     print "Oops: $@\n";
545   }
546
547 I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
548
549 Before setting the value, a check is made on the type constraint of
550 the attribute, if it has one, to see if the value passes it. If the
551 value fails to pass, the set operation dies with a L<Carp/confess>.
552
553 Any coercion to convert values is done before checking the type constraint.
554
555 To check a value against a type constraint before setting it, fetch the
556 attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
557 fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
558 and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
559 for an example.
560
561 =back
562
563 =head2 Additional Moose features
564
565 Moose attributes support type-constraint checking, weak reference
566 creation and type coercion.
567
568 =over 4
569
570 =item B<clone_and_inherit_options>
571
572 This is to support the C<has '+foo'> feature, it clones an attribute
573 from a superclass and allows a very specific set of changes to be made
574 to the attribute.
575
576 =item B<has_type_constraint>
577
578 Returns true if this meta-attribute has a type constraint.
579
580 =item B<type_constraint>
581
582 A read-only accessor for this meta-attribute's type constraint. For
583 more information on what you can do with this, see the documentation
584 for L<Moose::Meta::TypeConstraint>.
585
586 =item B<has_handles>
587
588 Returns true if this meta-attribute performs delegation.
589
590 =item B<handles>
591
592 This returns the value which was passed into the handles option.
593
594 =item B<is_weak_ref>
595
596 Returns true if this meta-attribute produces a weak reference.
597
598 =item B<is_required>
599
600 Returns true if this meta-attribute is required to have a value.
601
602 =item B<is_lazy>
603
604 Returns true if this meta-attribute should be initialized lazily.
605
606 NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
607
608 =item B<is_lazy_build>
609
610 Returns true if this meta-attribute should be initialized lazily through
611 the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
612 make your attribute required and lazy. In addition it will set the builder, clearer
613 and predicate options for you using the following convention.
614
615    #If your attribute name starts with an underscore:
616    has '_foo' => (lazy_build => 1);
617    #is the same as
618    has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo);
619    # or
620    has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
621
622    #If your attribute name does not start with an underscore:
623    has 'foo' => (lazy_build => 1);
624    #is the same as
625    has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo);
626    # or
627    has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
628
629 The reason for the different naming of the C<builder> is that the C<builder>
630 method is a private method while the C<clearer> and C<predicate> methods
631 are public methods.
632
633 NOTE: This means your class should provide a method whose name matches the value
634 of the builder part, in this case _build__foo or _build_foo.
635
636 =item B<should_coerce>
637
638 Returns true if this meta-attribute should perform type coercion.
639
640 =item B<should_auto_deref>
641
642 Returns true if this meta-attribute should perform automatic
643 auto-dereferencing.
644
645 NOTE: This can only be done for attributes whose type constraint is
646 either I<ArrayRef> or I<HashRef>.
647
648 =item B<has_trigger>
649
650 Returns true if this meta-attribute has a trigger set.
651
652 =item B<trigger>
653
654 This is a CODE reference which will be executed every time the
655 value of an attribute is assigned. The CODE ref will get two values,
656 the invocant and the new value. This can be used to handle I<basic>
657 bi-directional relations.
658
659 =item B<documentation>
660
661 This is a string which contains the documentation for this attribute.
662 It serves no direct purpose right now, but it might in the future
663 in some kind of automated documentation system perhaps.
664
665 =item B<has_documentation>
666
667 Returns true if this meta-attribute has any documentation.
668
669 =back
670
671 =head1 BUGS
672
673 All complex software has bugs lurking in it, and this module is no
674 exception. If you find a bug please either email me, or add the bug
675 to cpan-RT.
676
677 =head1 AUTHOR
678
679 Stevan Little E<lt>stevan@iinteractive.comE<gt>
680
681 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
682
683 =head1 COPYRIGHT AND LICENSE
684
685 Copyright 2006-2008 by Infinity Interactive, Inc.
686
687 L<http://www.iinteractive.com>
688
689 This library is free software; you can redistribute it and/or modify
690 it under the same terms as Perl itself.
691
692 =cut