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   278 use strict;
  59         84  
  59         2655  
4 59     59   262 use warnings;
  59         86  
  59         2647  
5              
6 59     59   265 use Exporter 5.57 qw(import);
  59         1641  
  59         2072  
7              
8 59     59   24620 use autodie::Scope::GuardStack;
  59         119  
  59         44923  
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.27'; # 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 264 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         266 $^H |= 0x020000;
34              
35 138         322 my $stack = $^H{$H_STACK_KEY};
36 138 100       1598 if (not defined($stack)) {
37 110         840 $stack = autodie::Scope::GuardStack->new;
38 110         1026 $^H{$H_STACK_KEY} = $stack;
39             }
40              
41 138         593 $stack->push_hook($hook);
42 138         240 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 3142 my ($proto) = @_;
49 181         453 my ($n, $isref, @out, @out1, $seen_semi) = -1;
50 181 100       1142 if ($proto =~ m{^\s* (?: [;] \s*)? \@}x) {
51             # prototype is entirely slurply - special case that does not
52             # require any handling.
53 60         1082 return ([0, '@_']);
54             }
55              
56 121         681 while ($proto =~ /\S/) {
57 393         440 $n++;
58 393 100       870 push(@out1,[$n,@out]) if $seen_semi;
59 393 100       1009 push(@out, $1 . "{\$_[$n]}"), next if $proto =~ s/^\s*\\([\@%\$\&])//;
60 380 100       2017 push(@out, "\$_[$n]"), next if $proto =~ s/^\s*([_*\$&])//;
61 116 100       953 push(@out, "\@_[$n..\$#_]"), last if $proto =~ s/^\s*(;\s*)?\@//;
62 68 50       576 $seen_semi = 1, $n--, next if $proto =~ s/^\s*;//; # XXXX ????
63 0         0 die "Internal error: Unknown prototype letters: \"$proto\"";
64             }
65 121         396 push(@out1,[$n+1,@out]);
66 121         499 return @out1;
67             }
68              
69              
70             sub make_core_trampoline {
71 4     4 1 11 my ($call, $pkg, $proto_str) = @_;
72 4         8 my $trampoline_code = 'sub {';
73 4         7 my $trampoline_sub;
74 4         11 my @protos = fill_protos($proto_str);
75              
76 4         10 foreach my $proto (@protos) {
77 8         12 local $" = ", "; # So @args is formatted correctly.
78 8         19 my ($count, @args) = @$proto;
79 8 100 66     51 if (@args && $args[-1] =~ m/[@#]_/) {
80 3         23 $trampoline_code .= qq/
81             if (\@_ >= $count) {
82             return $call(@args);
83             }
84             /;
85             } else {
86 5         34 $trampoline_code .= qq<
87             if (\@_ == $count) {
88             return $call(@args);
89             }
90             >;
91             }
92             }
93              
94 4         9 $trampoline_code .= qq< require Carp; Carp::croak("Internal error in Fatal/autodie. Leak-guard failure"); } >;
95 4         6 my $E;
96              
97             {
98 4         5 local $@;
  4         6  
99 4         684 $trampoline_sub = eval "package $pkg;\n $trampoline_code"; ## no critic
100 4         13 $E = $@;
101             }
102 4 50       29 die "Internal error in Fatal/autodie: Leak-guard installation failure: $E"
103             if $E;
104              
105 4         18 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 469 my ($target_pkg, $subs_to_reinstate) = @_;
121              
122 278         567 my $pkg_sym = "${target_pkg}::";
123              
124             # It does not hurt to do this in a predictable order, and might help debugging.
125 278         342 foreach my $sub_name (sort keys(%{$subs_to_reinstate})) {
  278         4148  
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   787 no strict qw(refs); ## no critic
  59         105  
  59         4285  
131              
132 6467         8159 my $sub_ref = $subs_to_reinstate->{$sub_name};
133              
134 6467         7659 my $full_path = ${pkg_sym}.${sub_name};
135 6467         14784 my $oldglob = *$full_path;
136              
137             # Nuke the old glob.
138 6467         10248 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   322 no warnings qw(once);
  59         80  
  59         3613  
144 6467         14554 local *alias = *$full_path;
145 59     59   783 use warnings qw(once);
  59         81  
  59         6539  
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         7279 foreach my $slot (qw( SCALAR ARRAY HASH IO ) ) {
153 25868 100       56417 next unless defined(*$oldglob{$slot});
154 6473         12579 *alias = *$oldglob{$slot};
155             }
156              
157 6467 100       15815 if ($sub_ref) {
158 3660         8576 *$full_path = $sub_ref;
159             }
160             }
161              
162 278         1253 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.