work around $DB::sub
Yuval Kogman [Wed, 23 Sep 2009 15:20:31 +0000 (18:20 +0300)]
The variable is a string which is dereferenced as a sub that no longer
exists.

When we delete the glob where the sub was defined, we therefore alias it
to "namespace::clean::deleted::$fq" so that the debugger can still
dereference a symbolic ref and get back a working subroutine

Makefile.PL
lib/namespace/clean.pm
t/07-debugger.t [new file with mode: 0644]

index 703dbc4..db5a201 100644 (file)
@@ -14,6 +14,8 @@ build_requires  q{FindBin},                     0;
 
 requires        q{B::Hooks::EndOfScope},        '0.07';
 requires        q{Symbol},                      0;
+requires        q{Sub::Name},                   '0.04';
+requires        q{Sub::Identify},               '0.04';
 
 auto_provides;
 auto_install;
index 1f370fe..a23e6e9 100644 (file)
@@ -10,8 +10,10 @@ use warnings;
 use strict;
 
 use vars        qw( $VERSION $STORAGE_VAR $SCOPE_HOOK_KEY $SCOPE_EXPLICIT );
-use Symbol      qw( qualify_to_ref );
+use Symbol      qw( qualify_to_ref gensym );
 use B::Hooks::EndOfScope;
+use Sub::Identify qw(sub_fullname);
+use Sub::Name qw(subname);
 
 =head1 VERSION
 
@@ -161,11 +163,24 @@ my $RemoveSubs = sub {
     my $store   = shift;
   SYMBOL:
     for my $f (@_) {
+        my $fq = "${cleanee}::$f";
 
         # ignore already removed symbols
         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;
+        }
+
         local *__tmp;
 
         # keep original value to restore non-code slots
diff --git a/t/07-debugger.t b/t/07-debugger.t
new file mode 100644 (file)
index 0000000..fd4ee87
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/perl -d
+
+BEGIN {
+    push @DB::typeahead, "c", "q";
+
+    # try to shut it up at least a little bit
+    open my $out, ">", \my $out_buf;
+    $DB::OUT = $out;
+    open my $in, "<", \my $in_buf;
+    $DB::IN = $in;
+}
+
+{
+    package Foo;
+
+    BEGIN { *baz = sub { 42 } }
+    sub foo { 22 }
+
+    use namespace::clean;
+
+    sub bar {
+        ::is(baz(), 42);
+        ::is(foo(), 22);
+    }
+}
+
+use Test::More tests => 5;
+
+ok( !Foo->can("foo"), "foo cleaned up" );
+ok( !Foo->can("baz"), "baz cleaned up" );
+
+Foo->bar();
+
+pass();