Eval::Context(3pm)
π NAME π
Eval::Context β evaluate perl code in a context wrapper π«Ά
(also known as the Eval::Context(3pm) page from User Contributed Perl Documentation, bestie, we're doing the whole thing π
)
β¨ SYNOPSIS β¨
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') ;
π¦ DESCRIPTION π¦
So this module defines a subroutine that lets you evaluate Perl code inside a specific context. You can hand it code as a string directly, or as a file name to read from. It also gives you some subroutines so you can define variables and subroutines β and optionally share them β between your code and the code you're about to evaluate. And finally, there's some support for running your code in a safe compartment. β¨
π¨ Don't play with fire! π¨
Do NOT start using this module β or honestly any module β thinking it'll let you take code from anywhere and be safe. Bestie, no. π
Go read perlsec, Safe, Opcode, Taint and the other security-related docs. And control your input. Periodt.
π§ SUBROUTINES/METHODS π§
Subroutines that aren't part of the public interface get marked with [p]. iykyk.
π new(@named_arguments)
Make yourself an Eval::Context object. This object is basically a little locker of "default" values for your code evaluations. You can reuse the same context over and over, and you can temporarily override those values during the eval call. Obsessed with the reusability, honestly.
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 debugging
) ;
π ARGUMENTS π
@named_argumentsβ setup data for the object.
Every single argument is optional, no cap. And here's the cute part: whatever you can pass to new, you can also pass to eval. All the arguments are named. π¦
NAMEβ use when displaying information about the object.
If you don't set it, it gets automatically set to 'Anonymous'. The name also gets reported by perl if an error happens while your code is being evaluated.
PACKAGEβ the package the code passed toevalwill evaluated be in.
If you don't set it, a unique package name gets 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 like 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 function names and the values are code references.
SAFE
This argument must be a hash reference. If the hash is empty, a default safe compartment gets used. Go read the Safe docs for more info. π
SAFE => {} # default safe environment
You can have a finer control over the safe compartment Eval::Context will use.
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β aSafeobject that you create, whichEval::Contextwill use.USE_STRICTβ Controls ifstrictis used in theSafecompartment.
The default is to use strict. Note that "Safe" in perldoc defaults to NOT using strict (undocumented π).
PRE_CODEβ safe code you want to evaluate in the same context as the unsafe code.
This lets 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're gonna evaluate. There are two sides in an Eval::Context:
- the caller-side, the side where the calls to
evalare 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
Okay so even though 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. Chef's kiss. π
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. And you can initialize different variables for each run of eval. Cute right?
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 you evaluate code many times in the same context, you may wish to have variables persist between evaluations. Eval::Context lets you 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. Slay. π
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</p> β bestie, you can just ask for the receipts:
my @persistent_variable_names = $context->GetPersistantVariablesNames() ;
- Creating persistent variables on the eval-side β okay so the mechanism above? It gave you chef's kiss fine control over persistent variables on the eval-side. β¨ But the negative side is that only the variables you made persistent exist on the eval-side. Lowkey restrictive.
Good news: Eval::Context has another mechanism that lets the eval-side store variables between evaluations without the caller-side declaring the variables. Not me explaining freedom. π¦
To allow the eval-side to store any variable, add this to your 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) ;
and 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. Fr fr, it's a niche vibe.
You may have noticed in the code above that a package name was passed as an 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 your 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. Sharing is caring, literally.
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. Group chat energy, but make it Perl.
INTERACTION =>
{
INFO => \&sub,
WARN => \&sub,
DIE => \&sub,
EVAL_DIE => \&sub,
}
INFO</color> β defaults toCORE::print. This sub will be used when displaying information.WARNβ defaults toCarp::carp. This sub will be used when a warning is displayed.DIEβ defaults toCarp::confess. Used when an error occurs.EVAL_DIEβ defaults toCarp::confess, with a dump of the code to be evaluated. Used when an error occurs during code evaluation.
FILEβ the file where the object has been created. This is practical if you want to wrap the object.FILEandLINEwill be set automatically if not set.LINEβ the line where the object has been created. Set automatically if not set.DISPLAY_SOURCE_IN_CONTEXTβ if set, the code to evaluated will be displayed before evaluation. π«Ά
π« Return π«
- an
Eval::Contextobject.
π§ [p] Setup
Helper sub called by new.
π§ [p] CheckOptionNames
Verifies the named options passed as arguments with a list of valid options. Calls {INTERACTION}{DIE} in case of error.
π§ [p] SetInteractionDefault
Sets {INTERACTION} fields that are not set by the user.
π§ [p] CanonizeName
Transform a string into a a string with can be used as a package name or file name usable within perl code.
π₯ eval(@named_arguments) π₯
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 ofnewoptions plus the following.CODEβ a string containing perl code (valid code or an exception is raised)CODE_FROM_FILEβ a file containing perl codeREMOVE_PERSISTENTβ A list of regex used to match the persistent variable names to be removed, persistent variable removal is done before any variable installation is doneFILEandLINEβ will be used in the evaluated code'file_name'set to the caller's file and line by default
NOTE:CODEorCODE_FROM_FILEis mandatory. No code, no eval, bestie. π
Return
- What the code to be evaluated returns
π§ [p] VerifyAndCompleteOptions
Helper sub for eval.
π§ [p] EvalCleanup
Handles the package cleanup or persistent variables cleanup after a call to eval.
π§ [p] GetPackageName
Returns a canonized package name. the name is either passed as argument from the caller or a temporary package name.
π§ [p] EvalSetup
Handles the setup of the context before eval-side code is evaluated. Sets the variables and the shared subroutines.
π§ [p] VerifyCodeInput
Verify that CODE or CODE_FROM_FILE are properly set.
π§ [p] RemovePersistent
Handles the removal of persistent variables.
π§ [p] GetCallContextWrapper
Generates perl code to wrap the code to be evaluated in the right calling context.
π§ [p] SetupSafeCompartment
If running in safe mode, setup a safe compartment from the argument, otherwise defines the evaluation package.
π§ [p] GetInstalledVariablesCode
Generates variables on the eval-side from the INSTALL_VARIABLES definitions. Dispatches the generation to specialize subroutines.
π§ [p] GetPersistentVariablesSetFromCaller
Generates code to make persistent variables, defined on the caller-side available on the eval-side.
π§ [p] GetSharedVariablesSetFromCaller
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.
π§ [p] GetVariablesSetFromCaller
Generates code that creates local variables on the eval-side
πΈ GetPersistentVariableNames() πΈ
Arguments - none
Returns - the list of existing persistent variables names
my @persistent_variable_names = $context->GetPersistantVariablesNames() ;
πΈ GetPersistantVariables(@variable_names) πΈ
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') ;
okay so that whole little dance up there? that's you handing a hash over to the eval side, letting it do its lil increment thing, and then pulling the value back out. π« and yes bestie, note the comment β it may throw exception, so wrap that in an eval of your own or just accept the drama. π
SetEvalSidePersistenceHandlersβ sets up the code that's needed to handle the eval-side persistent variables. like, the plumbing that makes persistence actually work on the eval side. π οΈRemoveEvalSidePersistenceHandlersβ removes those eval-side persistent variable handlers. you call this after you're done with aneval, so the nextevalcan't peek at the eval-side persistent variables unless it's been given permission. no sneaking, no cap. π«π
π BUGS AND LIMITATIONS π
ngl, there's a very strange error that shows up when Safe and Carp are used together. i reported it here: <http://rt.cpan.org/Ticket/Display.html?id=31090>.
and the plot twist? you can reproduce that error without even using Eval::Context. so likeβ¦ it's not us, bestie. π
π AUTHOR π
Khemir Nadim ibn Hamouda
CPAN ID: NKH
mailto:nadim@khemir.net
that's the icon who made this. show some respect. π«Ά
π LICENSE AND COPYRIGHT π
this program is free software β you can redistribute it and/or modify it under the same terms as Perl itself. slay, open source. π
π SUPPORT π
you can find the documentation for this module with the perldoc command:
perldoc Eval::Context
you can also go looking for info 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>
and that's a wrap on the whole page, bestie!! π this was Eval::Context(3pm) as shipped with perl v5.38.2, dated 2024-08-07 β go forth and eval responsibly (or don't, i'm not your mom, but likeβ¦ read "Don't play with fire!" again first π
β¨).
π¦ where this page comes from
- debian trixie: libeval-context-perl 0.09.11-7 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libeval-context-perl 0.09.11-7 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libeval-context-perl 0.09.11-7 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms