File Coverage

blib/lib/autodie/Util.pm
Criterion Covered Total %
statement 75 76 98.6
branch 20 22 90.9
condition 2 3 66.6
subroutine 11 11 100.0
pod 4 4 100.0
total 112 116 96.5


line stmt bran cond sub pod time code
1             package autodie::Util;
2              
3 59     59   229 use strict;
  59         71  
  59         1857  
4 59     59   213 use warnings;
  59         63  
  59         1921  
5              
6 59     59   215 use Exporter 5.57 qw(import);
  59         1397  
  59         1695  
7              
8 59     59   20952 use autodie::Scope::GuardStack;
  59         95  
  59         36260  
9              
10             our @EXPORT_OK = qw(
11             fill_protos
12             install_subs
13             make_core_trampoline
14             on_end_of_compile_scope
15             );
16              
17             our $VERSION = '2.28'; # VERSION: Generated by DZP::OurPkg:Version
18              
19             # ABSTRACT: Internal Utility subroutines for autodie and Fatal
20              
21             # docs says we should pick __PACKAGE__ /<whatever>
22             my $H_STACK_KEY = __PACKAGE__ . '/stack';
23              
24             sub on_end_of_compile_scope {
25 138     138 1 192 my ($hook) = @_;
26              
27             # Dark magic to have autodie work under 5.8
28             # Copied from namespace::clean, that copied it from
29             # autobox, that found it on an ancient scroll written
30             # in blood.
31              
32             # This magic bit causes %^H to be lexically scoped.
33 138         994 $^H |= 0x020000;
34              
35 138         256 my $stack = $^H{$H_STACK_KEY};
36 138 100       318 if (not defined($stack)) {
37 110         602 $stack = autodie::Scope::GuardStack->new;
38 110         702 $^H{$H_STACK_KEY} = $stack;
39             }
40              
41 138         421 $stack->push_hook($hook);
42 138         213 return;
43             }
44              
45             # This code is based on code from the original Fatal. The "XXXX"
46             # remark is from the original code and its meaning is (sadly) unknown.
47             sub fill_protos {
48 181     181 1 3782 my ($proto) = @_;
49 181         335 my ($n, $isref, @out, @out1, $seen_semi) = -1;
50 181 100       822 if ($proto =~ m{^\s* (?: [;] \s*)? \@}x) {
51             # prototype is entirely slurply - special case that does not
52             # require any handling.
53 60         206 return ([0, '@_']);
54             }
55              
56 121         560 while ($proto =~ /\S/) {
57 393         356 $n++;
58 393 100       731 push(@out1,[$n,@out]) if $seen_semi;
59 393 100       790 push(@out, $1 . "{\$_[$n]}"), next if $proto =~ s/^\s*\\([\@%\$\&])//;
60 380 100       1616 push(@out, "\$_[$n]"), next if $proto =~ s/^\s*([_*\$&])//;
61 116 100       477 push(@out, "\@_[$n..\$#_]"), last if $proto =~ s/^\s*(;\s*)?\@//;
62 68 50       417 $seen_semi = 1, $n--, next if $proto =~ s/^\s*;//; # XXXX ????
63 0         0 die "Internal error: Unknown prototype letters: \"$proto\"";
64             }
65 121         311 push(@out1,[$n+1,@out]);
66 121         392 return @out1;
67             }
68              
69              
70             sub make_core_trampoline {
71 4     4 1 8 my ($call, $pkg, $proto_str) = @_;
72 4         4 my $trampoline_code = 'sub {';
73 4         4 my $trampoline_sub;
74 4         9 my @protos = fill_protos($proto_str);
75              
76 4         9 foreach my $proto (@protos) {
77 8         10 local $" = ", "; # So @args is formatted correctly.
78 8         13 my ($count, @args) = @$proto;
79 8 100 66     40 if (@args && $args[-1] =~ m/[@#]_/) {
80 3         17 $trampoline_code .= qq/
81             if (\@_ >= $count) {
82             return $call(@args);
83             }
84             /;
85             } else {
86 5         25 $trampoline_code .= qq<
87             if (\@_ == $count) {
88             return $call(@args);
89             }
90             >;
91             }
92             }
93              
94 4         7 $trampoline_code .= qq< require Carp; Carp::croak("Internal error in Fatal/autodie. Leak-guard failure"); } >;
95 4         3 my $E;
96              
97             {
98 4         4 local $@;
  4         4  
99 4         530 $trampoline_sub = eval "package $pkg;\n $trampoline_code"; ## no critic
100 4         8 $E = $@;
101             }
102 4 50       16 die "Internal error in Fatal/autodie: Leak-guard installation failure: $E"
103             if $E;
104              
105 4         15 return $trampoline_sub;
106             }
107              
108             # The code here is originally lifted from namespace::clean,
109             # by Robert "phaylon" Sedlacek.
110             #
111             # It's been redesigned after feedback from ikegami on perlmonks.
112             # See http://perlmonks.org/?node_id=693338 . Ikegami rocks.
113             #
114             # Given a package, and hash of (subname => subref) pairs,
115             # we install the given subroutines into the package. If
116             # a subref is undef, the subroutine is removed. Otherwise
117             # it replaces any existing subs which were already there.
118              
119             sub install_subs {
120 278     278 1 356 my ($target_pkg, $subs_to_reinstate) = @_;
121              
122 278         430 my $pkg_sym = "${target_pkg}::";
123              
124             # It does not hurt to do this in a predictable order, and might help debugging.
125 278         364 foreach my $sub_name (sort keys(%{$subs_to_reinstate})) {
  278         3299  
126              
127             # We will repeatedly mess with stuff that strict "refs" does
128             # not like. So lets just disable it once for this entire
129             # scope.
130 59     59   325 no strict qw(refs); ## no critic
  59         92  
  59         3453  
131              
132 6467         6273 my $sub_ref = $subs_to_reinstate->{$sub_name};
133              
134 6467         7444 my $full_path = ${pkg_sym}.${sub_name};
135 6467         10970 my $oldglob = *$full_path;
136              
137             # Nuke the old glob.
138 6467         8121 delete($pkg_sym->{$sub_name});
139              
140             # For some reason this local *alias = *$full_path triggers an
141             # "only used once" warning. Not entirely sure why, but at
142             # least it is easy to silence.
143 59     59   270 no warnings qw(once);
  59         73  
  59         3035  
144 6467         11205 local *alias = *$full_path;
145 59     59   599 use warnings qw(once);
  59         81  
  59         5823  
146              
147             # Copy innocent bystanders back. Note that we lose
148             # formats; it seems that Perl versions up to 5.10.0
149             # have a bug which causes copying formats to end up in
150             # the scalar slot. Thanks to Ben Morrow for spotting this.
151              
152 6467         5887 foreach my $slot (qw( SCALAR ARRAY HASH IO ) ) {
153 25868 100       46415 next unless defined(*$oldglob{$slot});
154 6473         9152 *alias = *$oldglob{$slot};
155             }
156              
157 6467 100       10758 if ($sub_ref) {
158 3660         6490 *$full_path = $sub_ref;
159             }
160             }
161              
162 278         890 return;
163             }
164              
165             1;
166              
167             __END__
168              
169             =head1 NAME
170              
171             autodie::Util - Internal Utility subroutines for autodie and Fatal
172              
173             =head1 SYNOPSIS
174              
175             # INTERNAL API for autodie and Fatal only!
176              
177             use autodie::Util qw(on_end_of_compile_scope);
178             on_end_of_compile_scope(sub { print "Hallo world\n"; });
179              
180             =head1 DESCRIPTION
181              
182             Interal Utilities for autodie and Fatal! This module is not a part of
183             autodie's public API.
184              
185             This module contains utility subroutines for abstracting away the
186             underlying magic of autodie and (ab)uses of C<%^H> to call subs at the
187             end of a (compile-time) scopes.
188              
189             Note that due to how C<%^H> works, some of these utilities are only
190             useful during the compilation phase of a perl module and relies on the
191             internals of how perl handles references in C<%^H>.
192              
193             =head2 Methods
194              
195             =head3 on_end_of_compile_scope
196              
197             on_end_of_compile_scope(sub { print "Hallo world\n"; });
198              
199             Will invoke a sub at the end of a (compile-time) scope. The sub is
200             called once with no arguments. Can be called multiple times (even in
201             the same "compile-time" scope) to install multiple subs. Subs are
202             called in a "first-in-last-out"-order (FILO or "stack"-order).
203              
204             =head3 fill_protos
205              
206             fill_protos('*$$;$@')
207              
208             Given a Perl subroutine prototype, return a list of invocation
209             specifications. Each specification is a listref, where the first
210             member is the (minimum) number of arguments for this invocation
211             specification. The remaining arguments are a string representation of
212             how to pass the arguments correctly to a sub with the given prototype,
213             when called with the given number of arguments.
214              
215             The specifications are returned in increasing order of arguments
216             starting at 0 (e.g. ';$') or 1 (e.g. '$@'). Note that if the
217             prototype is "slurpy" (e.g. ends with a "@"), the number of arguments
218             for the last specification is a "minimum" number rather than an exact
219             number. This can be detected by the last member of the last
220             specification matching m/[@#]_/.
221              
222             =head3 make_core_trampoline
223              
224             make_core_trampoline('CORE::open', 'main', prototype('CORE::open'))
225              
226             Creates a trampoline for calling a core sub. Essentially, a tiny sub
227             that figures out how we should be calling our core sub, puts in the
228             arguments in the right way, and bounces our control over to it.
229              
230             If we could reliably use `goto &` on core builtins, we wouldn't need
231             this subroutine.
232              
233             =head3 install_subs
234              
235             install_subs('My::Module', { 'read' => sub { die("Hallo\n"), ... }})
236              
237             Given a package name and a hashref mapping names to a subroutine
238             reference (or C<undef>), this subroutine will install said subroutines
239             on their given name in that module. If a name mapes to C<undef>, any
240             subroutine with that name in the target module will be remove
241             (possibly "unshadowing" a CORE sub of same name).
242              
243             =head1 AUTHOR
244              
245             Copyright 2013-2014, Niels Thykier E<lt>niels@thykier.netE<gt>
246              
247             =head1 LICENSE
248              
249             This module is free software. You may distribute it under the
250             same terms as Perl itself.