X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit%2FEval-WithLexicals.git;a=blobdiff_plain;f=lib%2FEval%2FWithLexicals.pm;h=31703e65713c85c9635e1726d8109b8b1130a66a;hp=1517ef710a75a4d59721fece83afa26e0005f0bb;hb=1de34059104e948aa75ce26b562eb9b3f14980e7;hpb=6f914695d80ef46fe45ac39758eb956f0f5389a6 diff --git a/lib/Eval/WithLexicals.pm b/lib/Eval/WithLexicals.pm index 1517ef7..31703e6 100644 --- a/lib/Eval/WithLexicals.pm +++ b/lib/Eval/WithLexicals.pm @@ -3,6 +3,9 @@ package Eval::WithLexicals; use Moo; use Sub::Quote; +our $VERSION = '1.001000'; # 1.1.0 +$VERSION = eval $VERSION; + has lexicals => (is => 'rw', default => quote_sub q{ {} }); { @@ -33,13 +36,14 @@ sub eval { ${setup} sub Eval::WithLexicals::Cage::current_line { package ${package}; +#line 1 "(eval)" ${to_eval} ;sub Eval::WithLexicals::Cage::pad_capture { } BEGIN { Eval::WithLexicals::Util::capture_list() } sub Eval::WithLexicals::Cage::grab_captures { - no warnings 'closure'; no strict 'refs'; - package Eval::WithLexicals::Cage;!; - $self->_eval_do(\$current_code, $self->lexicals); + no warnings 'closure'; no strict 'vars'; + package Eval::WithLexicals::VarScope;!; + $self->_eval_do(\$current_code, $self->lexicals, $to_eval); my @ret; my $ctx = $self->context; if ($ctx eq 'list') { @@ -51,13 +55,26 @@ sub Eval::WithLexicals::Cage::grab_captures { } $self->lexicals({ %{$self->lexicals}, - %{Eval::WithLexicals::Cage::grab_captures()} + %{$self->_grab_captures}, }); @ret; } +sub _grab_captures { + my ($self) = @_; + my $cap = Eval::WithLexicals::Cage::grab_captures(); + foreach my $key (keys %$cap) { + my ($sigil, $name) = $key =~ /^(.)(.+)$/; + my $var_scope_name = $sigil.'Eval::WithLexicals::VarScope::'.$name; + if ($cap->{$key} eq eval "\\${var_scope_name}") { + delete $cap->{$key}; + } + } + $cap; +} + sub _eval_do { - my ($self, $text_ref) = @_; + my ($self, $text_ref, $lexicals, $original) = @_; local @INC = (sub { if ($_[1] eq '/eval_do') { open my $fh, '<', $text_ref; @@ -66,7 +83,7 @@ sub _eval_do { (); } }, @INC); - do '/eval_do' or die "Error: $@\nCompiling: $$text_ref"; + do '/eval_do' or die $@; } { @@ -76,7 +93,7 @@ sub _eval_do { sub capture_list { my $pad_capture = \&Eval::WithLexicals::Cage::pad_capture; - my @names = map $_->PV, grep $_->isa('B::PV'), + my @names = grep $_ ne '&', map $_->PV, grep $_->isa('B::PV'), svref_2object($pad_capture)->OUTSIDE->PADLIST->ARRAYelt(0)->ARRAY; $Eval::WithLexicals::current_code .= '+{ '.join(', ', map "'$_' => \\$_", @names).' };' @@ -84,4 +101,102 @@ sub _eval_do { } } +=head1 NAME + +Eval::WithLexicals - pure perl eval with persistent lexical variables + +=head1 SYNOPSIS + + # file: bin/tinyrepl + + #!/usr/bin/env perl + + use strictures 1; + use Eval::WithLexicals; + use Term::ReadLine; + use Data::Dumper; + + $SIG{INT} = sub { warn "SIGINT\n" }; + + { package Data::Dumper; no strict 'vars'; + $Terse = $Indent = $Useqq = $Deparse = $Sortkeys = 1; + $Quotekeys = 0; + } + + my $eval = Eval::WithLexicals->new; + my $read = Term::ReadLine->new('Perl REPL'); + while (1) { + my $line = $read->readline('re.pl$ '); + exit unless defined $line; + my @ret; eval { + local $SIG{INT} = sub { die "Caught SIGINT" }; + @ret = $eval->eval($line); 1; + } or @ret = ("Error!", $@); + print Dumper @ret; + } + + # shell session: + + $ perl -Ilib bin/tinyrepl + re.pl$ my $x = 0; + 0 + re.pl$ ++$x; + 1 + re.pl$ $x + 3; + 4 + re.pl$ ^D + $ + +=head1 METHODS + +=head2 new + + my $eval = Eval::WithLexicals->new( + lexicals => { '$x' => \1 }, # default {} + in_package => 'PackageToEvalIn', # default Eval::WithLexicals::Scratchpad + context => 'scalar', # default 'list' + ); + +=head2 eval + + my @return_value = $eval->eval($code_to_eval); + +=head2 lexicals + + my $current_lexicals = $eval->lexicals; + + $eval->lexicals(\%new_lexicals); + +=head2 in_package + + my $current_package = $eval->in_package; + + $eval->in_package($new_package); + +=head2 context + + my $current_context = $eval->context; + + $eval->context($new_context); # 'list', 'scalar' or 'void' + +=head1 AUTHOR + +Matt S. Trout + +=head1 CONTRIBUTORS + +David Leadbeater + +=head1 COPYRIGHT + +Copyright (c) 2010 the Eval::WithLexicals L and L +as listed above. + +=head1 LICENSE + +This library is free software and may be distributed under the same terms +as perl itself. + +=cut + 1;