4 use Sub::Exporter -setup => {
5 exports => [qw(eval_closure)],
6 groups => { default => [qw(eval_closure)] },
8 # ABSTRACT: safely and cleanly create closures via string eval
13 use Scalar::Util qw(reftype);
20 my $code = eval_closure(
21 source => 'sub { $foo++ }',
30 my $code2 = eval_closure(
31 source => 'sub { $code->() }',
32 ); # dies, $code isn't in scope
36 String eval is often used for dynamic code generation. For instance, C<Moose>
37 uses it heavily, to generate inlined versions of accessors and constructors,
38 which speeds code up at runtime by a significant amount. String eval is not
39 without its issues however - it's difficult to control the scope it's used in
40 (which determines which variables are in scope inside the eval), and it can be
41 quite slow, especially if doing a large number of evals.
43 This module attempts to solve both of those problems. It provides an
44 C<eval_closure> function, which evals a string in a clean environment, other
45 than a fixed list of specified variables. It also caches the result of the
46 eval, so that doing repeated evals of the same source, even with a different
47 environment, will be much faster (but note that the description is part of the
48 string to be evaled, so it must also be the same (or non-existent) if caching
53 =func eval_closure(%args)
55 This function provides the main functionality of this module. It is exported by
56 default. It takes a hash of parameters, with these keys being valid:
62 The string to be evaled. It should end by returning a code reference. It can
63 access any variable declared in the C<environment> parameter (and only those
64 variables). It can be either a string, or an arrayref of lines (which will be
65 joined with newlines to produce the string).
69 The environment to provide to the eval. This should be a hashref, mapping
70 variable names (including sigils) to references of the appropriate type. For
71 instance, a valid value for environment would be C<< { '@foo' => [] } >> (which
72 would allow the generated function to use an array named C<@foo>). Generally,
73 this is used to allow the generated function to access externally defined
74 variables (so you would pass in a reference to a variable that already exists).
78 This lets you provide a bit more information in backtraces. Normally, when a
79 function that was generated through string eval is called, that stack frame
80 will show up as "(eval n)", where 'n' is a sequential identifier for every
81 string eval that has happened so far in the program. Passing a C<description>
82 parameter lets you override that to something more useful (for instance,
83 L<Moose> overrides the description for accessors to something like "accessor
84 foo at MyClass.pm, line 123").
93 $args{source} = _canonicalize_source($args{source});
94 _validate_env($args{environment} ||= {});
96 $args{source} = _line_directive($args{description}) . $args{source}
97 if defined $args{description};
99 my ($code, $e) = _clean_eval_closure(@args{qw(source environment)});
101 croak("Failed to compile source: $e\n\nsource:\n$args{source}")
107 sub _canonicalize_source {
110 if (defined($source)) {
112 if (reftype($source) eq 'ARRAY'
113 || overload::Method($source, '@{}')) {
114 return join "\n", @$source;
116 elsif (overload::Method($source, '""')) {
120 croak("The 'source' parameter to eval_closure must be a "
121 . "string or array reference");
129 croak("The 'source' parameter to eval_closure is required");
136 croak("The 'environment' parameter must be a hashref")
137 unless reftype($env) eq 'HASH';
139 for my $var (keys %$env) {
140 croak("Environment key '$var' should start with \@, \%, or \$")
141 unless $var =~ /^([\@\%\$])/;
142 croak("Environment values must be references, not $env->{$var}")
143 unless ref($env->{$var});
147 sub _line_directive {
148 my ($description) = @_;
150 return qq{#line 1 "$description"\n};
153 sub _clean_eval_closure {
154 my ($source, $captures) = @_;
156 if ($ENV{EVAL_CLOSURE_PRINT_SOURCE}) {
157 _dump_source(_make_compiler_source(@_));
160 my @capture_keys = sort keys %$captures;
161 my ($compiler, $e) = _make_compiler($source, @capture_keys);
163 if (defined $compiler) {
164 $code = $compiler->(@$captures{@capture_keys});
167 if (defined($code) && (!ref($code) || ref($code) ne 'CODE')) {
168 $e = "The 'source' parameter must return a subroutine reference, "
179 my $compiler = eval _make_compiler_source(@_);
181 return ($compiler, $e);
183 memoize('_make_compiler');
185 sub _make_compiler_source {
186 my ($source, @capture_keys) = @_;
191 'my ' . $_ . ' = ' . substr($_, 0, 1) . '{$_[' . $i++ . ']};'
202 if (try { require Perl::Tidy }) {
203 Perl::Tidy::perltidy(
205 destination => \$output,
219 Please report any bugs through RT: email
220 C<bug-eval-closure at rt.cpan.org>, or browse to
221 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Eval-Closure>.
227 =item * L<Class::MOP::Method::Accessor>
229 This module is a factoring out of code that used to live here
235 You can find this documentation for this module with the perldoc command.
237 perldoc Eval::Closure
239 You can also look for information at:
243 =item * AnnoCPAN: Annotated CPAN documentation
245 L<http://annocpan.org/dist/Eval-Closure>
249 L<http://cpanratings.perl.org/d/Eval-Closure>
251 =item * RT: CPAN's request tracker
253 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Eval-Closure>
257 L<http://search.cpan.org/dist/Eval-Closure>
263 Jesse Luehrs <doy at tozt dot net>
265 Based on code from L<Class::MOP::Method::Accessor>, by Stevan Little and the