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.
51 =func eval_closure(%args)
53 This function provides the main functionality of this module. It is exported by
54 default. It takes a hash of parameters, with these keys being valid:
60 The string to be evaled. It should end by returning a code reference. It can
61 access any variable declared in the C<environment> parameter (and only those
62 variables). It can be either a string, or an arrayref of lines (which will be
63 joined with newlines to produce the string).
67 The environment to provide to the eval. This should be a hashref, mapping
68 variable names (including sigils) to references of the appropriate type. For
69 instance, a valid value for environment would be C<< { '@foo' => [] } >> (which
70 would allow the generated function to use an array named C<@foo>). Generally,
71 this is used to allow the generated function to access externally defined
72 variables (so you would pass in a reference to a variable that already exists).
76 This lets you provide a bit more information in backtraces. Normally, when a
77 function that was generated through string eval is called, that stack frame
78 will show up as "(eval n)", where 'n' is a sequential identifier for every
79 string eval that has happened so far in the program. Passing a C<description>
80 parameter lets you override that to something more useful (for instance,
81 L<Moose> overrides the description for accessors to something like "accessor
82 foo at MyClass.pm, like 123").
91 $args{source} = _canonicalize_source($args{source});
92 _validate_env($args{environment} ||= {});
94 $args{source} = _line_directive($args{description}) . $args{source}
95 if defined $args{description};
97 my ($code, $e) = _clean_eval_closure(@args{qw(source environment)});
99 croak("Failed to compile source: $e\n\nsource:\n$args{source}")
105 sub _canonicalize_source {
108 if (defined($source)) {
110 if (reftype($source) eq 'ARRAY'
111 || overload::Method($source, '@{}')) {
112 return join "\n", @$source;
114 elsif (overload::Method($source, '""')) {
118 croak("The 'source' parameter to eval_closure must be a "
119 . "string or array reference");
127 croak("The 'source' parameter to eval_closure is required");
134 croak("The 'environment' parameter must be a hashref")
135 unless reftype($env) eq 'HASH';
137 for my $var (keys %$env) {
138 croak("Environment key '$var' should start with \@, \%, or \$")
139 unless $var =~ /^([\@\%\$])/;
140 croak("Environment values must be references, not $env->{$var}")
141 unless ref($env->{$var});
145 sub _line_directive {
146 my ($description) = @_;
148 return qq{#line 1 "$description"\n};
151 sub _clean_eval_closure {
152 my ($source, $captures) = @_;
154 if ($ENV{EVAL_CLOSURE_PRINT_SOURCE}) {
155 _dump_source(_make_compiler_source(@_));
158 my @capture_keys = sort keys %$captures;
159 my ($compiler, $e) = _make_compiler($source, @capture_keys);
161 if (defined $compiler) {
162 $code = $compiler->(@$captures{@capture_keys});
165 if (defined($code) && (!ref($code) || ref($code) ne 'CODE')) {
166 $e = "The 'source' parameter must return a subroutine reference, "
177 my $compiler = eval _make_compiler_source(@_);
179 return ($compiler, $e);
181 memoize('_make_compiler');
183 sub _make_compiler_source {
184 my ($source, @capture_keys) = @_;
189 'my ' . $_ . ' = ' . substr($_, 0, 1) . '{$_[' . $i++ . ']};'
200 if (try { require Perl::Tidy }) {
201 Perl::Tidy::perltidy(
203 destination => \$output,
217 Please report any bugs through RT: email
218 C<bug-eval-closure at rt.cpan.org>, or browse to
219 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Eval-Closure>.
225 =item * L<Class::MOP::Method::Accessor>
227 This module is a factoring out of code that used to live here
233 You can find this documentation for this module with the perldoc command.
235 perldoc Eval::Closure
237 You can also look for information at:
241 =item * AnnoCPAN: Annotated CPAN documentation
243 L<http://annocpan.org/dist/Eval-Closure>
247 L<http://cpanratings.perl.org/d/Eval-Closure>
249 =item * RT: CPAN's request tracker
251 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Eval-Closure>
255 L<http://search.cpan.org/dist/Eval-Closure>
261 Jesse Luehrs <doy at tozt dot net>
263 Based on code from L<Class::MOP::Method::Accessor>, by Stevan Little and the