File Coverage

blib/lib/PerlGuard/Agent/LexWrap.pm
Criterion Covered Total %
statement 38 82 46.3
branch 5 48 10.4
condition 2 17 11.7
subroutine 11 18 61.1
pod 1 1 100.0
total 57 166 34.3


line stmt bran cond sub pod time code
1 1     1   5 use strict;
  1         1  
  1         27  
2 1     1   4 use warnings;
  1         2  
  1         45  
3             package PerlGuard::Agent::LexWrap;
4             # ABSTRACT: Lexically scoped subroutine wrappers
5              
6             our $VERSION = '0.26';
7              
8 1     1   5 use Carp ();
  1         1  
  1         19  
9              
10             {
11 1     1   5 no warnings 'redefine';
  1         2  
  1         213  
12             *CORE::GLOBAL::caller = sub (;$) {
13 4   50 4   127109 my ($height) = ($_[0]||0);
14 4         7 my $i=1;
15 4         4 my $name_cache;
16 4         8 while (1) {
17 4 50       48 my @caller = CORE::caller($i++) or return;
18 4 50       11 $caller[3] = $name_cache if $name_cache;
19 4 50       12 $name_cache = $caller[0] eq 'PerlGuard::Agent::LexWrap' ? $caller[3] : '';
20 4 50 33     19 next if $name_cache || $height-- != 0;
21 4 0       20 return wantarray ? @_ ? @caller : @caller[0..2] : $caller[0];
    50          
22             }
23             };
24             }
25              
26 1     1   6 sub import { no strict 'refs'; *{caller()."::wrap"} = \&wrap }
  1     2   1  
  1         131  
  2         4  
  2         46  
27              
28             sub wrap (*@) { ## no critic Prototypes
29 0     0 1   my ($typeglob, %wrapper) = @_;
30 0 0 0       $typeglob = (ref $typeglob || $typeglob =~ /::/)
31             ? $typeglob
32             : caller()."::$typeglob";
33 0           my $original;
34             {
35 1     1   5 no strict 'refs';
  1         2  
  1         106  
  0            
36             $original = ref $typeglob eq 'CODE' && $typeglob
37             || *$typeglob{CODE}
38 0   0       || Carp::croak "Can't wrap non-existent subroutine ", $typeglob;
39             }
40             Carp::croak "'$_' value is not a subroutine reference"
41 0 0         foreach grep {$wrapper{$_} && ref $wrapper{$_} ne 'CODE'}
  0            
42             qw(pre post);
43 1     1   4 no warnings 'redefine';
  1         2  
  1         382  
44 0           my ($caller, $unwrap) = *CORE::GLOBAL::caller{CODE};
45             my $imposter = sub {
46 0 0   0     if ($unwrap) { goto &$original }
  0            
47 0           my ($return, $prereturn);
48 0 0         if (wantarray) {
    0          
49 0           $prereturn = $return = [];
50 0 0         () = $wrapper{pre}->(\@_,$return) if $wrapper{pre};
51 0 0 0       if (ref $return eq 'ARRAY' && $return == $prereturn && !@$return) {
      0        
52 0           $return = [ &$original ];
53             () = $wrapper{post}->(@_, $return)
54 0 0         if $wrapper{post};
55             }
56 0 0         return ref $return eq 'ARRAY' ? @$return : ($return);
57             }
58             elsif (defined wantarray) {
59 0           $return = bless sub {$prereturn=1}, 'PerlGuard::Agent::LexWrap::Cleanup';
  0            
60 0 0         my $dummy = $wrapper{pre}->(\@_, $return) if $wrapper{pre};
61 0 0         unless ($prereturn) {
62 0           $return = &$original;
63             $dummy = scalar $wrapper{post}->(@_, $return)
64 0 0         if $wrapper{post};
65             }
66 0           return $return;
67             }
68             else {
69 0           $return = bless sub {$prereturn=1}, 'PerlGuard::Agent::LexWrap::Cleanup';
  0            
70 0 0         $wrapper{pre}->(\@_, $return) if $wrapper{pre};
71 0 0         unless ($prereturn) {
72 0           &$original;
73             $wrapper{post}->(@_, $return)
74 0 0         if $wrapper{post};
75             }
76 0           return;
77             }
78 0           };
79 0 0         ref $typeglob eq 'CODE' and return defined wantarray
    0          
80             ? $imposter
81             : Carp::carp "Uselessly wrapped subroutine reference in void context";
82             {
83 1     1   5 no strict 'refs';
  1         2  
  1         161  
  0            
84 0           *{$typeglob} = $imposter;
  0            
85             }
86 0 0         return unless defined wantarray;
87 0     0     return bless sub{ $unwrap=1 }, 'PerlGuard::Agent::LexWrap::Cleanup';
  0            
88             }
89              
90             package PerlGuard::Agent::LexWrap::Cleanup;
91              
92 0     0     sub DESTROY { $_[0]->() }
93             use overload
94 0     0   0 q{""} => sub { undef },
95 0     0   0 q{0+} => sub { undef },
96 0     0   0 q{bool} => sub { undef },
97 1     1   5 q{fallback}=>1; #fallback=1 - like no overloading for other operations
  1         1  
  1         30  
98              
99             1;
100              
101             __END__