Stop relying on stash entries always being upgraded into real GVs.
Florian Ragwitz [Thu, 14 Jan 2010 01:51:59 +0000 (02:51 +0100)]
Makefile.PL
lib/namespace/clean.pm
t/08-const-sub.t [new file with mode: 0644]

index db5a201..cf902bb 100644 (file)
@@ -9,7 +9,7 @@ license         q{perl};
 author          q{Robert 'phaylon'' Sedlacek <rs@474.at>};
 all_from        q{lib/namespace/clean.pm};
 
-build_requires  q{Test::More},                  '0.62';
+build_requires  q{Test::More},                  '0.88';
 build_requires  q{FindBin},                     0;
 
 requires        q{B::Hooks::EndOfScope},        '0.07';
index a23e6e9..76bb92e 100644 (file)
@@ -169,34 +169,44 @@ my $RemoveSubs = sub {
         next SYMBOL if $store->{exclude}{ $f };
         no strict 'refs';
 
-        # convince the Perl debugger to work
-        # it assumes that sub_fullname($sub) can always be used to find the CV again
-        # since we are deleting the glob where the subroutine was originally
-        # defined, that assumption no longer holds, so we need to move it
-        # elsewhere and point the CV's name to the new glob.
-        my $sub = \&$fq;
-        if ( sub_fullname($sub) eq $fq ) {
-            my $new_fq = "namespace::clean::deleted::$fq";
-            subname($new_fq, $sub);
-            *{$new_fq} = $sub;
+        next SYMBOL unless exists ${ "${cleanee}::" }{ $f };
+
+        if (ref(\${ "${cleanee}::" }{ $f }) eq 'GLOB') {
+            # convince the Perl debugger to work
+            # it assumes that sub_fullname($sub) can always be used to find the CV again
+            # since we are deleting the glob where the subroutine was originally
+            # defined, that assumption no longer holds, so we need to move it
+            # elsewhere and point the CV's name to the new glob.
+            my $sub = \&$fq;
+            if ( sub_fullname($sub) eq $fq ) {
+                my $new_fq = "namespace::clean::deleted::$fq";
+                subname($new_fq, $sub);
+                *{$new_fq} = $sub;
+            }
+
+            local *__tmp;
+
+            # keep original value to restore non-code slots
+            {   no warnings 'uninitialized';    # fix possible unimports
+                *__tmp = *{ ${ "${cleanee}::" }{ $f } };
+                delete ${ "${cleanee}::" }{ $f };
+            }
+
+          SLOT:
+            # restore non-code slots to symbol.
+            # omit the FORMAT slot, since perl erroneously puts it into the
+            # SCALAR slot of the new glob.
+            for my $t (qw( SCALAR ARRAY HASH IO )) {
+                next SLOT unless defined *__tmp{ $t };
+                *{ "${cleanee}::$f" } = *__tmp{ $t };
+            }
         }
-
-        local *__tmp;
-
-        # keep original value to restore non-code slots
-        {   no warnings 'uninitialized';    # fix possible unimports
-            *__tmp = *{ ${ "${cleanee}::" }{ $f } };
+        else {
+            # A non-glob in the stash is assumed to stand for some kind
+            # of function.  So far they all do, but the core might change
+            # this some day.  Watch perl5-porters.
             delete ${ "${cleanee}::" }{ $f };
         }
-
-      SLOT:
-        # restore non-code slots to symbol.
-        # omit the FORMAT slot, since perl erroneously puts it into the
-        # SCALAR slot of the new glob.
-        for my $t (qw( SCALAR ARRAY HASH IO )) {
-            next SLOT unless defined *__tmp{ $t };
-            *{ "${cleanee}::$f" } = *__tmp{ $t };
-        }
     }
 };
 
diff --git a/t/08-const-sub.t b/t/08-const-sub.t
new file mode 100644 (file)
index 0000000..1ec65b9
--- /dev/null
@@ -0,0 +1,14 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use constant CONST => 123;
+use namespace::clean;
+
+my $x = CONST;
+is $x, 123;
+
+ok eval("!defined(&CONST)");
+
+done_testing;