4 use Sub::Exporter -setup => {
5 exports => [qw(eval_closure)],
6 groups => { default => [qw(eval_closure)] },
11 use Scalar::Util qw(reftype);
17 $args{source} = _canonicalize_source($args{source});
18 _validate_env($args{environment} ||= {});
20 $args{source} = _line_directive($args{description}) . $args{source}
21 if defined $args{description};
23 my ($code, $e) = _clean_eval_closure(@args{qw(source environment)});
25 croak("Failed to compile source: $e\n\nsource:\n$args{source}")
31 sub _canonicalize_source {
34 if (defined($source)) {
36 if (reftype($source) eq 'ARRAY'
37 || overload::Method($source, '@{}')) {
38 return join "\n", @$source;
40 elsif (overload::Method($source, '""')) {
44 croak("The 'source' parameter to eval_closure must be a "
45 . "string or array reference");
53 croak("The 'source' parameter to eval_closure is required");
60 croak("The 'environment' parameter must be a hashref")
61 unless reftype($env) eq 'HASH';
63 for my $var (keys %$env) {
64 croak("Environment key '$var' should start with \@, \%, or \$")
65 unless $var =~ /^([\@\%\$])/;
66 croak("Environment values must be references, not $env->{$var}")
67 unless ref($env->{$var});
72 my ($description) = @_;
74 return qq{#line 1 "$description"\n};
77 sub _clean_eval_closure {
78 my ($source, $captures) = @_;
80 if ($ENV{EVAL_CLOSURE_PRINT_SOURCE}) {
81 _dump_source(_make_compiler_source(@_));
84 my ($compiler, $e) = _make_compiler(@_);
86 if (defined $compiler) {
87 $code = $compiler->(map { $captures->{$_} } sort keys %$captures);
90 if (defined($code) && (!ref($code) || ref($code) ne 'CODE')) {
91 $e = "The 'source' parameter must return a subroutine reference, "
102 my $compiler = eval _make_compiler_source(@_);
104 return ($compiler, $e);
107 sub _make_compiler_source {
108 my ($source, $captures) = @_;
113 'my ' . $_ . ' = ' . substr($_, 0, 1) . '{$_[' . $i++ . ']};'
114 } sort keys %$captures),
124 if (try { require Perl::Tidy }) {
125 Perl::Tidy::perltidy(
127 destination => \$output,