Failing tests for custom type error messages. Now let's see about making them pass..
[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.18';
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                     (defined $proxy) 
409                         || confess "Cannot delegate $handle to $method_to_call because " . 
410                                    "the value of " . $self->name . " is not defined";
411                     goto &{ $proxy->can($method_to_call) || return };
412                 });
413             }
414         }
415     }
416
417     return;
418 }
419
420 # private methods to help delegation ...
421
422 sub _canonicalize_handles {
423     my $self    = shift;
424     my $handles = $self->handles;
425     if (my $handle_type = ref($handles)) {
426         if ($handle_type eq 'HASH') {
427             return %{$handles};
428         }
429         elsif ($handle_type eq 'ARRAY') {
430             return map { $_ => $_ } @{$handles};
431         }
432         elsif ($handle_type eq 'Regexp') {
433             ($self->has_type_constraint)
434                 || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
435             return map  { ($_ => $_) }
436                    grep { /$handles/ } $self->_get_delegate_method_list;
437         }
438         elsif ($handle_type eq 'CODE') {
439             return $handles->($self, $self->_find_delegate_metaclass);
440         }
441         else {
442             confess "Unable to canonicalize the 'handles' option with $handles";
443         }
444     }
445     else {
446         my $role_meta = eval { $handles->meta };
447         if ($@) {
448             confess "Unable to canonicalize the 'handles' option with $handles because : $@";
449         }
450
451         (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
452             || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
453
454         return map { $_ => $_ } (
455             $role_meta->get_method_list,
456             $role_meta->get_required_method_list
457         );
458     }
459 }
460
461 sub _find_delegate_metaclass {
462     my $self = shift;
463     if (my $class = $self->_isa_metadata) {
464         # if the class does have
465         # a meta method, use it
466         return $class->meta if $class->can('meta');
467         # otherwise we might be
468         # dealing with a non-Moose
469         # class, and need to make
470         # our own metaclass
471         return Moose::Meta::Class->initialize($class);
472     }
473     elsif (my $role = $self->_does_metadata) {
474         # our role will always have
475         # a meta method
476         return $role->meta;
477     }
478     else {
479         confess "Cannot find delegate metaclass for attribute " . $self->name;
480     }
481 }
482
483 sub _get_delegate_method_list {
484     my $self = shift;
485     my $meta = $self->_find_delegate_metaclass;
486     if ($meta->isa('Class::MOP::Class')) {
487         return map  { $_->{name}                     }  # NOTE: !never! delegate &meta
488                grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' }
489                     $meta->compute_all_applicable_methods;
490     }
491     elsif ($meta->isa('Moose::Meta::Role')) {
492         return $meta->get_method_list;
493     }
494     else {
495         confess "Unable to recognize the delegate metaclass '$meta'";
496     }
497 }
498
499 1;
500
501 __END__
502
503 =pod
504
505 =head1 NAME
506
507 Moose::Meta::Attribute - The Moose attribute metaclass
508
509 =head1 DESCRIPTION
510
511 This is a subclass of L<Class::MOP::Attribute> with Moose specific
512 extensions.
513
514 For the most part, the only time you will ever encounter an
515 instance of this class is if you are doing some serious deep
516 introspection. To really understand this class, you need to refer
517 to the L<Class::MOP::Attribute> documentation.
518
519 =head1 METHODS
520
521 =head2 Overridden methods
522
523 These methods override methods in L<Class::MOP::Attribute> and add
524 Moose specific features. You can safely assume though that they
525 will behave just as L<Class::MOP::Attribute> does.
526
527 =over 4
528
529 =item B<new>
530
531 =item B<initialize_instance_slot>
532
533 =item B<install_accessors>
534
535 =item B<accessor_metaclass>
536
537 =item B<get_value>
538
539 =item B<set_value>
540
541   eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
542   if($@) {
543     print "Oops: $@\n";
544   }
545
546 I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
547
548 Before setting the value, a check is made on the type constraint of
549 the attribute, if it has one, to see if the value passes it. If the
550 value fails to pass, the set operation dies with a L<Carp/confess>.
551
552 Any coercion to convert values is done before checking the type constraint.
553
554 To check a value against a type constraint before setting it, fetch the
555 attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
556 fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
557 and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
558 for an example.
559
560 =back
561
562 =head2 Additional Moose features
563
564 Moose attributes support type-constraint checking, weak reference
565 creation and type coercion.
566
567 =over 4
568
569 =item B<clone_and_inherit_options>
570
571 This is to support the C<has '+foo'> feature, it clones an attribute
572 from a superclass and allows a very specific set of changes to be made
573 to the attribute.
574
575 =item B<has_type_constraint>
576
577 Returns true if this meta-attribute has a type constraint.
578
579 =item B<type_constraint>
580
581 A read-only accessor for this meta-attribute's type constraint. For
582 more information on what you can do with this, see the documentation
583 for L<Moose::Meta::TypeConstraint>.
584
585 =item B<has_handles>
586
587 Returns true if this meta-attribute performs delegation.
588
589 =item B<handles>
590
591 This returns the value which was passed into the handles option.
592
593 =item B<is_weak_ref>
594
595 Returns true if this meta-attribute produces a weak reference.
596
597 =item B<is_required>
598
599 Returns true if this meta-attribute is required to have a value.
600
601 =item B<is_lazy>
602
603 Returns true if this meta-attribute should be initialized lazily.
604
605 NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
606
607 =item B<is_lazy_build>
608
609 Returns true if this meta-attribute should be initialized lazily through
610 the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
611 make your attribute required and lazy. In addition it will set the builder, clearer
612 and predicate options for you using the following convention.
613
614    #If your attribute name starts with an underscore:
615    has '_foo' => (lazy_build => 1);
616    #is the same as
617    has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo);
618    # or
619    has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
620
621    #If your attribute name does not start with an underscore:
622    has 'foo' => (lazy_build => 1);
623    #is the same as
624    has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo);
625    # or
626    has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
627
628 The reason for the different naming of the C<builder> is that the C<builder>
629 method is a private method while the C<clearer> and C<predicate> methods
630 are public methods.
631
632 NOTE: This means your class should provide a method whose name matches the value
633 of the builder part, in this case _build__foo or _build_foo.
634
635 =item B<should_coerce>
636
637 Returns true if this meta-attribute should perform type coercion.
638
639 =item B<should_auto_deref>
640
641 Returns true if this meta-attribute should perform automatic
642 auto-dereferencing.
643
644 NOTE: This can only be done for attributes whose type constraint is
645 either I<ArrayRef> or I<HashRef>.
646
647 =item B<has_trigger>
648
649 Returns true if this meta-attribute has a trigger set.
650
651 =item B<trigger>
652
653 This is a CODE reference which will be executed every time the
654 value of an attribute is assigned. The CODE ref will get two values,
655 the invocant and the new value. This can be used to handle I<basic>
656 bi-directional relations.
657
658 =item B<documentation>
659
660 This is a string which contains the documentation for this attribute.
661 It serves no direct purpose right now, but it might in the future
662 in some kind of automated documentation system perhaps.
663
664 =item B<has_documentation>
665
666 Returns true if this meta-attribute has any documentation.
667
668 =back
669
670 =head1 BUGS
671
672 All complex software has bugs lurking in it, and this module is no
673 exception. If you find a bug please either email me, or add the bug
674 to cpan-RT.
675
676 =head1 AUTHOR
677
678 Stevan Little E<lt>stevan@iinteractive.comE<gt>
679
680 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
681
682 =head1 COPYRIGHT AND LICENSE
683
684 Copyright 2006-2008 by Infinity Interactive, Inc.
685
686 L<http://www.iinteractive.com>
687
688 This library is free software; you can redistribute it and/or modify
689 it under the same terms as Perl itself.
690
691 =cut