File Coverage

blib/lib/Sub/Replace.pm
Criterion Covered Total %
statement 22 22 100.0
branch 9 10 90.0
condition 2 3 66.6
subroutine 5 5 100.0
pod 1 1 100.0
total 39 41 95.1


line stmt bran cond sub pod time code
1              
2             package Sub::Replace;
3             $Sub::Replace::VERSION = '0.2.0';
4             # ABSTRACT: Replace subroutines in packages with controlled effects
5              
6 3     3   150953 use 5.010001;
  3         31  
7              
8             our @EXPORT_OK = qw(sub_replace);
9              
10 3     3   21 use Carp ();
  3         6  
  3         67  
11 3     3   1346 use Sub::Delete 1.00002 ();
  3         3036  
  3         789  
12              
13             sub sub_replace {
14 9 100 66 9 1 274 @_ = %{ $_[0] } if @_ == 1 && ref $_[0] eq 'HASH';
  2         11  
15 9         37 goto &_sub_replace;
16             }
17              
18             sub _sub_replace {
19 9 50   9   30 Carp::croak "Odd number of elements in sub_replace" if @_ % 2;
20              
21 9         25 my $caller = caller;
22              
23 9         17 my %old;
24 9         42 while ( my ( $name, $sub ) = splice @_, 0, 2 ) {
25              
26 9 100       57 ( my $stashname, $name )
27             = $name =~ /(.*::)((?:(?!::).)*)\z/s
28             ? ( $1, $2 )
29             : ( $caller . "::", $name );
30              
31 9         25 my $fullname = "${stashname}${name}";
32              
33 9 100       55 $old{$fullname} = exists &$fullname ? \&$fullname : undef;
34 9         38 Sub::Delete::delete_sub $fullname;
35 9 100       1189 *{$fullname} = $sub if defined $sub;
  7         60  
36             }
37              
38 9         3538 return \%old;
39             }
40              
41             1;
42              
43             #pod =encoding utf8
44             #pod
45             #pod =head1 SYNOPSIS
46             #pod
47             #pod use Sub::Replace;
48             #pod
49             #pod sub one { say 'One' }
50             #pod
51             #pod one(); # One
52             #pod
53             #pod BEGIN { Sub::Replace::sub_replace('one', sub { say 'Uno' }); }
54             #pod
55             #pod one(); # Uno
56             #pod
57             #pod BEGIN { Sub::Replace::sub_replace('one', sub { say 'Eins' }); }
58             #pod
59             #pod one(); # Eins
60             #pod
61             #pod =head1 DESCRIPTION
62             #pod
63             #pod In Perl, replacing a subroutine in a symbol table is as easy as doing:
64             #pod
65             #pod *TargetPackage::target_sub = sub { ... };
66             #pod
67             #pod However that may cause a lot of trouble for compiled code
68             #pod with mentions to C<\&target_sub>. For example,
69             #pod
70             #pod sub one { say 'One' }
71             #pod one();
72             #pod BEGIN { *one = sub { say 'Uno' }; }
73             #pod one();
74             #pod BEGIN { *one = sub { say 'Eins' }; }
75             #pod one();
76             #pod
77             #pod will not output
78             #pod
79             #pod One
80             #pod Uno
81             #pod Eins
82             #pod
83             #pod but
84             #pod
85             #pod Eins
86             #pod Eins
87             #pod Eins
88             #pod
89             #pod This module provides a C function to address that.
90             #pod
91             #pod =head1 FUNCTIONS
92             #pod
93             #pod L implements the following functions, which are exportable.
94             #pod
95             #pod =head2 sub_replace
96             #pod
97             #pod $old = Sub::Replace::sub_replace($name, $code);
98             #pod $old = Sub::Replace::sub_replace($name1, $code1, $name2, $code2);
99             #pod $old = Sub::Replace::sub_replace(\%subs);
100             #pod
101             #pod The sub name may be fully qualified (eg. C<'TargetPackage::target_sub'>) or not
102             #pod (like C<'target_sub'>). In the latter case, the caller package will be used.
103             #pod
104             #pod The return is a hash ref which maps the fully qualified names into
105             #pod the previously installed subroutines (or C if none were there).
106             #pod This is suitable to undo a previous C by calling
107             #pod
108             #pod Sub::Replace::sub_replace($old);
109             #pod
110             #pod =head1 CAVEATS
111             #pod
112             #pod The same as mentioned in L, namely:
113             #pod you may be surprised by taking references to globs in between
114             #pod calls to C.
115             #pod
116             #pod =head1 SEE ALSO
117             #pod
118             #pod L
119             #pod
120             #pod =cut
121              
122             __END__