File Coverage

blib/lib/Eval/Quosure.pm
Criterion Covered Total %
statement 55 64 85.9
branch 5 10 50.0
condition 3 4 75.0
subroutine 16 16 100.0
pod 4 5 80.0
total 83 99 83.8


line stmt bran cond sub pod time code
1             package Eval::Quosure;
2              
3             # ABSTRACT: Evaluate within a caller environment
4              
5 1     1   188427 use 5.010;
  1         7  
6 1     1   4 use strict;
  1         2  
  1         16  
7 1     1   3 use warnings;
  1         2  
  1         34  
8              
9             our $VERSION = '0.001002'; # VERSION
10              
11 1     1   5 use List::Util 1.28 qw(pairmap);
  1         13  
  1         51  
12 1     1   357 use PadWalker 2.3 qw(peek_my peek_our);
  1         566  
  1         50  
13 1     1   352 use Safe::Isa 1.000009;
  1         470  
  1         119  
14 1     1   432 use Sub::Quote 2.005 qw(quote_sub);
  1         5317  
  1         56  
15 1     1   513 use Type::Params 1.004004;
  1         92289  
  1         9  
16 1     1   431 use Types::Standard qw(Str Int HashRef Optional);
  1         2  
  1         8  
17              
18             sub new {
19 2     2 0 95 state $check = Type::Params::compile( Str, Optional [Int] );
20              
21 2         42826 my $class = shift;
22 2         8 my ( $expr, $level ) = $check->(@_);
23 2   100     37 $level //= 0;
24              
25             my $captures = {
26 5     5   15 pairmap { $a => $b }
27 2         9 ( %{ peek_our( $level + 1 ) }, %{ peek_my( $level + 1 ) } )
  2         21  
  2         29  
28             };
29              
30 2         33 my $self = bless {
31             expr => $expr,
32             captures => $captures,
33             caller => [ caller($level) ],
34             }, $class;
35 2         8 return $self;
36             }
37              
38              
39 4     4 1 25 sub expr { $_[0]->{expr} }
40 4     4 1 39 sub captures { $_[0]->{captures} }
41 4     4 1 8 sub caller { $_[0]->{caller} }
42              
43              
44             sub eval {
45 4     4 1 20 state $check = Type::Params::compile( Optional [HashRef] );
46              
47 4         2439 my $self = shift;
48 4         11 my ($additional_captures) = $check->(@_);
49 4   50     67 $additional_captures //= {};
50              
51             my $captures =
52 4     6   6 { %{ $self->captures }, pairmap { $a => \$b } %$additional_captures };
  4         10  
  6         20  
53 4         17 my $caller = $self->caller;
54              
55 4         9 my $coderef = quote_sub(
56             undef,
57             $self->expr,
58             $captures,
59             {
60             no_install => 1, # do not install the function
61             package => $caller->[0],
62             file => $caller->[1],
63             line => $caller->[2],
64              
65             # Without below it would get error with Function::Parameters
66             # https://rt.cpan.org/Public/Bug/Display.html?id=122698
67             hintshash => undef,
68             }
69             );
70              
71 4         287 my @rslt;
72 4 50       12 if (wantarray) {
    50          
73 0         0 @rslt = eval { $coderef->(); };
  0         0  
74             }
75             elsif ( defined wantarray ) {
76 4         4 $rslt[0] = eval { $coderef->(); };
  4         9  
77             }
78             else {
79 0         0 eval { $coderef->(); };
  0         0  
80             }
81 4 50       1886 if ($@) {
82              
83             # Simplify error message as sometimes part of what's come from
84             # Sub::Quote may not be very meaningful to users.
85             # See also https://metacpan.org/source/HAARG/Sub-Quote-2.006003/lib/Sub/Quote.pm#L307
86 0         0 my $msg = $@;
87 0         0 $msg =~ s/.*\d+:.*?[\n]+//ms;
88 0         0 die $msg;
89             }
90 4 50       13 if (wantarray) {
    50          
91 0         0 return @rslt;
92             }
93             elsif ( defined wantarray ) {
94 4         35 return $rslt[0];
95             }
96             else {
97 0           return;
98             }
99             }
100              
101             1;
102              
103             __END__