File Coverage

blib/lib/Sub/Defer.pm
Criterion Covered Total %
statement 109 109 100.0
branch 52 54 100.0
condition 49 63 77.7
subroutine 22 22 100.0
pod 5 5 100.0
total 237 253 94.4


line stmt bran cond sub pod time code
1             package Sub::Defer;
2 14     14   514043 use strict;
  14         64  
  14         354  
3 14     14   58 use warnings;
  14         24  
  14         319  
4 14     14   55 use Exporter qw(import);
  14         24  
  14         379  
5 14     14   62 use Scalar::Util qw(weaken);
  14         39  
  14         804  
6 14     14   68 use Carp qw(croak);
  14         20  
  14         1529  
7              
8             our $VERSION = '2.006006';
9             $VERSION = eval $VERSION;
10              
11             our @EXPORT = qw(defer_sub undefer_sub undefer_all);
12             our @EXPORT_OK = qw(undefer_package defer_info);
13              
14 14     14   77 sub _getglob { no strict 'refs'; \*{$_[0]} }
  14     84   26  
  14         2518  
  84         83  
  84         328  
15              
16             BEGIN {
17 14     14   44 my $no_subname;
18             *_subname
19             = defined &Sub::Util::set_subname ? \&Sub::Util::set_subname
20             : defined &Sub::Name::subname ? \&Sub::Name::subname
21             : (eval { require Sub::Util } && defined &Sub::Util::set_subname) ? \&Sub::Util::set_subname
22             : (eval { require Sub::Name } && defined &Sub::Name::subname ) ? \&Sub::Name::subname
23 14 100 66 31   66 : ($no_subname = 1, sub { $_[1] });
  1 100 66     615  
    100          
    100          
24 14 100       3017 *_CAN_SUBNAME = $no_subname ? sub(){0} : sub(){1};
25             }
26              
27             sub _name_coderef {
28 26 100   26   52 shift if @_ > 2; # three args is (target, name, sub)
29 26         132 _CAN_SUBNAME ? _subname(@_) : $_[1];
30             }
31              
32             sub _install_coderef {
33 26     26   1101 my ($glob, $code) = (_getglob($_[0]), _name_coderef(@_));
34 14     14   82 no warnings 'redefine';
  14         23  
  14         821  
35 26 100       37 if (*{$glob}{CODE}) {
  26         55  
36 3         6 *{$glob} = $code;
  3         36  
37             }
38             # perl will sometimes warn about mismatched prototypes coming from the
39             # inheritance cache, so disable them if we aren't redefining a sub
40             else {
41 14     14   79 no warnings 'prototype';
  14         26  
  14         2366  
42 23         23 *{$glob} = $code;
  23         54  
43             }
44             }
45              
46             # We are dealing with three subs. The first is the generator sub. It is
47             # provided by the user, so we cannot modify it. When called, it generates the
48             # undeferred sub. This is also created, so it also cannot be modified. These
49             # are wrapped in a third sub. The deferred sub is generated by us, and when
50             # called it uses the generator sub to create the undeferred sub. If it is a
51             # named sub, it is installed in the symbol table, usually overwriting the
52             # deferred sub. From then on, the deferred sub will goto the undeferred sub
53             # if it is called.
54             #
55             # In %DEFERRED we store array refs with information about these subs. The key
56             # is the stringified subref. We have a CLONE method to fix this up in the
57             # case of threading to deal with changing refaddrs. The arrayrefs contain:
58             #
59             # 0. fully qualified sub name (or undef)
60             # 1. generator sub
61             # 2. options (attributes)
62             # 3. scalar ref to undeferred sub (inner reference weakened)
63             # 4. deferred sub (deferred only)
64             # 5. info arrayref for undeferred sub (deferred only, after undefer)
65             #
66             # The deferred sub contains a strong reference to its info arrayref, and the
67             # undeferred.
68              
69             our %DEFERRED;
70              
71             sub undefer_sub {
72 98     98 1 3815 my ($deferred) = @_;
73 98 100       253 my $info = $DEFERRED{$deferred} or return $deferred;
74 86         175 my ($target, $maker, $options, $undeferred_ref, $deferred_sub) = @$info;
75              
76 86 100 66     275 if (!(
      66        
      100        
77             $deferred_sub && $deferred eq $deferred_sub
78 14         32 || ${$undeferred_ref} && $deferred eq ${$undeferred_ref}
  12         33  
79             )) {
80 2         4 return $deferred;
81             }
82              
83 22         57 return ${$undeferred_ref}
84 84 100       94 if ${$undeferred_ref};
  84         140  
85 62         394 ${$undeferred_ref} = my $made = $maker->();
  61         181  
86              
87             # make sure the method slot has not changed since deferral time
88 61 100 100     186 if (defined($target) && $deferred eq *{_getglob($target)}{CODE}||'') {
  30   100     45  
89 14     14   84 no warnings 'redefine';
  14         31  
  14         8319  
90              
91             # I believe $maker already evals with the right package/name, so that
92             # _install_coderef calls are not necessary --ribasushi
93 28         38 *{_getglob($target)} = $made;
  28         36  
94             }
95 61         123 my $undefer_info = [ $target, $maker, $options, $undeferred_ref ];
96 61         166 $info->[5] = $DEFERRED{$made} = $undefer_info;
97 61         71 weaken ${$undefer_info->[3]};
  61         146  
98              
99 61         191 return $made;
100             }
101              
102             sub undefer_all {
103 2     2 1 1441 undefer_sub($_) for keys %DEFERRED;
104 2         4 return;
105             }
106              
107             sub undefer_package {
108 4     4 1 24 my $package = shift;
109             undefer_sub($_)
110 4         14 for grep {
111 62   100     140 my $name = $DEFERRED{$_} && $DEFERRED{$_}[0];
112 62 100       266 $name && $name =~ /^${package}::[^:]+$/
113             } keys %DEFERRED;
114 4         10 return;
115             }
116              
117             sub defer_info {
118 26     26 1 4594 my ($deferred) = @_;
119 26 100 100     106 my $info = $DEFERRED{$deferred||''} or return undef;
120              
121 18         37 my ($target, $maker, $options, $undeferred_ref, $deferred_sub) = @$info;
122 18 100 66     57 if (!(
      66        
      66        
123             $deferred_sub && $deferred eq $deferred_sub
124 12         25 || ${$undeferred_ref} && $deferred eq ${$undeferred_ref}
  6         21  
125             )) {
126 6         11 delete $DEFERRED{$deferred};
127 6         35 return undef;
128             }
129             [
130 12 100 66     86 $target, $maker, $options,
131             ( $undeferred_ref && $$undeferred_ref ? $$undeferred_ref : ()),
132             ];
133             }
134              
135             sub defer_sub {
136 98     98 1 27736 my ($target, $maker, $options) = @_;
137 98         138 my $package;
138             my $subname;
139 98 100 66     812 ($package, $subname) = $target =~ /^(.*)::([^:]+)$/
140             or croak "$target is not a fully qualified sub name!"
141             if $target;
142 95   66     783 $package ||= $options && $options->{package} || caller;
      66        
143 95 100 100     100 my @attributes = @{$options && $options->{attributes} || []};
  95         374  
144 95 100       190 if (@attributes) {
145             /\A\w+(?:\(.*\))?\z/s || croak "invalid attribute $_"
146 7   66     246 for @attributes;
147             }
148 93         125 my $deferred;
149             my $undeferred;
150 93         163 my $deferred_info = [ $target, $maker, $options, \$undeferred ];
151 93 100 100     305 if (@attributes || $target && !_CAN_SUBNAME) {
      100        
152 15 100       110 my $code
    100          
153             = q[#line ].(__LINE__+2).q[ "].__FILE__.qq["\n]
154             . qq[package $package;\n]
155             . ($target ? "sub $subname" : '+sub') . join('', map " :$_", @attributes)
156             . q[ {
157             package Sub::Defer;
158             # uncoverable subroutine
159             # uncoverable statement
160             $undeferred ||= undefer_sub($deferred_info->[4]);
161             goto &$undeferred; # uncoverable statement
162             $undeferred; # fake lvalue return
163             }]."\n"
164             . ($target ? "\\&$subname" : '');
165 15         20 my $e;
166 15         18 $deferred = do {
167 14     14   119 no warnings qw(redefine closure);
  14         24  
  14         3663  
168 15         25 local $@;
169 15 50       1291 eval $code or $e = $@; # uncoverable branch true
170             };
171 15 50       40 die $e if defined $e; # uncoverable branch true
172             }
173             else {
174             # duplicated from above
175             $deferred = sub {
176 37   66 37   7108 $undeferred ||= undefer_sub($deferred_info->[4]);
177 36         662 goto &$undeferred;
178 78         215 };
179 78 100       163 _install_coderef($target, $deferred)
180             if $target;
181             }
182 93         262 weaken($deferred_info->[4] = $deferred);
183 93         278 weaken($DEFERRED{$deferred} = $deferred_info);
184 93         260 return $deferred;
185             }
186              
187             sub CLONE {
188             %DEFERRED = map {
189 10     10   254 defined $_ ? (
190             $_->[4] ? ($_->[4] => $_)
191 188 100 66     414 : ($_->[3] && ${$_->[3]}) ? (${$_->[3]} => $_)
  86 100       129  
    100          
192             : ()
193             ) : ()
194             } values %DEFERRED;
195             }
196              
197             1;
198             __END__
199              
200             =head1 NAME
201              
202             Sub::Defer - Defer generation of subroutines until they are first called
203              
204             =head1 SYNOPSIS
205              
206             use Sub::Defer;
207              
208             my $deferred = defer_sub 'Logger::time_since_first_log' => sub {
209             my $t = time;
210             sub { time - $t };
211             };
212              
213             Logger->time_since_first_log; # returns 0 and replaces itself
214             Logger->time_since_first_log; # returns time - $t
215              
216             =head1 DESCRIPTION
217              
218             These subroutines provide the user with a convenient way to defer creation of
219             subroutines and methods until they are first called.
220              
221             =head1 SUBROUTINES
222              
223             =head2 defer_sub
224              
225             my $coderef = defer_sub $name => sub { ... }, \%options;
226              
227             This subroutine returns a coderef that encapsulates the provided sub - when
228             it is first called, the provided sub is called and is -itself- expected to
229             return a subroutine which will be goto'ed to on subsequent calls.
230              
231             If a name is provided, this also installs the sub as that name - and when
232             the subroutine is undeferred will re-install the final version for speed.
233              
234             Exported by default.
235              
236             =head3 Options
237              
238             A hashref of options can optionally be specified.
239              
240             =over 4
241              
242             =item package
243              
244             The package to generate the sub in. Will be overridden by a fully qualified
245             C<$name> option. If not specified, will default to the caller's package.
246              
247             =item attributes
248              
249             The L<perlsub/Subroutine Attributes> to apply to the sub generated. Should be
250             specified as an array reference.
251              
252             =back
253              
254             =head2 undefer_sub
255              
256             my $coderef = undefer_sub \&Foo::name;
257              
258             If the passed coderef has been L<deferred|/defer_sub> this will "undefer" it.
259             If the passed coderef has not been deferred, this will just return it.
260              
261             If this is confusing, take a look at the example in the L</SYNOPSIS>.
262              
263             Exported by default.
264              
265             =head2 defer_info
266              
267             my $data = defer_info $sub;
268             my ($name, $generator, $options, $undeferred_sub) = @$data;
269              
270             Returns original arguments to defer_sub, plus the undeferred version if this
271             sub has already been undeferred.
272              
273             Note that $sub can be either the original deferred version or the undeferred
274             version for convenience.
275              
276             Not exported by default.
277              
278             =head2 undefer_all
279              
280             undefer_all();
281              
282             This will undefer all deferred subs in one go. This can be very useful in a
283             forking environment where child processes would each have to undefer the same
284             subs. By calling this just before you start forking children you can undefer
285             all currently deferred subs in the parent so that the children do not have to
286             do it. Note this may bake the behavior of some subs that were intended to
287             calculate their behavior later, so it shouldn't be used midway through a
288             module load or class definition.
289              
290             Exported by default.
291              
292             =head2 undefer_package
293              
294             undefer_package($package);
295              
296             This undefers all deferred subs in a package.
297              
298             Not exported by default.
299              
300             =head1 SUPPORT
301              
302             See L<Sub::Quote> for support and contact information.
303              
304             =head1 AUTHORS
305              
306             See L<Sub::Quote> for authors.
307              
308             =head1 COPYRIGHT AND LICENSE
309              
310             See L<Sub::Quote> for the copyright and license.
311              
312             =cut