|
|
| |
Eval::Context(3) |
User Contributed Perl Documentation |
Eval::Context(3) |
Eval::Context - Evalute perl code in context wraper
use Eval::Context ;
my $context = new Eval::Context(PRE_CODE => "use strict;\nuse warnings;\n") ;
# code will be evaluated with strict and warnings loaded in the context.
$context->eval(CODE => 'print "evaluated in an Eval::Context!" ;') ;
$context->eval(CODE_FROM_FILE => 'file.pl') ;
This module define a subroutine that let you evaluate Perl code in a specific
context. The code can be passed directly as a string or as a file name to read
from. It also provides some subroutines to let you define and optionally share
variables and subroutines between your code and the code you wish to evaluate.
Finally there is some support for running your code in a safe compartment.
Don't start using this module, or any other module, thinking it will let you
take code from anywhere and be safe. Read perlsec, Safe, Opcode, Taint and
other security related documents. Control your input.
Subroutines that are not part of the public interface are marked with [p].
Create an Eval::Context object. The object is used as a repository of
"default" values for your code evaluations. The context can be used
many times. The values can be temporarily overridden during the
"eval" call.
my $context = new Eval::Context() ; # default context
my $context = new Eval::Context
(
NAME => 'libraries evaluation context',
PACKAGE => 'libraries',
SAFE => {...} ;
PRE_CODE => "use strict ;\n"
POST_CODE => sub{},
PERL_EVAL_CONTEXT => undef,
INSTALL_SUBS => {...},
INSTALL_VARIABLES => [...],
EVAL_SIDE_PERSISTENT_VARIABLES => {...},
INTERACTION => {...},
DISPLAY_SOURCE_IN_CONTEXT => 1, #useful when debuging
) ;
ARGUMENTS
- •
- @named_arguments - setup data for the object
All the arguments optional. The argument passed to
"new" can also be passed to
"eval". All arguments are named.
- NAME - use when displaying information about the object.
Set automatically to 'Anonymous' if not set. The name will
also be reported by perl if an error occurs during your code
evaluation.
- PACKAGE - the package the code passed to
"eval" will evaluated be in.
If not set, a unique package name is generated and used for
every "eval" call.
- REMOVE_PACKAGE_AFTER_EVAL - When set the content of the package after
evaluation will be erase
The default behavior is to remove all data from after the call
to "eval".
- PRE_CODE - code prepended to the code passed to eval
- POST_CODE - code appended to the code passed to eval
- PERL_EVAL_CONTEXT - the context to eval code in (void, scalar, list).
This option Works as "wantarray" in perlfunc. It
will override the context in which
"eval" is called.
- INSTALL_SUBS - subs that will be available in the eval.
A hash where the keys are a function names and the values a
code references.
- SAFE
This argument must be a hash reference. if the hash is empty,
a default safe compartment will be used. Read Safe documentation for
more information.
SAFE => {} # default safe environment
You can have a finer control over the safe compartment
Eval::Context that will be used.
my $compartment = new Safe('ABC') ;
my $context = new Eval::Context
(
SAFE => # controlling the safe environment
{
PACKAGE => 'ABC',
PRE_CODE => "use my module ;\n" # code we consider safe
USE_STRICT => 0, # set to 1 by default
COMPARTMENT => $compartment , # use default if not passed
} ,
}
$context->eval(CODE => .....) ;
- COMPARTMENT - a Safe object, you create, that will be used by
Eval::Context
- USE_STRICT - Controls if strict is used in the Safe compartment
The default is to use strict. Note that "Safe" in
perldoc default is to NOT use strict (undocumented).
- PRE_CODE - safe code you want to evaluate in the same context as the
unsafe code
This let you, for example, use certain modules which provide
subroutines to be used in the evaluated code. The default compartment is
quite restrictive and you can't even use strict in it without tuning the
safe compartment.
A few remarks:
- See <http://rt.cpan.org/Ticket/Display.html?id=31090> on
RT
- Pass the same package name to your safe compartment and to
Eval::Context.
- If you really want to be on the safe side, control your input.
When you use a module, are you sure the module hasn't been fiddle with?
- Leave strict on. Even for trivial code.
- •
- INSTALL_VARIABLES - "Give me sugar baby" Ash.
Eval::Context has mechanisms you can use to set and
share variables with the code you will evaluate. There are two sides in
an Eval::Context. The caller-side, the side where the
calls to "eval" are made and the
eval-side, the side where the code to be evaluated is run.
- How should you get values back from the eval-side
Although you can use the mechanisms below to get values from
the eval-side, the cleanest way is to get the results directly
from the "eval" call.
my $context = new Eval::Context() ;
my ($scalr_new_value, $a_string) =
$context->eval
(
INSTALL_VARIABLES =>[[ '$scalar' => 42]] ,
CODE => "\$scalar++ ;\n (\$scalar, 'a string') ;",
) ;
- initializing variables on the eval side
You can pass INSTALL_VARIABLES to
"new" or
"eval". You can initialize different
variables for each run of "eval".
my $context = new Eval::Context
(
INSTALL_VARIABLES =>
[
# variables on eval-side #initialization source
[ '$data' => 42],
[ '$scalar' => $scalar_caller_side ],
[ '%hash' => \%hash_caller_side ]
[ '$hash' => \%hash_caller_side ],
[ '$object' => $object ],
] ,
) ;
The variables will be my variables on the
eval-side.
You can declare variables of any of the base types supported
by perl. The initialization data , on the caller-side, is serialized and
deserialized to make the values available on the eval-side. Modifying
the variables on the eval-side does not modify the variables on the
caller-side. The initialization data can be scalars or references and
even my variables.
- Persistent variables
When evaluating code many times in the same context, you may
wish to have variables persist between evaluations. Eval::Context
allows you to declare, define and control such state
variables.
This mechanism lets you control which variables are
persistent. Access to the persistent variables is controlled per
"eval" run. Persistent variables are
my variables on the eval-side. Modifying the variables on
the eval-side does not modify the variables on the
caller-side.
Define persistent variables:
# note: creating persistent variables in 'new' makes little sense as
# it will force those values in the persistent variables for every run.
# This may or may not be what you want.
my $context = new Eval::Context() ;
$context->eval
(
INSTALL_VARIABLES =>
[
[ '$scalar' => 42 => $Eval::Context::PERSISTENT ] ,
# make %hash and $hash available on the eval-side. both are
# initialized from the same caller-side hash
[ '%hash' => \%hash_caller_side => $Eval::Context::PERSISTENT ] ,
[ '$hash' => \%hash_caller_side => $Eval::Context::PERSISTENT ] ,
],
CODE => '$scalar++',
) ;
Later, use the persistent value:
$context->eval
(
INSTALL_VARIABLES =>
[
[ '$scalar' => $Eval::Context::USE => $Eval::Context::PERSISTENT ] ,
# here you decided %hash and $hash shouldn't be available on the eval-side
],
CODE => '$scalar',
) ;
$Eval::Context::USE means "make
the persistent variable and it's value available on the
eval-side". Any other value will reinitialize the persistent
variable. See also REMOVE_PERSISTENT in
"eval".
- Manually synchronizing caller-side data with persistent eval-side data
Although the first intent of persistent variables is to be
used as state variables on the eval-side, you can get persistent
variables values on the caller-side. To change the value of an
eval-side persistent variable, simply reinitialize it with
INSTALL_VARIABLES next time you call
"eval".
my $context = new Eval::Context
(
INSTALL_VARIABLES =>
[
['%hash' => \%hash_caller_side => $Eval::Context::PERSISTENT]
] ,
) ;
$context->Eval(CODE => '$hash{A}++ ;') ;
# throws exception if you request a non existing variable
my %hash_after_eval = $context->GetPersistantVariables('%hash') ;
- Getting the list of all the PERSISTENT variables
my @persistent_variable_names = $context->GetPersistantVariablesNames() ;
- Creating persistent variables on the eval-side
The mechanism above gave you fine control over persistent
variables on the eval-side. The negative side is that only
the variables you made persistent exist on the eval-side.
Eval::Context has another mechanism that allows the
eval-side to store variables between evaluations without the
caller-side declaration of the variables.
To allow the eval-side to store any variable, add this
to you "new" call.
my $context = new Eval::Context
(
PACKAGE => 'my_package',
EVAL_SIDE_PERSISTENT_VARIABLES =>
{
SAVE => { NAME => 'SavePersistent', VALIDATOR => sub{} },
GET => { NAME => 'GetPersistent', VALIDATOR => sub{} },
},
) ;
The eval-side can now store variables between calls to
"eval"
SavePersistent('name', $value) ;
later in another call to
"eval":
my $variable = GetPersistent('name') ;
By fine tuning EVAL_SIDE_PERSISTENT_VARIABLES you can
control what variables are stored by the eval-side. This should
seldom be used and only to help those storing data from the
eval-side.
You may have notices in the code above that a package name was
passed as argument to "new". This is
very important as the package names that are automatically generated
differ for each "eval" call. If you
want to run all you eval-side code in different packages
(Eval::Context default behavior), you must tell
Eval::Context where to store the eval-side values. This is
done by setting CATEGORY
The validator sub can verify if the value to be stored are
valid, E.G.: variable name, variable value is within range, ...
Here is an example of code run in different packages but can
share variables. Only variables which names start with A are
valid.
new Eval::Context
(
EVAL_SIDE_PERSISTENT_VARIABLES =>
{
CATEGORY => 'TEST',
SAVE =>
{
NAME => 'SavePersistent',
VALIDATOR => sub
{
my ($self, $name, $value, $package) = @_ ;
$self->{INTERACTION}{DIE}->
(
$self,
"SavePersistent: name '$name' doesn't start with A!"
) unless $name =~ /^A/ ;
},
},
GET => {NAME => 'GetPersistent',VALIDATOR => sub {}},
},
) ;
$context->eval(CODE => 'SavePersistent('A_variable', 123) ;') ;
later:
$context->eval(CODE => 'GetPersistent('A_variable') ;') ;
- Shared variables
You can also share references between the caller-side
and the eval-side.
my $context =
new Eval::Context
(
INSTALL_VARIABLES =>
[
# reference to reference only
[ '$scalar' => \$scalar => $Eval::Context::SHARED ],
[ '$hash' => \%hash_caller_side => $Eval::Context::SHARED ],
[ '$object' => $object => $Eval::Context::SHARED ],
] ,
) ;
Modification of the variables on the eval-side will
modify the variable on the caller-side. There are but a few
reasons to share references. Note that you can share references to
my variables.
- •
- INTERACTION
Lets you define subs used to interact with the user.
INTERACTION =>
{
INFO => \&sub,
WARN => \&sub,
DIE => \&sub,
EVAL_DIE => \&sub,
}
- INFO - defaults to CORE::print
- This sub will be used when displaying information.
- WARN - defaults to Carp::carp
- This sub will be used when a warning is displayed.
- DIE - defaults to Carp::confess
- Used when an error occurs.
- EVAL_DIE - defaults to Carp::confess, with a dump of the code to be
evaluated
- Used when an error occurs during code evaluation.
Return
- •
- an Eval::Context object.
Helper sub called by new.
Verifies the named options passed as arguments with a list of valid options.
Calls {INTERACTION}{DIE} in case of error.
Sets {INTERACTION} fields that are not set by the user.
Transform a string into a a string with can be used as a package name or file
name usable within perl code.
Evaluates Perl code, passed as a string or read from a file, in the context.
my $context = new Eval::Context(PRE_CODE => "use strict;\nuse warnings;\n") ;
$context->eval(CODE => 'print "evaluated in an Eval::Context!";') ;
$context->eval(CODE_FROM_FILE => 'file.pl') ;
Call context
Evaluation context of the code (void, scalar, list) is the same as
the context this subroutine was called in or in the context defined by
PERL_EVAL_CONTEXT if that option is present.
Arguments
NOTE: You can override any argument passed to
"new". The override is temporary
during the duration of this call.
- •
- @named_arguments - Any of
"new" options plus the following.
NOTE: CODE or CODE_FROM_FILE is
mandatory.
Return
- •
- What the code to be evaluated returns
Handles the package cleanup or persistent variables cleanup after a call to
"eval".
Returns a canonized package name. the name is either passed as argument from the
caller or a temporary package name.
Handles the setup of the context before eval-side code is evaluated. Sets
the variables and the shared subroutines.
Verify that CODE or CODE_FROM_FILE are properly set.
Handles the removal of persistent variables.
Generates perl code to wrap the code to be evaluated in the right calling
context.
If running in safe mode, setup a safe compartment from the argument, otherwise
defines the evaluation package.
Generates variables on the eval-side from the INSTALL_VARIABLES definitions.
Dispatches the generation to specialize subroutines.
Generates code to make persistent variables, defined on the caller-side
available on the eval-side.
Handles the mechanism used to share variables (references) between the
caller-side and the eval-side.
Shared variables must be defined and references. If the shared
variable is undef, the variable that was previously shared, under the
passed name, is used if it exists or an exception is raised.
Also check that variables are not PERSISTENT and
SHARED.
Generates code that creates local variables on the eval-side
Arguments - none
Returns - the list of existing persistent variables
names
my @persistent_variable_names = $context->GetPersistantVariablesNames() ;
Arguments
- •
- @variable_names - list of variable names to
retrieve
Returns - list of values corresponding to the input
names
This subroutine will return whatever the caller-site set or
the eval-side modified. Thus if you created a
%hash persistent variable, a hash (not a hash
reference) will be returned.
If you request multiple values, list flattening will be in effect.
Be careful.
my $context = new Eval::Context
(
INSTALL_VARIABLES =>
[
['%hash' => \%hash_caller_side => $Eval::Context::PERSISTENT]
] ,
) ;
$context->Eval(CODE => '$hash{A}++ ;') ;
# may throw exception
my %hash_after_eval = $context->GetPersistantVariables('%hash') ;
Set the code needed to handle eval-side persistent variables.
Removes eval-side persistent variable handlers. Used after calling
"eval" so the next
"eval" can not access eval-side
persistent variables without being allowed to do so.
I have reported a very strange error when Safe and Carp are used
together. <http://rt.cpan.org/Ticket/Display.html?id=31090>. The error
can be reproduced without using Eval::Context.
Khemir Nadim ibn Hamouda
CPAN ID: NKH
mailto:nadim@khemir.net
This program is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.
You can find documentation for this module with the perldoc command.
perldoc Eval::Context
You can also look for information at:
- AnnoCPAN: Annotated CPAN documentation
<http://annocpan.org/dist/Eval-Context>
- RT: CPAN's request tracker
Please report any bugs or feature requests to L
<bug-eval-context@rt.cpan.org>.
We will be notified, and then you'll automatically be notified
of progress on your bug as we make changes.
- Search CPAN
<http://search.cpan.org/dist/Eval-Context>
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc. |