adding lazy and handles to the has +foo form
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
index a0d2469..c1613da 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Scalar::Util 'blessed', 'weaken', 'reftype';
 use Carp         'confess';
 
-our $VERSION   = '0.10';
+our $VERSION   = '0.11';
 our $AUTHORITY = 'cpan:STEVAN';
 
 use Moose::Meta::Method::Accessor;
@@ -52,14 +52,23 @@ sub new {
 
 sub clone_and_inherit_options {
     my ($self, %options) = @_;
-    # you can change default, required, coerce and documentation 
+    # you can change default, required, coerce, documentation and lazy
     my %actual_options;
-    foreach my $legal_option (qw(default coerce required documentation)) {
+    foreach my $legal_option (qw(default coerce required documentation lazy)) {
         if (exists $options{$legal_option}) {
             $actual_options{$legal_option} = $options{$legal_option};
             delete $options{$legal_option};
         }
     }
+    
+    # handles can only be added, not changed
+    if ($options{handles}) {
+        confess "You can only add the 'handles' option, you cannot change it"
+            if $self->has_handles;
+        $actual_options{handles} = $options{handles};
+        delete $options{handles};
+    }
+    
     # isa can be changed, but only if the 
     # new type is a subtype    
     if ($options{isa}) {
@@ -93,7 +102,7 @@ sub _process_options {
     
        if (exists $options->{is}) {
                if ($options->{is} eq 'ro') {
-                       $options->{reader} = $name;
+                       $options->{reader} ||= $name;
                        (!exists $options->{trigger})
                            || confess "Cannot have a trigger on a read-only attribute";
                }
@@ -212,6 +221,7 @@ sub initialize_instance_slot {
     if (!defined $val && $self->has_default) {
         $val = $self->default($instance); 
     }
+    
        if (defined $val) {
            if ($self->has_type_constraint) {
                my $type_constraint = $self->type_constraint;
@@ -361,7 +371,9 @@ sub install_accessors {
                     # we should check for lack of 
                     # a callable return value from 
                     # the accessor here 
-                    ((shift)->$accessor_name())->$method_to_call(@_);
+                    my $proxy = (shift)->$accessor_name();
+                    @_ = ($proxy, @_);
+                    goto &{ $proxy->can($method_to_call)};
                 });
             }
         }
@@ -375,23 +387,39 @@ sub install_accessors {
 sub _canonicalize_handles {
     my $self    = shift;
     my $handles = $self->handles;
-    if (ref($handles) eq 'HASH') {
-        return %{$handles};
-    }
-    elsif (ref($handles) eq 'ARRAY') {
-        return map { $_ => $_ } @{$handles};
-    }
-    elsif (ref($handles) eq 'Regexp') {
-        ($self->has_type_constraint)
-            || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
-        return map  { ($_ => $_) } 
-               grep { /$handles/ } $self->_get_delegate_method_list;
-    }
-    elsif (ref($handles) eq 'CODE') {
-        return $handles->($self, $self->_find_delegate_metaclass);
+    if (my $handle_type = ref($handles)) {
+        if ($handle_type eq 'HASH') {
+            return %{$handles};
+        }
+        elsif ($handle_type eq 'ARRAY') {
+            return map { $_ => $_ } @{$handles};
+        }
+        elsif ($handle_type eq 'Regexp') {
+            ($self->has_type_constraint)
+                || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
+            return map  { ($_ => $_) } 
+                   grep { /$handles/ } $self->_get_delegate_method_list;
+        }
+        elsif ($handle_type eq 'CODE') {
+            return $handles->($self, $self->_find_delegate_metaclass);
+        }
+        else {
+            confess "Unable to canonicalize the 'handles' option with $handles";
+        }
     }
     else {
-        confess "Unable to canonicalize the 'handles' option with $handles";
+        my $role_meta = eval { $handles->meta };
+        if ($@) {
+            confess "Unable to canonicalize the 'handles' option with $handles because : $@";            
+        }
+
+        (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
+            || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
+        
+        return map { $_ => $_ } (
+            $role_meta->get_method_list, 
+            $role_meta->get_required_method_list
+        );
     }
 }