File Coverage

blib/lib/Sub/Replace.pm
Criterion Covered Total %
statement 25 26 96.1
branch 5 10 50.0
condition 1 3 33.3
subroutine 6 6 100.0
pod 1 1 100.0
total 38 46 82.6


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