File Coverage

inc/Sub/Uplevel.pm
Criterion Covered Total %
statement 36 60 60.0
branch 8 24 33.3
condition 2 11 18.1
subroutine 7 8 87.5
pod 1 1 100.0
total 54 104 51.9


line stmt bran cond sub pod time code
1             #line 1
2             package Sub::Uplevel;
3 1     1   29  
  1         4  
  1         42  
4 1     1   6 use 5.006;
  1         2  
  1         63  
5             use strict;
6             our $VERSION = '0.2002';
7             $VERSION = eval $VERSION;
8              
9 1     1   5 sub import {
  1         2  
  1         852  
10 1     1   2 no strict 'refs';
11 1         3 my ($class, @args) = @_;
12 1 50       5 for my $fcn ( @args ) {
13 0         0 if ( $fcn ne 'uplevel' ) {
14             die qq{"$fcn" is not exported by the $class module\n}
15             }
16 1         3 }
17 1         3 my $caller = caller(0);
  1         5  
18 1         29 *{"$caller\::uplevel"} = \&uplevel;
19             return;
20             }
21              
22             # We must override *CORE::GLOBAL::caller if it hasn't already been
23             # overridden or else Perl won't see our local override later.
24              
25             if ( not defined *CORE::GLOBAL::caller{CODE} ) {
26             *CORE::GLOBAL::caller = \&_normal_caller;
27             }
28              
29              
30             #line 96
31              
32             # @Up_Frames -- uplevel stack
33             # $Caller_Proxy -- whatever caller() override was in effect before uplevel
34             our (@Up_Frames, $Caller_Proxy);
35              
36             sub _apparent_stack_height {
37             my $height = 1; # start above this function
38             while ( 1 ) {
39             last if ! defined scalar $Caller_Proxy->($height);
40             $height++;
41             }
42             return $height - 1; # subtract 1 for this function
43             }
44              
45             sub uplevel {
46             my($num_frames, $func, @args) = @_;
47            
48             # backwards compatible version of "no warnings 'redefine'"
49             my $old_W = $^W;
50             $^W = 0;
51              
52             # Update the caller proxy if the uplevel override isn't in effect
53             local $Caller_Proxy = *CORE::GLOBAL::caller{CODE}
54             if *CORE::GLOBAL::caller{CODE} != \&_uplevel_caller;
55             local *CORE::GLOBAL::caller = \&_uplevel_caller;
56            
57             # restore old warnings state
58             $^W = $old_W;
59              
60             if ( $num_frames >= _apparent_stack_height() ) {
61             require Carp;
62             Carp::carp("uplevel $num_frames is more than the caller stack");
63             }
64              
65             local @Up_Frames = ($num_frames, @Up_Frames );
66            
67             return $func->(@args);
68             }
69              
70             sub _normal_caller (;$) { ## no critic Prototypes
71             my $height = $_[0];
72             $height++;
73             if ( CORE::caller() eq 'DB' ) {
74             # passthrough the @DB::args trick
75             package DB;
76             if( wantarray and !@_ ) {
77             return (CORE::caller($height))[0..2];
78             }
79             else {
80             return CORE::caller($height);
81             }
82             }
83             else {
84             if( wantarray and !@_ ) {
85             return (CORE::caller($height))[0..2];
86             }
87             else {
88             return CORE::caller($height);
89             }
90             }
91             }
92              
93             sub _uplevel_caller (;$) { ## no critic Prototypes
94             my $height = $_[0] || 0;
95              
96             # shortcut if no uplevels have been called
97             # always add +1 to CORE::caller (proxy caller function)
98             # to skip this function's caller
99             return $Caller_Proxy->( $height + 1 ) if ! @Up_Frames;
100              
101             #line 215
102 7     7   10  
103 7         9 my $saw_uplevel = 0;
104 35 100       157 my $adjust = 0;
105 28         35  
106             # walk up the call stack to fight the right package level to return;
107 7         23 # look one higher than requested for each call to uplevel found
108             # and adjust by the amount found in the Up_Frames stack for that call.
109             # We *must* use CORE::caller here since we need the real stack not what
110             # some other override says the stack looks like, just in case that other
111 7     7 1 11 # override breaks things in some horrible way
112              
113             for ( my $up = 0; $up <= $height + $adjust; $up++ ) {
114 7         22 my @caller = CORE::caller($up + 1);
115 7         11 if( defined $caller[0] && $caller[0] eq __PACKAGE__ ) {
116             # add one for each uplevel call seen
117             # and look into the uplevel stack for the offset
118 7 50       35 $adjust += 1 + $Up_Frames[$saw_uplevel];
119             $saw_uplevel++;
120 7         18 }
121             }
122              
123 7         8 # For returning values, we pass through the call to the proxy caller
124             # function, just at a higher stack level
125 7 50       19 my @caller;
126 0         0 if ( CORE::caller() eq 'DB' ) {
127 0         0 # passthrough the @DB::args trick
128             package DB;
129             @caller = $Sub::Uplevel::Caller_Proxy->($height + $adjust + 1);
130 7         20 }
131             else {
132 7         27 @caller = $Caller_Proxy->($height + $adjust + 1);
133             }
134              
135             if( wantarray ) {
136 9     9   59469 if( !@_ ) {
137 9         15 @caller = @caller[0..2];
138 9 50       26 }
139             return @caller;
140             }
141 0 0 0     0 else {
142 0         0 return $caller[0];
143             }
144             }
145 0         0  
146             #line 327
147              
148             1;