File Coverage

blib/lib/Hook/LexWrap.pm
Criterion Covered Total %
statement 82 84 97.6
branch 48 50 96.0
condition 16 17 94.1
subroutine 18 20 90.0
pod 1 1 100.0
total 165 172 95.9


line stmt bran cond sub pod time code
1 2     2   13216 use strict;
  2         2  
  2         45  
2 2     2   6 use warnings;
  2         2  
  2         71  
3             package Hook::LexWrap; # git description: v0.25-14-g33c34e7
4             # vi: noet sts=8 sw=8 ts=8 :
5             # ABSTRACT: Lexically scoped subroutine wrappers
6             # KEYWORDS: subroutine function modifier wrapper lexical scope
7              
8             our $VERSION = '0.26';
9              
10 2     2   6 use Carp ();
  2         1  
  2         34  
11              
12             {
13 2     2   5 no warnings 'redefine';
  2         1  
  2         281  
14             *CORE::GLOBAL::caller = sub (;$) {
15 86   100 86   267 my ($height) = ($_[0]||0);
16 86         54 my $i=1;
17 86         73 my $name_cache;
18 86         54 while (1) {
19             my @caller = CORE::caller() eq 'DB'
20 402 100       928 ? do { package # line break to foil [Git::Describe]
21 96         263 DB; CORE::caller($i++) }
22             : CORE::caller($i++);
23 402 100       576 return if not @caller;
24 390 100       471 $caller[3] = $name_cache if $name_cache;
25 390 100       368 $name_cache = $caller[0] eq 'Hook::LexWrap' ? $caller[3] : '';
26 390 100 100     1034 next if $name_cache || $height-- != 0;
27 74 100       619 return wantarray ? @_ ? @caller : @caller[0..2] : $caller[0];
    100          
28             }
29             };
30             }
31              
32 2     2   7 sub import { no strict 'refs'; *{caller()."::wrap"} = \&wrap }
  2     2   2  
  2         190  
  2         9  
  2         195  
33              
34             sub wrap (*@) { ## no critic Prototypes
35 28     28 1 271 my ($typeglob, %wrapper) = @_;
36 28 100 100     109 $typeglob = (ref $typeglob || $typeglob =~ /::/)
37             ? $typeglob
38             : caller()."::$typeglob";
39 28         19 my $original;
40             {
41 2     2   7 no strict 'refs';
  2         1  
  2         199  
  28         22  
42             $original = ref $typeglob eq 'CODE' && $typeglob
43             || *$typeglob{CODE}
44 28   66     157 || Carp::croak "Can't wrap non-existent subroutine ", $typeglob;
45             }
46             Carp::croak "'$_' value is not a subroutine reference"
47 27 100       25 foreach grep {$wrapper{$_} && ref $wrapper{$_} ne 'CODE'}
  54         165  
48             qw(pre post);
49 2     2   6 no warnings 'redefine';
  2         3  
  2         473  
50 25         28 my ($caller, $unwrap) = *CORE::GLOBAL::caller{CODE};
51             my $imposter = sub {
52 52 100   52   129 if ($unwrap) { goto &$original }
  24         20  
53 28         19 my ($return, $prereturn);
54 28 100       41 if (wantarray) {
    100          
55 11         9 $prereturn = $return = [];
56 11 100       22 () = $wrapper{pre}->(@_,$return) if $wrapper{pre};
57 11 100 100     73 if (ref $return eq 'ARRAY' && $return == $prereturn && !@$return) {
      100        
58 7         9 $return = [ &$original ];
59             () = $wrapper{post}->(@_, $return)
60 7 100       34 if $wrapper{post};
61             }
62 11 100       64 return ref $return eq 'ARRAY' ? @$return : ($return);
63             }
64             elsif (defined wantarray) {
65 4     4   8 $return = bless sub {$prereturn=1}, 'Hook::LexWrap::Cleanup';
  4         14  
66 4 100       9 my $dummy = $wrapper{pre}->(@_, $return) if $wrapper{pre};
67 4 100       16 unless ($prereturn) {
68 3         4 $return = &$original;
69             $dummy = scalar $wrapper{post}->(@_, $return)
70 3 50       9 if $wrapper{post};
71             }
72 4         16 return $return;
73             }
74             else {
75 13     13   28 $return = bless sub {$prereturn=1}, 'Hook::LexWrap::Cleanup';
  13         39  
76 13 100       32 $wrapper{pre}->(@_, $return) if $wrapper{pre};
77 13 50       34 unless ($prereturn) {
78 13         15 &$original;
79             $wrapper{post}->(@_, $return)
80 13 100       49 if $wrapper{post};
81             }
82 13         39 return;
83             }
84 25         62 };
85 25 100       47 ref $typeglob eq 'CODE' and return defined wantarray
    100          
86             ? $imposter
87             : Carp::carp "Uselessly wrapped subroutine reference in void context";
88             {
89 2     2   6 no strict 'refs';
  2         2  
  2         233  
  23         13  
90 23         14 *{$typeglob} = $imposter;
  23         41  
91             }
92 23 100       47 return unless defined wantarray;
93 10     10   37 return bless sub{ $unwrap=1 }, 'Hook::LexWrap::Cleanup';
  10         21  
94             }
95              
96             package # hide from PAUSE
97             Hook::LexWrap::Cleanup;
98              
99 27     27   768 sub DESTROY { $_[0]->() }
100             use overload
101 6     6   49 q{""} => sub { undef },
102 0     0   0 q{0+} => sub { undef },
103 0     0   0 q{bool} => sub { undef },
104 2     2   1810 q{fallback}=>1; #fallback=1 - like no overloading for other operations
  2         1432  
  2         18  
105              
106             1;
107              
108             __END__