diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Reply/Plugin/LexicalPersistence.pm | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/lib/Reply/Plugin/LexicalPersistence.pm b/lib/Reply/Plugin/LexicalPersistence.pm index 0540f96..deb8d94 100644 --- a/lib/Reply/Plugin/LexicalPersistence.pm +++ b/lib/Reply/Plugin/LexicalPersistence.pm @@ -25,7 +25,45 @@ sub compile { (map { $_ => ref($c{$_}) ? $c{$_} : \$c{$_} } keys %c), }; my ($code) = $next->($line, %args); + $code = $self->_fixup_code($code, \%c); return $self->{env}->wrap($code); } +# XXX this is maybe a bug in Lexical::Persistence - it clears variables that +# aren't in its context, regardless of if they may have been set elsewhere +sub _fixup_code { + my $self = shift; + my ($code, $context) = @_; + + require PadWalker; + require Devel::LexAlias; + + my $pad = PadWalker::peek_sub($code); + my %restore; + for my $var (keys %$pad) { + next unless $var =~ /^\$\@\%./; + next if exists $context->{$var}; + $restore{$var} = $pad->{$var}; + } + + $self->{code} = $code; + + return sub { + my $code = shift; + for my $var (keys %restore) { + Devel::LexAlias::lexalias($code, $var, $restore{$var}); + } + $code->(@_); + }; +} + +# XXX can't just close over $code, because it will also be cleared by the same +# bug! we have to pass it as a parameter instead +sub execute { + my $self = shift; + my ($next, @args) = @_; + + $next->(delete $self->{code}, @args); +} + 1; |