summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2013-05-31 03:06:56 -0500
committerJesse Luehrs <doy@tozt.net>2013-05-31 03:06:56 -0500
commit7ece130cfc351e31e273d14a72ccd8442c0df549 (patch)
treec7b7248afedb56f74360fe48730769d225521337
parentef520c02cea20449c3bdeb656271ac51e645edcb (diff)
downloadreply-7ece130cfc351e31e273d14a72ccd8442c0df549.tar.gz
reply-7ece130cfc351e31e273d14a72ccd8442c0df549.zip
work around a lexical::persistence bug
-rw-r--r--lib/Reply/Plugin/LexicalPersistence.pm38
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;