summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToby Inkster <mail@tobyinkster.co.uk>2013-07-30 09:12:20 +0100
committerJesse Luehrs <doy@tozt.net>2013-07-30 15:44:47 -0400
commite30e904a59a0a48b43af7e4200d5784445938e51 (patch)
treebca3da3446ae2ee12636d927265f58693e6d8aff
parenta52d611f30176d32061d5f9386589f2404957d67 (diff)
downloadeval-closure-e30e904a59a0a48b43af7e4200d5784445938e51.tar.gz
eval-closure-e30e904a59a0a48b43af7e4200d5784445938e51.zip
make lexalias behaviour optional
-rw-r--r--dist.ini2
-rw-r--r--lib/Eval/Closure.pm44
-rw-r--r--t/close-over-nonref.t1
3 files changed, 35 insertions, 12 deletions
diff --git a/dist.ini b/dist.ini
index 0c17480..ba39718 100644
--- a/dist.ini
+++ b/dist.ini
@@ -13,8 +13,10 @@ bugtracker_mailto =
[AutoPrereqs]
skip = ^Perl::Tidy$
skip = ^perl$
+skip = ^Devel::LexAlias$
[Prereqs / RuntimeRecommends]
Perl::Tidy = 0
+Devel::LexAlias = 0.05
[ContributorsFromGit]
diff --git a/lib/Eval/Closure.pm b/lib/Eval/Closure.pm
index cd6a030..cc2602d 100644
--- a/lib/Eval/Closure.pm
+++ b/lib/Eval/Closure.pm
@@ -8,7 +8,6 @@ use Exporter 'import';
use Carp;
use overload ();
-use Devel::LexAlias ();
use Scalar::Util qw(reftype);
use Try::Tiny;
@@ -76,6 +75,15 @@ sigil of C<&>. This will create a lexical sub in the evaluated code (see
L<feature/The 'lexical_subs' feature>). Using a C<&> sigil on perl versions
before lexical subs were available will throw an error.
+=item alias
+
+If set to true, the coderef returned closes over the variables referenced in
+the environment hashref. (This feature requires L<Devel::LexAlias>.) If set to
+false, the ccoderef closes over a I<< shallow copy >> of the variables.
+
+If this argument is omitted, Eval::Closure will currently assume false, but
+this assumption may change in a future version.
+
=item description
This lets you provide a bit more information in backtraces. Normally, when a
@@ -104,6 +112,9 @@ behavior so you get only the compilation error that Perl actually reported.
sub eval_closure {
my (%args) = @_;
+ # default to copying environment
+ $args{alias} = 0 if !exists $args{alias};
+
$args{source} = _canonicalize_source($args{source});
_validate_env($args{environment} ||= {});
@@ -111,7 +122,7 @@ sub eval_closure {
. $args{source}
if defined $args{description} && !($^P & 0x10);
- my ($code, $e) = _clean_eval_closure(@args{qw(source environment)});
+ my ($code, $e) = _clean_eval_closure(@args{qw(source environment alias)});
if (!$code) {
if ($args{terse_error}) {
@@ -180,15 +191,15 @@ sub _line_directive {
}
sub _clean_eval_closure {
- my ($source, $captures) = @_;
+ my ($source, $captures, $alias) = @_;
my @capture_keys = sort keys %$captures;
if ($ENV{EVAL_CLOSURE_PRINT_SOURCE}) {
- _dump_source(_make_compiler_source($source, @capture_keys));
+ _dump_source(_make_compiler_source($source, $alias, @capture_keys));
}
- my ($compiler, $e) = _make_compiler($source, @capture_keys);
+ my ($compiler, $e) = _make_compiler($source, $alias, @capture_keys);
my $code;
if (defined $compiler) {
$code = $compiler->(@$captures{@capture_keys});
@@ -200,8 +211,12 @@ sub _clean_eval_closure {
undef $code;
}
- Devel::LexAlias::lexalias($code, $_, $captures->{$_}) for keys %$captures;
-
+ if ($alias) {
+ require Devel::LexAlias;
+ Devel::LexAlias::lexalias($code, $_, $captures->{$_})
+ for grep !/^\&/, keys %$captures;
+ }
+
return ($code, $e);
}
@@ -222,20 +237,20 @@ sub _clean_eval {
$Eval::Closure::SANDBOX_ID = 0;
sub _make_compiler_source {
- my ($source, @capture_keys) = @_;
+ my ($source, $alias, @capture_keys) = @_;
$Eval::Closure::SANDBOX_ID++;
my $i = 0;
return join "\n", (
"package Eval::Closure::Sandbox_$Eval::Closure::SANDBOX_ID;",
'sub {',
- (map { _make_lexical_stub($_, $i++) } @capture_keys),
+ (map { _make_lexical_assignment($_, $i++, $alias) } @capture_keys),
$source,
'}',
);
}
-sub _make_lexical_stub {
- my ($key, $index) = @_;
+sub _make_lexical_assignment {
+ my ($key, $index, $alias) = @_;
my $sigil = substr($key, 0, 1);
my $name = substr($key, 1);
if (HAS_LEXICAL_SUBS && $sigil eq '&') {
@@ -245,7 +260,12 @@ sub _make_lexical_stub {
. 'my ' . $tmpname . ' = $_[' . $index . ']; '
. 'my sub ' . $name . ' { goto ' . $tmpname . ' }';
}
- return 'my ' . $key . ';';
+ if ($alias) {
+ return 'my ' . $key . ';';
+ }
+ else {
+ return 'my ' . $key . ' = ' . $sigil . '{$_[' . $index . ']};';
+ }
}
sub _dump_source {
diff --git a/t/close-over-nonref.t b/t/close-over-nonref.t
index 66af1c1..69acba0 100644
--- a/t/close-over-nonref.t
+++ b/t/close-over-nonref.t
@@ -9,6 +9,7 @@ my $number = 40;
my $closure = eval_closure(
source => 'sub { $xxx += 2 }',
environment => { '$xxx' => \$number },
+ alias => 1,
);
$closure->();