Update: fix private
package ScopeSaver; use strict; use warnings; use Carp; use B::Deparse; =pod $ss_obj = eval ScopeSaver->new(lexical => [qw/$x %y/], global => [qw/$q @r/], private => [qw/$t $u/]); ... # eval code in saved scope $ss_obj->scope_eval(" code "); # rebind closure into saved scope $coderef = $ss_obj->rebind($coderef); Encapsulates the current scope into an object, which can then evaluate code using the saved scope or rebind a closure into it. You can control some aspects of how variables in evalled code interact with the scope with the lexical, global, and private parameters, which each take a ref to an array of simple variable names. To be able to access lexicals in the scope even after their normal scope has ended, list them in the lexical parameter. To have evaled code access globals instead of the lexicals in the scope of the same name, list them in the global parameter. To have evaled code use lexicals private to each eval instead of lexicals in the scope or globals, list them in the private parameter. =cut sub new { my $class = shift; my %vars = @_; my $str = "bless sub {\n"; $str .= "(".join(",",@{$vars{lexical}}).") if 0;\n" if $vars{lexic +al}; $str .= "our (".join(",",@{$vars{global}}).");\n" if $vars{global} +; $str .= "my (".join(",",@{$vars{private}}).");\n" if $vars{private +}; $str .= "eval \$_[0]\n}, \"$class\";\n" } sub scope_eval { my $self = shift; $self->($_[0]); } sub rebind { my $self = shift; UNIVERSAL::isa($_[0], "CODE") or croak "rebind expected coderef"; $self->("sub ".B::Deparse->new->coderef2text($_[0])); } 1;
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Rebinding closures by scope
by ysth (Canon) on Dec 17, 2003 at 19:38 UTC |