File Coverage

blib/lib/Constant/Export/Lazy.pm
Criterion Covered Total %
statement 139 140 99.2
branch 68 68 100.0
condition 20 26 76.9
subroutine 19 20 95.0
pod n/a
total 246 254 96.8


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