refactoring no-get_method_map with package symmbol APIs
gfx [Fri, 10 Jul 2009 06:31:49 +0000 (15:31 +0900)]
lib/Class/MOP/Class.pm
lib/Class/MOP/Package.pm
t/003_methods.t
t/010_self_introspection.t
t/081_meta_package_extension.t

index 90df86a..f5ca01a 100644 (file)
@@ -719,12 +719,20 @@ sub alias_method {
     shift->add_method(@_);
 }
 
+sub _code_is_mine{
+    my($self, $code) = @_;
+    my($code_package, $code_name) = Class::MOP::get_code_info($code);
+    return  $code_package
+        &&  $code_package eq $self->name
+        || ($code_package eq 'constant' && $code_name eq '__ANON__');
+}
+
 sub has_method {
     my ($self, $method_name) = @_;
     (defined $method_name && $method_name)
         || confess "You must define a method name";
 
-    defined $self->get_method($method_name);
+    return defined($self->get_method($method_name));
 }
 
 sub get_method {
@@ -732,83 +740,29 @@ sub get_method {
     (defined $method_name && $method_name)
         || confess "You must define a method name";
 
-    my $class_name = $self->name;
-    my $method_map = $self->_method_map;
-
+    my $method_map    = $self->_method_map;
     my $method_object = $method_map->{$method_name};
 
-    if(!$method_object){
-        my $glob = $self->namespace->{$method_name};
+    if(!($method_object && $method_object->_is_valid_generation)){
+        my $code = $self->get_package_symbol({
+            name  => $method_name,
+            sigil => '&',
+            type  => 'CODE',
+        });
 
-        if(!defined $glob){
+        if(!($code && $self->_code_is_mine($code))){
+            delete $method_map->{$method_name};
             return undef;
         }
-
-        my $code;
-        if(ref(\$glob) eq 'GLOB'){
-            $code = *{$glob}{CODE};
-            if(!defined $code){
-                return undef;
-            }
-            my($code_package, $code_name) = Class::MOP::get_code_info($code);
-
-            if(!$code_package
-                    || ( !($code_package eq 'constant' && $code_name eq '__ANON__')
-                            && $code_package ne $class_name ) ){
-                return undef;
-            }
-        }
-        else{ # stubs or constants
-            no strict 'refs';
-            $code = \&{$class_name . '::' . $method_name};
-        }
-        $method_object = $method_map->{$method_name} = $self->wrap_method_body(
-            body                 => $code,
-            name                 => $method_name,
-            associated_metaclass => $self,
-       );
+        if(!($method_object && $method_object->body == $code)){
+           $method_object = $method_map->{$method_name} = $self->wrap_method_body(
+               body                 => $code,
+               name                 => $method_name,
+               associated_metaclass => $self,
+           );
+       }
        $method_object->_update_generation();
     }
-    else{ # $method_object already exists
-        if(!$method_object->_is_valid_generation){
-            my $glob = $self->namespace->{$method_name};
-            if(!defined $glob){
-                delete $method_map->{$method_name};
-                return undef;
-            }
-
-            my $code;
-            if(ref(\$glob) eq 'GLOB'){
-                $code = *{$glob}{CODE};
-                if(!defined($code)){
-                    delete $method_map->{$method_name};
-                    return undef;
-                }
-            }
-            else{ # stubs or constants
-                no strict 'refs';
-                $code = \&{$class_name . '::' . $method_name};
-            }
-
-            if($method_object->body != $code){ # changed for some reason
-                 my($code_package, $code_name) = Class::MOP::get_code_info($code);
-                 if(!$code_package
-                         || ( !($code_package eq 'constant' && $code_name eq '__ANON__')
-                                 && $code_package ne $class_name ) ){
-                     delete $method_map->{$method_name};
-                     return undef;
-                 }
-
-                 # update $method_map
-                 $method_object = $method_map->{$method_name} = $self->wrap_method_body(
-                     body                 => $code,
-                     name                 => $method_name,
-                     associated_metaclass => $self,
-                );
-            }
-            $method_object->_update_generation();
-        }
-    }
 
     return $method_object;
 }
index 0336a57..e5ed66f 100644 (file)
@@ -155,24 +155,19 @@ sub has_package_symbol {
     
     return 0 unless exists $namespace->{$name};   
     
-    # FIXME:
-    # For some really stupid reason 
-    # a typeglob will have a default
-    # value of \undef in the SCALAR 
-    # slot, so we need to work around
-    # this. Which of course means that 
-    # if you put \undef in your scalar
-    # then this is broken.
-
-    if (ref($namespace->{$name}) eq 'SCALAR') {
-        return ($type eq 'CODE');
-    }
-    elsif ($type eq 'SCALAR') {    
-        my $val = *{$namespace->{$name}}{$type};
-        return defined(${$val});
-    }
-    else {
-        defined(*{$namespace->{$name}}{$type});
+    my $entry_ref = \$namespace->{$name};
+    if (ref($entry_ref) eq 'GLOB') {
+        if ($type eq 'SCALAR') {
+            return defined(${ *{$entry_ref}{SCALAR} });
+        }
+        else {
+            return defined(*{$entry_ref}{$type});
+        }
+     }
+     else {
+         # a symbol table entry can be -1 (stub), string (stub with prototype),
+         # or reference (constant)
+         return $type eq 'CODE';
     }
 }
 
@@ -185,21 +180,24 @@ sub get_package_symbol {
 
     my $namespace = $self->namespace;
 
+    # FIXME
     $self->add_package_symbol($variable)
         unless exists $namespace->{$name};
 
-    if (ref($namespace->{$name}) eq 'SCALAR') {
-        if ($type eq 'CODE') {
+    my $entry_ref = \$namespace->{$name};
+
+    if (ref($entry_ref) eq 'GLOB') {
+        return *{$entry_ref}{$type};
+    }
+    else{
+        if($type eq 'CODE'){
             no strict 'refs';
-            return \&{$self->name.'::'.$name};
+            return \&{$self->name . '::' . $name};
         }
-        else {
+        else{
             return undef;
         }
     }
-    else {
-        return *{$namespace->{$name}}{$type};
-    }
 }
 
 sub remove_package_symbol {
index a176441..a6ba53a 100644 (file)
@@ -288,7 +288,8 @@ my $new_method = Bar->meta->get_method('objecty');
 isnt( $method, $new_method,
     'add_method clones method objects as they are added' );
 is( $new_method->original_method, $method,
-    '... the cloned method has the correct original method' );
+    '... the cloned method has the correct original method' )
+        or diag $new_method->dump;
 
 {
     package CustomAccessor;
index dcac510..04504f4 100644 (file)
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 298;
+use Test::More tests => 300;
 use Test::Exception;
 
 use Class::MOP;
@@ -76,6 +76,7 @@ my @class_mop_class_methods = qw(
     linearized_isa _superclasses_updated
 
     _method_map
+    _code_is_mine
     has_method get_method add_method remove_method alias_method wrap_method_body
     get_method_list get_method_map get_all_method_names get_all_methods compute_all_applicable_methods
         find_method_by_name find_all_methods_by_name find_next_method_by_name
index 84ad5be..8ede745 100644 (file)
@@ -32,7 +32,7 @@ BEGIN {use Class::MOP;
     
         my $glob = gensym();
         *{$glob} = $initial_value if defined $initial_value;
-        $self->namespace->{$name} = $glob;    
+        $self->namespace->{$name} = *{$glob};    
     }       
 }