OK, so as not to disappoint...
Introducing Acme::Asplode: it lets you drag your caller's lexical variables kicking and screaming into your sub. Ought to work in Perl 5.12+.
package Acme::Asplode;
use 5.012;
use strict;
use warnings;
use Keyword::Simple ();
use PadWalker ();
use Text::Balanced ();
use Carp;
sub import
{
Keyword::Simple::define asplode => sub {
my $ref = shift;
$$ref =~ s/^\s+//;
my $extracted;
if ($$ref =~ /^\(/)
{
$extracted = Text::Balanced::extract_bracketed($$ref)
or croak "usage: asplode (VARIABLES);";
$extracted =~ s/(^\(|\)$)//g;
}
else
{
($extracted, $$ref) = ($$ref =~ /^([^;]+)(;.*)$/s)
or croak "usage: asplode VARIABLES;";
}
(my $globs = $extracted) =~ s/[\$\%\@]/*/g;
$$ref = "our($extracted); local($globs) = Acme::Asplode::_call
+back(q($extracted));$$ref";
}
}
sub unimport
{
Keyword::Simple::undefine asplode => ();
}
sub _callback
{
my $vars = shift;
$vars =~ s/(^\s*|\s*$)//g;
my @vars = split /\s*,\s*/, $vars;
my $MY = PadWalker::peek_my(2);
my $OUR = PadWalker::peek_our(2);
return map {
exists $MY->{$_} ? $MY->{$_} :
exists $OUR->{$_} ? $OUR->{$_} :
croak "asplode($_) failed; caller has no $_ defined";
} @vars;
}
'ASPLODE!';
Example usage...
use 5.012;
use strict;
use warnings;
use Acme::Asplode;
sub bar
{
asplode($x, $y); # steal lexical variables from our caller!
say $x;
say $y;
asplode @A, $z; # steal moar lexicals!!!
say $z;
$z++; # alter our caller's lexical variable!!
say for @A;
};
sub foo
{
my $x = 1;
my $y = 2;
my $z = 3;
my @A = qw(a b c);
bar();
say "Z is changed: $z";
}
foo();
Update: Acme::Asplode, renamed Acme::Lexical::Thief is now on CPAN.
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'