don't need this to be a do block anymore
[gitmo/Eval-Closure.git] / lib / Eval / Closure.pm
CommitLineData
efb592ef 1package Eval::Closure;
2use Sub::Exporter -setup => {
3 exports => [qw(eval_closure)],
4};
5
6use Carp;
7use overload ();
8use Scalar::Util qw(reftype);
9use Try::Tiny;
10
11sub eval_closure {
12 my (%args) = @_;
13 $args{source} = _canonicalize_source($args{source});
14
15 my ($code, $e) = _clean_eval_closure(@args{qw(source environment name)});
16
17 croak("Failed to compile source: $e\n\nsource:\n$args{source}")
18 unless $code;
19
20 return $code;
21}
22
23sub _canonicalize_source {
24 my ($source) = @_;
25
26 if (defined($source)) {
27 if (ref($source)) {
28 if (reftype($source) eq 'ARRAY'
29 || overload::Method($source, '@{}')) {
30 return join "\n", @$source;
31 }
32 elsif (overload::Method($source, '""')) {
33 return "$source";
34 }
35 else {
36 croak("The 'source' parameter to eval_closure must be a "
37 . "string or array reference");
38 }
39 }
40 else {
41 return $source;
42 }
43 }
44 else {
45 croak("The 'source' parameter to eval_closure is required");
46 }
47}
48
49sub _clean_eval_closure {
d3319272 50 # my ($source, $__captures, $name) = @_
efb592ef 51 my $__captures = $_[1];
52
a30f41f7 53 local $@;
54 local $SIG{__DIE__};
efb592ef 55
a30f41f7 56 if ($ENV{EVAL_CLOSURE_PRINT_SOURCE}) {
57 _dump_source(_make_source(@_), $_[2]);
58 }
efb592ef 59
a30f41f7 60 my $code = eval _make_source(@_);
61 ($code, $@);
efb592ef 62}
63
64sub _make_source {
65 my ($source, $__captures) = @_;
66 return join "\n", (
67 (map {
68 die "Capture key should start with \@, \% or \$: $_"
69 unless /^([\@\%\$])/;
70 'my ' . $_ . ' = ' . $1 . '{$__captures->{\'' . $_ . '\'}};';
71 } keys %$__captures),
72 $source,
73 );
74}
75
76sub _dump_source {
77 my ($source, $name) = @_;
78
79 my $output;
80 if (try { require Perl::Tidy }) {
81 Perl::Tidy::perltidy(
82 source => \$source,
83 destination => \$output,
84 );
85 }
86 else {
87 $output = $source;
88 }
89
90 $name = defined($name) ? $name : "__ANON__";
91 warn $name . ":\n" . $output . "\n";
92}
93
941;