File Coverage

blib/lib/Constant/Export/Lazy.pm
Criterion Covered Total %
statement 126 127 99.2
branch 66 66 100.0
condition 20 26 76.9
subroutine 17 18 94.4
pod n/a
total 229 237 96.6


line stmt bran cond sub pod time code
1             package Constant::Export::Lazy;
2             BEGIN {
3 7     7   34300 $Constant::Export::Lazy::AUTHORITY = 'cpan:AVAR';
4             }
5             {
6             $Constant::Export::Lazy::VERSION = '0.15';
7             }
8 7     7   169 use 5.006;
  7         16  
9 7     7   21 use strict;
  7         7  
  7         112  
10 7     7   20 use warnings;
  7         5  
  7         149  
11 7     7   17 use warnings FATAL => "recursion";
  7         8  
  7         1011  
12              
13             our $_CALL_SHOULD_ALIAS_FROM_TO = {};
14              
15             sub import {
16 14     14   1069 my ($class, %args) = @_;
17 14         25 my $caller = caller;
18              
19             # Are we wrapping an existing import subroutine?
20             my $wrap_existing_import = (
21             exists $args{options}
22             ? exists $args{options}->{wrap_existing_import}
23             ? $args{options}->{wrap_existing_import}
24             : undef
25             : undef
26 14 100       38 );
    100          
27 14         101 my $existing_import = $caller->can("import");
28              
29             # Sanity check whether we do or don't have an existing 'import'
30             # sub with the wrap_existing_import option:
31 14 100       24 if ($wrap_existing_import) {
32 4 100       18 die "PANIC: We need an existing 'import' with the wrap_existing_import option" unless $existing_import;
33             } else {
34 10 100       27 die "PANIC: We're trying to clobber an existing 'import' subroutine without having the 'wrap_existing_import' option" if $existing_import;
35             }
36              
37             # Munge the %args we're given so users can be lazy and give sub {
38             # ... } as the value for the constants, but internally we support
39             # them being a HashRef with options for each one. Allows us to be
40             # lazy later by flattening this whole thing now.
41 12         28 my $normalized_args = _normalize_arguments(%args);
42 10         13 my $constants = $normalized_args->{constants};
43              
44             # This is a callback that can be used to munge the import list, to
45             # e.g. provide a facility to provide import tags.
46             my $buildargs = (
47             exists $args{options}
48             ? exists $args{options}->{buildargs}
49             ? $args{options}->{buildargs}
50             : undef
51             : undef
52 10 100       28 );
    100          
53              
54 7     7   25 no strict 'refs';
  7         7  
  7         181  
55 7     7   22 no warnings 'redefine'; # In case of $wrap_existing_import
  7         8  
  7         241  
56 10         35 *{$caller . '::import'} = sub {
57 7     7   19 use strict;
  7         5  
  7         110  
58 7     7   18 use warnings;
  7         7  
  7         4960  
59              
60 21     21   47890 my (undef, @gimme) = @_;
61 21         32 my $pkg_importer = caller;
62              
63 21         101 my $ctx = bless {
64             constants => $constants,
65             pkg_importer => $pkg_importer,
66              
67             # Note that when unpacking @_ above we threw away the
68             # package we're imported as from the user's perspective
69             # and are using our "real" calling package for $pkg_stash
70             # instead.
71             #
72             # This is because if we have a My::Constants package as
73             # $caller but someone subclasses My::Constants for
74             # whatever reason as say My::Constants::Subclass we don't
75             # want to be sticking generated subroutines in both the
76             # My::Constants and My::Constants::Subclass namespaces.
77             #
78             # This is because we want to guarantee that we only ever
79             # call each generator subroutine once, even in the face of
80             # subclassing. Maybe I should lift this restriction or
81             # make it an option, e.g. if you want to have a constant
82             # for "when I was compiled" it would be useful if
83             # subclassing actually re-generated constants.
84             pkg_stash => $caller,
85              
86             # If we're not wrapping an existing import subroutine we
87             # don't need to bend over backwards to support constants
88             # generated by e.g. constant.pm, we know we've made all
89             # the constants in the package to our liking.
90             wrap_existing_import => $wrap_existing_import,
91             } => 'Constant::Export::Lazy::Ctx';
92              
93             # We've been provided with a callback to be used to munge
94             # whatever we actually got provided with in @gimme to a list
95             # of constants, or if $wrap_existing_import is enabled any
96             # leftover non-$gimme names it's going to handle.
97 21 100       57 if ($buildargs) {
98 4         6 my @overriden_gimme = $buildargs->(\@gimme, $constants);
99 4 100       152 die "PANIC: We only support subs that return zero or one values with buildargs, yours returns " . @overriden_gimme . " values"
100             if @overriden_gimme > 1;
101 3 100       12 @gimme = @{$overriden_gimme[0]} if @overriden_gimme;
  2         9  
102             }
103              
104             # Just doing ->call() like you would when you're using the API
105             # will fleshen the constant, do this for all the constants
106             # we've been requested to export.
107 20         24 my @leftover_gimme;
108 20         29 for my $gimme (@gimme) {
109 106 100       166 if (exists $constants->{$gimme}) {
    100          
110             # We only want to alias constants into the importer's
111             # package if the constant is on the import list, not
112             # if it's just needed within some $ctx->call() when
113             # defining another constant.
114             #
115             # To disambiguate these two cases we maintain a
116             # globally dynamically scoped variable with the
117             # constants that have been requested, and we note
118             # who've they've been requested by.
119 98         140 local $_CALL_SHOULD_ALIAS_FROM_TO->{$pkg_importer}->{$gimme} = undef;
120              
121 98         128 $ctx->call($gimme);
122             } elsif ($wrap_existing_import) {
123             # We won't even die on $wrap_existing_import if that
124             # importer doesn't know about this $gimme, but
125             # hopefully they're just about to die with an error
126             # similar to ours if they don't know about the
127             # requested constant.
128 7         10 push @leftover_gimme => $gimme;
129             } else {
130 1         9 die "PANIC: We don't have the constant '$gimme' to export to you";
131             }
132             }
133              
134 16 100 100     55 if ($wrap_existing_import and @leftover_gimme) {
135             # Because if we want to eliminate a stack frame *AND* only
136             # dispatch to this for some things we have to partition
137             # the import list into shit we can handle and shit we
138             # can't. The list of things we're making the function
139             # we're overriding handle is @leftover_gimme.
140 4         9 @_ = ($caller, @leftover_gimme);
141 4         1521 goto &$existing_import;
142             }
143              
144 12         2372 return;
145 10         43 };
146              
147 10         287 return;
148             }
149              
150             sub _normalize_arguments {
151 12     12   21 my (%args) = @_;
152              
153 12 100       12 my %default_options = %{ $args{options} || {} };
  12         60  
154 12         17 my $constants = $args{constants};
155 12         10 my %new_constants;
156 12         31 for my $constant_name (keys %$constants) {
157 102         72 my $value = $constants->{$constant_name};
158 102 100       140 if (ref $value eq 'CODE') {
    100          
159 61         112 $new_constants{$constant_name} = {
160             call => $value,
161             options => \%default_options,
162             };
163             } elsif (ref $value eq 'HASH') {
164             $new_constants{$constant_name} = {
165             call => $value->{call},
166             options => {
167             %default_options,
168 39 100       34 %{ $value->{options} || {} },
  39         143  
169             },
170             };
171             } else {
172 2   100     20 die sprintf "PANIC: The constant <$constant_name> has some value type we don't know about (ref = %s)",
173             ref $value || 'Undef';
174             }
175             }
176              
177 10         16 $args{constants} = \%new_constants;
178              
179 10         19 return \%args;
180             }
181              
182             our $_GETTING_VALUE_FOR_OVERRIDE = {};
183              
184             sub Constant::Export::Lazy::Ctx::call {
185 227     227   646 my ($ctx, $gimme) = @_;
186              
187             # Unpack our options
188 227         241 my $pkg_importer = $ctx->{pkg_importer};
189 227         167 my $pkg_stash = $ctx->{pkg_stash};
190 227         146 my $constants = $ctx->{constants};
191 227         147 my $wrap_existing_import = $ctx->{wrap_existing_import};
192              
193             # Unless we're wrapping an existing import ->call($gimme) should
194             # always be called with a $gimme that we know about.
195 227 100       318 unless (exists $constants->{$gimme}) {
196 18 100       30 die "PANIC: You're trying to get the value of an unknown constant ($gimme), and wrap_existing_import isn't set" unless $wrap_existing_import;
197             }
198              
199 226         142 my ($private_name, $glob_name, $alias_as);
200             my $make_private_glob_and_alias_name = sub {
201             # Checking "exists $constants->{$gimme}" here to avoid
202             # autovivification would be redundant since we won't call this
203             # if $wrap_existing_import is true, otherwise
204             # $constants->{$gimme} is guaranteed to exist. See the
205             # assertion just a few lines above this code.
206             #
207             # If $wrap_existing_import is true and we're handling a
208             # constant we don't know about we'll have called the import()
209             # we're wrapping, or we're being called from ->call(), in
210             # which case we won't be calling this sub unless
211             # $constants->{$gimme} exists.
212             $private_name = exists $constants->{$gimme}->{options}->{private_name_munger}
213 209 100   209   303 ? $constants->{$gimme}->{options}->{private_name_munger}->($gimme)
214             : $gimme;
215 209 100       219 $private_name = defined $private_name ? $private_name : $gimme;
216 209         293 $glob_name = "${pkg_stash}::${private_name}";
217 209         191 $alias_as = "${pkg_importer}::${gimme}";
218 209         151 return;
219 226         501 };
220              
221 226         159 my $value;
222 226 100 100     478 if ($wrap_existing_import and not exists $constants->{$gimme}) {
    100          
223             # This is in case $ctx->call() is used on a constant defined
224             # by constant.pm. See the giant comment about constant.pm
225             # below.
226 17 100       78 if (my $code = $pkg_stash->can($gimme)) {
227 16         26 my @value = $code->();
228 16 100       52 die "PANIC: We only support subs that return one value with wrap_existing_import, $gimme returns " . @value . " values" if @value > 1;
229 14         14 $value = $value[0];
230             } else {
231 1         8 die "PANIC: We're trying to fallback to a constant we don't know about under wrap_existing_import, but $gimme has no symbol table entry";
232             }
233             } elsif (do {
234             # Check if this is a constant we've defined already, in which
235             # case we can just return its value.
236             #
237             # If we got this far we know we're going to want to call
238             # $make_private_glob_and_alias_name->(). It'll also be used by
239             # the "else" branch below if we end up having to define this
240             # constant.
241 209         226 $make_private_glob_and_alias_name->();
242              
243 209         643 $pkg_stash->can($private_name);
244             }) {
245             # This is for constants that *we've* previously defined, we'll
246             # always use our own $private_name.
247 6         15 $value = $pkg_stash->can($private_name)->();
248             } else {
249 203         193 my $override = $constants->{$gimme}->{options}->{override};
250 203         168 my $stash = $constants->{$gimme}->{options}->{stash};
251              
252             # Only pass the stash around if we actually have it. Note that
253             # "delete local $ctx->{stash}" is a feature new in 5.12.0, so
254             # we can't use it. See
255             # http://perldoc.perl.org/5.12.0/perldelta.html#delete-local
256 203         196 local $ctx->{stash} = $stash;
257 203 100       311 delete $ctx->{stash} unless ref $stash;
258              
259 203         119 my @overriden_value;
260             my $source;
261 203 100 66     364 if ($override and
      100        
262             not (exists $_GETTING_VALUE_FOR_OVERRIDE->{$pkg_importer} and
263             exists $_GETTING_VALUE_FOR_OVERRIDE->{$pkg_importer}->{$gimme})) {
264 27         30 local $_GETTING_VALUE_FOR_OVERRIDE->{$pkg_importer}->{$gimme} = undef;
265 27         38 @overriden_value = $override->($ctx, $gimme);
266             }
267 203 100       353 if (@overriden_value) {
268 7 100       21 die "PANIC: We should only get one value returned from the override callback" if @overriden_value > 1;
269              
270             # This whole single value as an array business is so we
271             # can distinguish between "return;" meaning "I don't want
272             # to override this" and "return undef;" meaning "I want to
273             # override this, to undef".
274 6         650 $source = 'override';
275 6         8 $value = $overriden_value[0];
276             } else {
277 196         146 $source = 'callback';
278 196         483 $value = $constants->{$gimme}->{call}->($ctx);
279             }
280              
281 102 100 66     405 unless (exists $_GETTING_VALUE_FOR_OVERRIDE->{$pkg_importer} and
282             exists $_GETTING_VALUE_FOR_OVERRIDE->{$pkg_importer}->{$gimme}) {
283             # Instead of doing `sub () { $value }` we could also
284             # use the following trick that constant.pm uses if
285             # it's true that `$] > 5.009002`:
286             #
287             # Internals::SvREADONLY($value, 1);
288             # my $stash = \%{"$pkg_stash::"};
289             # $stash->{$gimme} = \$value;
290             #
291             # This would save some space for perl when producing
292             # these inline constants. The reason I'm not doing
293             # this is basically because it looks like evil
294             # sorcery, and I don't want to go through the hassle
295             # of efficiently and portibly invalidating the MRO
296             # cache (see $flush_mro in constant.pm).
297             #
298             # Relevant commits in perl.git:
299             #
300             # * perl-5.005_02-225-g779c5bc - first core support
301             # for these kinds of constants in the optree.
302             #
303             # * perl-5.9.2-1966-ge040ff7 - first use in constant.pm.
304             #
305             # * perl-5.9.2-1981-ge1234d8 - first attempts to
306             # invalidate the method cache with
307             # Internals::inc_sub_generation()
308             #
309             # * perl-5.9.4-1684-ge1a479c -
310             # Internals::inc_sub_generation() in constant.pm
311             # replaced with mro::method_changed_in($pkg)
312             #
313             # * perl-5.9.4-1714-g41892db - Now unused
314             # Internals::inc_sub_generation() removed from the
315             # core.
316             #
317             # * v5.10.0-3508-gf7fd265 (and v5.10.0-3523-g81a8de7)
318             # - MRO cache is changed to be flushed after all
319             # constants are defined.
320             #
321             # * v5.19.2-130-g94d5c17, v5.19.2-132-g6f1b3ab,
322             # v5.19.2-133-g15635cb, v5.19.2-134-gf815dc1 -
323             # Father Chrysostomos making various list constant
324             # changes, backed out in v5.19.2-204-gf99a5f0 due to
325             # perl #119045:
326             # https://rt.perl.org/rt3/Public/Bug/Display.html?id=119045
327             #
328             # So basically it looks like a huge can of worms that
329             # I don't want to touch now. So just create constants
330             # in the more portable and idiot-proof way instead so
331             # I don't have to duplicate all the logic in
332             # constant.pm
333             {
334             # Make the disabling of strict have as small as scope
335             # as possible.
336 7     7   30 no strict 'refs';
  7         12  
  7         895  
  97         66  
337              
338             # Future-proof against changes in perl that might not
339             # optimize the constant sub if $value is used
340             # elsewhere, we're passing it to the $after function
341             # just below. See the "Is it time to separate pad
342             # names from SVs?" thread on perl5-porters.
343 97         77 my $value_copy = $value;
344 97     0   493 *$glob_name = sub () { $value_copy };
  0         0  
345             }
346              
347             # Maybe we have a callback that wants to know when we define
348             # our constants, e.g. for printing something out, keeping taps
349             # of what constants we have etc.
350 97 100       217 if (my $after = $constants->{$gimme}->{options}->{after}) {
351             # Future-proof so we can do something clever with the
352             # return value in the future if we want.
353 26         32 my @ret = $after->($ctx, $gimme, $value, $source);
354 26 100       127 die "PANIC: Don't return anything from 'after' routines" if @ret;
355             }
356             }
357             }
358              
359             # So? What's this entire evil magic about?
360             #
361             # Early on in the history of this module I decided that everything
362             # that needed to call or define a constant would just go through
363             # $ctx->call($gimme), including things called via the import().
364             #
365             # This makes some parts of this module much simpler, since we
366             # don't have e.g. a $ctx->call_and_intern($gimme) to define
367             # constants for the first time, v.s. a
368             # $ctx->get_interned_value($gimme). We just have one
369             # $ctx->call($gimme) that DWYM. You just request a value, it does
370             # the right thing, and you don't have to worry about it.
371             #
372             # However, we have to worry about the following cases:
373             #
374             # * Someone in "user" imports YourExporter::CONSTANT, we define
375             # YourExporter::CONSTANT and alias user::CONSTANT to it. Easy,
376             # this is the common case.
377             #
378             # * Ditto, but YourExporter::CONSTANT needs to get the value of
379             # YourExporter::CONSTANT_NESTED to define its own value, we want
380             # to export YourExporter::CONSTANT to user::CONSTANT but *NOT*
381             # YourExporter::CONSTANT_NESTED. We don't want to leak dependent
382             # constants like that.
383             #
384             # * The "user" imports YourExporter::CONSTANT, this in turns needs
385             # to call Some::Module::function() and Some::Module::function()
386             # needs YourExporter::UNRELATED_CONSTANT
387             #
388             # * When we're in the "override" callback for
389             # YourExporter::CONSTANT we don't want to intern
390             # YourExporter::CONSTANT, but if we call some unrelated
391             # YourExporter::ANOTHER_CONSTANT while in the override we want
392             # to intern (but not export!) that value.
393             #
394             # So to do all this we're tracking on a per importer/constant pair
395             # basis who requested what during import()-time, and whether we're
396             # currently in the scope of an "override" for a given constant.
397 121 100 66     489 if (not (exists $_GETTING_VALUE_FOR_OVERRIDE->{$pkg_importer} and
      66        
      33        
398             exists $_GETTING_VALUE_FOR_OVERRIDE->{$pkg_importer}->{$gimme}) and
399             exists $_CALL_SHOULD_ALIAS_FROM_TO->{$pkg_importer} and
400             exists $_CALL_SHOULD_ALIAS_FROM_TO->{$pkg_importer}->{$gimme}) {
401 7     7   27 no strict 'refs';
  7         7  
  7         955  
402             # Alias e.g. user::CONSTANT to YourExporter::CONSTANT (well,
403             # actually YourExporter::$private_name)
404 95         312 *$alias_as = \&$glob_name;
405             }
406              
407 121         384 return $value;
408             }
409              
410             sub Constant::Export::Lazy::Ctx::stash {
411 9     9   25 my ($ctx) = @_;
412              
413             # We used to die here when no $ctx->{stash} existed, but that
414             # makes e.g. having a global "after" callback tedious. Just return
415             # undef instead so we can do things like:
416             #
417             # if (defined(my $stash = $ctx->stash)) { ... }
418             #
419 9         15 return $ctx->{stash};
420             }
421              
422             1;
423              
424             __END__