better diagnostics for get_symbol issues on bare anon stashes
Jesse Luehrs [Tue, 29 Nov 2011 20:07:30 +0000 (14:07 -0600)]
lib/Package/Stash/PP.pm
t/edge-cases.t

index 4996c39..8d95840 100644 (file)
@@ -88,6 +88,10 @@ sub namespace {
     }
 }
 
+sub _is_anon {
+    return !defined $_[0]->{package};
+}
+
 {
     my %SIGIL_MAP = (
         '$' => 'SCALAR',
@@ -270,19 +274,25 @@ sub get_symbol {
     }
     else {
         if ($type eq 'CODE') {
+            if (BROKEN_GLOB_ASSIGNMENT || !$self->_is_anon) {
+                no strict 'refs';
+                return \&{ $self->name . '::' . $name };
+            }
+
             # XXX we should really be able to support arbitrary anonymous
             # stashes here... (not just via Package::Anon)
-            if (!BROKEN_GLOB_ASSIGNMENT
-                && blessed($namespace)
-                && $namespace->isa('Package::Anon')) {
-                # ->can will call gv_init for us
+            if (blessed($namespace) && $namespace->isa('Package::Anon')) {
+                # ->can will call gv_init for us, which inflates the glob
+                # don't know how to do this in general
                 $namespace->bless(\(my $foo))->can($name);
-                return *{ $namespace->{$name} }{CODE};
             }
             else {
-                no strict 'refs';
-                return \&{ $self->name . '::' . $name };
+                confess "Don't know how to inflate a " . ref($entry_ref)
+                      . " into a full coderef (perhaps you could use"
+                      . " Package::Anon instead of a bare stash?)"
             }
+
+            return *{ $namespace->{$name} }{CODE};
         }
         else {
             return undef;
index 04e2164..b1e5bb8 100755 (executable)
@@ -53,4 +53,30 @@ is(ref($constant), 'CODE', "expanded a constant into a coderef");
 is(ref($stash->get_symbol('$glob')), '', "nothing yet");
 is(ref($stash->get_or_add_symbol('$glob')), 'SCALAR', "got an empty scalar");
 
+SKIP: {
+    skip "PP doesn't support anon stashes before 5.14", 4
+        if $Package::Stash::IMPLEMENTATION eq 'PP'
+        && Package::Stash::BROKEN_GLOB_ASSIGNMENT;
+    local $TODO = "don't know how to properly inflate a stash entry";
+
+    my $anon = {}; # not using Package::Anon
+    $anon->{foo} = -1;     # stub
+    $anon->{bar} = '$&';   # stub with prototype
+    $anon->{baz} = \"foo"; # constant
+
+    my $stash = Package::Stash->new($anon);
+    is(
+        exception {
+            is(ref($stash->get_symbol('&foo')), 'CODE',
+               "stub expanded into a glob");
+            is(ref($stash->get_symbol('&bar')), 'CODE',
+               "stub with prototype expanded into a glob");
+            is(ref($stash->get_symbol('&baz')), 'CODE',
+               "constant expanded into a glob");
+        },
+        undef,
+        "can call get_symbol on weird stash entries"
+    );
+}
+
 done_testing;