bump version to 0.62
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
index f16d2f7..28e9ad3 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Scalar::Util 'blessed', 'weaken';
 use overload     ();
 
-our $VERSION   = '0.57';
+our $VERSION   = '0.62';
 our $AUTHORITY = 'cpan:STEVAN';
 
 use Moose::Meta::Method::Accessor;
@@ -61,7 +61,7 @@ sub does {
         Moose::Util::resolve_metatrait_alias(Attribute => $role_name)
     };
     return 0 if !defined($name); # failed to load class
-    return Moose::Object::does($self, $name);
+    return $self->Moose::Object::does($name);
 }
 
 sub throw_error {
@@ -70,7 +70,8 @@ sub throw_error {
     unshift @_, "message" if @_ % 2 == 1;
     unshift @_, attr => $self if ref $self;
     unshift @_, $class;
-    goto $class->can("throw_error"); # to avoid incrementing depth by 1
+    my $handler = $class->can("throw_error"); # to avoid incrementing depth by 1
+    goto $handler;
 }
 
 sub new {
@@ -522,7 +523,7 @@ sub get_value {
                 $value = $type_constraint->coerce($value)
                     if ($self->should_coerce);
                 $type_constraint->check($value) 
-                  || c$self->throw_error("Attribute (" . $self->name
+                  || $self->throw_error("Attribute (" . $self->name
                       . ") does not pass the type constraint because: "
                       . $type_constraint->get_message($value), type_constraint => $type_constraint, data => $value);
             }
@@ -566,6 +567,13 @@ sub install_accessors {
     return;
 }
 
+sub remove_accessors {
+    my $self = shift;
+    $self->SUPER::remove_accessors(@_);
+    $self->remove_delegation if $self->has_handles;
+    return;
+}
+
 sub install_delegation {
     my $self = shift;
 
@@ -576,8 +584,6 @@ sub install_delegation {
     # to delagate to, see that method for details
     my %handles = $self->_canonicalize_handles;
 
-    # find the accessor method for this attribute
-    my $accessor = $self->_get_delegate_accessor;
 
     # install the delegation ...
     my $associated_class = $self->associated_class;
@@ -599,24 +605,23 @@ sub install_delegation {
         #cluck("Not delegating method '$handle' because it is a core method") and
         next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
 
-        my $method = $self->_make_delegation_method($accessor, $handle, $method_to_call);
+        my $method = $self->_make_delegation_method($handle, $method_to_call);
 
         $self->associated_class->add_method($method->name, $method);
     }    
 }
 
-# private methods to help delegation ...
-
-sub _get_delegate_accessor {
+sub remove_delegation {
     my $self = shift;
-    # find the accessor method for this attribute
-    my $accessor = $self->get_read_method_ref;
-    # then unpack it if we need too ...
-    $accessor = $accessor->body if blessed $accessor;    
-    # return the accessor
-    return $accessor;
+    my %handles = $self->_canonicalize_handles;
+    my $associated_class = $self->associated_class;
+    foreach my $handle (keys %handles) {
+        $self->associated_class->remove_method($handle);
+    }
 }
 
+# private methods to help delegation ...
+
 sub _canonicalize_handles {
     my $self    = shift;
     my $handles = $self->handles;
@@ -641,6 +646,9 @@ sub _canonicalize_handles {
         }
     }
     else {
+        Class::MOP::load_class($handles) 
+            unless Class::MOP::is_class_loaded($handles);
+            
         my $role_meta = eval { $handles->meta };
         if ($@) {
             $self->throw_error("Unable to canonicalize the 'handles' option with $handles because : $@", data => $handles, error => $@);
@@ -648,7 +656,7 @@ sub _canonicalize_handles {
 
         (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
             || $self->throw_error("Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role", data => $handles);
-
+            
         return map { $_ => $_ } (
             $role_meta->get_method_list,
             $role_meta->get_required_method_list
@@ -695,44 +703,18 @@ sub _get_delegate_method_list {
 }
 
 sub _make_delegation_method {
-    my ( $self, $accessor, $handle_name, $method_to_call ) = @_;
+    my ( $self, $handle_name, $method_to_call ) = @_;
 
     my $method_body;
 
-    if ( 'CODE' eq ref($method_to_call) ) {
-        $method_body = $method_to_call;
-    }
-    else {
-
-        # NOTE:
-        # we used to do a goto here, but the
-        # goto didn't handle failure correctly
-        # (it just returned nothing), so I took
-        # that out. However, the more I thought
-        # about it, the less I liked it doing
-        # the goto, and I prefered the act of
-        # delegation being actually represented
-        # in the stack trace.
-        # - SL
-        $method_body = sub {
-            my $instance = shift;
-            my $proxy    = $instance->$accessor();
-            ( defined $proxy )
-                || $self->throw_error(
-                "Cannot delegate $handle_name to $method_to_call because "
-                    . "the value of "
-                    . $self->name
-                    . " is not defined", method_name => $method_to_call,
-                object => $instance );
-            $proxy->$method_to_call(@_);
-        };
-    }
+    $method_body = $method_to_call
+        if 'CODE' eq ref($method_to_call);
 
     return Moose::Meta::Method::Delegation->new(
-        name         => $handle_name,
-        package_name => $self->associated_class->name,
-        attribute    => $self,
-        body         => $method_body,
+        name               => $handle_name,
+        package_name       => $self->associated_class->name,
+        attribute          => $self,
+        delegate_to_method => $method_to_call,
     );
 }
 
@@ -779,8 +761,12 @@ will behave just as L<Class::MOP::Attribute> does.
 
 =item B<install_accessors>
 
+=item B<remove_accessors>
+
 =item B<install_delegation>
 
+=item B<remove_delegation>
+
 =item B<accessor_metaclass>
 
 =item B<get_value>