File Coverage

blib/lib/Eval/Quosure.pm
Criterion Covered Total %
statement 60 64 93.7
branch 7 10 70.0
condition 4 4 100.0
subroutine 16 16 100.0
pod 4 5 80.0
total 91 99 91.9


line stmt bran cond sub pod time code
1             package Eval::Quosure;
2              
3             # ABSTRACT: Evaluate within a caller environment
4              
5 1     1   177944 use 5.010;
  1         7  
6 1     1   4 use strict;
  1         2  
  1         14  
7 1     1   4 use warnings;
  1         1  
  1         38  
8              
9             our $VERSION = '0.001001'; # VERSION
10              
11 1     1   5 use List::Util 1.28 qw(pairmap);
  1         13  
  1         66  
12 1     1   393 use PadWalker 2.3 qw(peek_my peek_our);
  1         566  
  1         51  
13 1     1   409 use Safe::Isa 1.000009;
  1         454  
  1         129  
14 1     1   426 use Sub::Quote 2.005 qw(quote_sub);
  1         4772  
  1         48  
15 1     1   485 use Type::Params 1.004004;
  1         78013  
  1         7  
16 1     1   315 use Types::Standard qw(Str Int HashRef Optional);
  1         2  
  1         3  
17              
18             sub new {
19 3     3 0 389 state $check = Type::Params::compile( Str, Optional [Int] );
20              
21 3         1897 my $class = shift;
22 3         59 my ( $expr, $level ) = $check->(@_);
23 3   100     47 $level //= 0;
24              
25             my $captures = {
26 8     8   16 pairmap { $a => $b }
27 3         12 ( %{ peek_our( $level + 1 ) }, %{ peek_my( $level + 1 ) } )
  3         25  
  3         21  
28             };
29              
30 3         38 my $self = bless {
31             expr => $expr,
32             captures => $captures,
33             caller => [ caller($level) ],
34             }, $class;
35 3         10 return $self;
36             }
37              
38              
39 5     5 1 29 sub expr { $_[0]->{expr} }
40 5     5 1 40 sub captures { $_[0]->{captures} }
41 5     5 1 10 sub caller { $_[0]->{caller} }
42              
43              
44             sub eval {
45 5     5 1 23 state $check = Type::Params::compile( Optional [HashRef] );
46              
47 5         1179 my $self = shift;
48 5         55 my ($additional_captures) = $check->(@_);
49 5   100     48 $additional_captures //= {};
50              
51             my $captures =
52 5     6   7 { %{ $self->captures }, pairmap { $a => \$b } %$additional_captures };
  5         11  
  6         19  
53 5         17 my $caller = $self->caller;
54              
55 5         10 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 5         333 my @rslt;
72 5 50       15 if (wantarray) {
    100          
73 0         0 @rslt = eval { $coderef->(); };
  0         0  
74             }
75             elsif ( defined wantarray ) {
76 4         5 $rslt[0] = eval { $coderef->(); };
  4         7  
77             }
78             else {
79 1         1 eval { $coderef->(); };
  1         3  
80             }
81 5 100       2367 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 1         3 my $msg = $@;
87 1         14 $msg =~ s/.*\d+:.*?[\n]+//ms;
88 1         11 die $msg;
89             }
90 4 50       12 if (wantarray) {
    50          
91 0         0 return @rslt;
92             }
93             elsif ( defined wantarray ) {
94 4         38 return $rslt[0];
95             }
96             else {
97 0           return;
98             }
99             }
100              
101             1;
102              
103             __END__