JadeNB has asked for the wisdom of the Perl Monks concerning the following question:

  1. Is it possible to inject new code into a subroutine that will execute within the lexical scope of the subroutine body? That is, can I take
    sub { BLAH }
    and convert it (programmatically, not by grovelling around in the original definition) into
    sub { BLAH YOUR CODE HERE }
    Specifically, what I have in mind is taking a subroutine that modifies @_—possibly without modifying its original arguments (say, by splicing entries into the middle)—and applying a user-specified function to the resulting mutated array. (A natural thought is some wrapper like
    sub inject { my ( $outer, $inner ) = @_; return sub { $inner->(@_); goto &$outer; } }
    but that doesn't work, since $outer is executing in a different lexical scope.)

    I know that B::Deparse will handle the simple case of functions that don't close over external variables, and Data::Dump::Streamer will handle more cases, but I'm looking for something really robust.

  2. Is there a subroutine uneval such that eval uneval($a) always returns $a? Even if it's possible to do this just when $a is a simple scalar (i.e., not a reference), then I'm happy—but I'd like to preserve any ‘magic’ associated to $a (for example, not lose its numeric value by just stringifying). If one could control the lexical scope in which eval'd strings executed, then this would be easy:
    sub uneval { my ( $a ) = @_; return ( in_current_scope => '$a' ); }
    but I'm not sure how to do it otherwise.

UPDATE: I forgot to mention that I wanted to do the unevaling with lexicals, not globals. It's easy with globals:

our @cache; my $id = 0; sub uneval { $cache[$id++] = $_[0]; return __PACKAGE__ . '::$cache[' . $id . ']'; }

Replies are listed 'Best First'.
Re: Modifying subroutines and un-eval-ing
by Fletch (Bishop) on Aug 06, 2009 at 17:02 UTC

    You might look into what Hook::LexWrap does to get its evil magic to work.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Actually, it looks to me like Hook::LexWrap might already do exactly what I want (which, of course, doesn't preclude my studying its evil ways source). The documentation is a little sparse about the scope in which the wrappers are executed, but the examples make it look like I might just pass my
      sub { BLAH }
      as a pre-wrapper to get the desired effect. Thanks so much!

      UPDATE: I've had a look at the source, and it seems that most of Hook::LexWrap's magic consists in fooling caller and installing subs in-place (a la memoize), not doing anything with lexical scope. My thoughts should probably have leapt immediately to PadWalker, though I'm not familiar enough with it to know if it'll do what I want. Binding is so so close, but it allows one to peek at bindings “the wrong way” for what I need.

Re: Modifying subroutines and un-eval-ing
by Anonymous Monk on Aug 06, 2009 at 15:21 UTC
    It is probably possible with B::, you should aske on perl5-porters.