File Coverage

blib/lib/constant/defer.pm
Criterion Covered Total %
statement 56 63 88.8
branch 10 14 71.4
condition n/a
subroutine 12 14 85.7
pod n/a
total 78 91 85.7


line stmt bran cond sub pod time code
1             # Copyright 2008, 2009, 2010, 2011, 2012, 2015 Kevin Ryde
2              
3             # This file is part of constant-defer.
4             #
5             # constant-defer is free software; you can redistribute it and/or modify it
6             # under the terms of the GNU General Public License as published by the Free
7             # Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # constant-defer is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with constant-defer. If not, see .
17              
18             package constant::defer;
19 1     1   526 use strict;
  1         2  
  1         40  
20              
21 1     1   3 use vars '$VERSION';
  1         1  
  1         324  
22             $VERSION = 6;
23              
24             sub import {
25 15     15   7682 my $class = shift;
26 15         42 $class->_create_for_package (scalar(caller), @_);
27             }
28             sub _create_for_package {
29 15     15   13 my $class = shift;
30 15         13 my $target_package = shift;
31 15         55 while (@_) {
32 20         20 my $name = shift;
33 20 100       40 if (ref $name eq 'HASH') {
34 2         7 unshift @_, %$name;
35 2         6 next;
36             }
37 18 50       33 unless (@_) {
38 0         0 require Carp;
39 0         0 Carp::croak ("Missing value sub for $name");
40             }
41 18         17 my $subr = shift;
42              
43             ### $constant::defer::DEBUG_LAST_SUBR = $subr;
44              
45 18         15 my ($fullname, $basename);
46 18 100       56 if ($name =~ /::([^:]*)$/s) {
47 1         3 $fullname = $name;
48 1         4 $basename = $1;
49             } else {
50 17         19 $basename = $name;
51 17         28 $fullname = "${target_package}::$name";
52             }
53             ## print "constant::defer $arg -- $fullname $basename $old\n";
54 18         35 $class->_validate_name ($basename);
55 18         28 $class->_create_fullname ($fullname, $subr);
56             }
57             }
58              
59             sub _create_fullname {
60 18     18   27 my ($class, $fullname, $subr) = @_;
61             my $run = sub {
62 17     17   26 unshift @_, $fullname, $subr;
63 17         27 goto &_run;
64 18         78 };
65             my $func = sub () {
66 20     20   1844 unshift @_, \$run;
67 20         42 goto $run;
68 18         45 };
69 1     1   5 no strict 'refs';
  1         4  
  1         111  
70 18         1725 *$fullname = $func;
71              
72             ### $constant::defer::DEBUG_LAST_RUNNER = $run;
73             }
74              
75             sub _run {
76 17     17   17 my $fullname = shift;
77 17         17 my $subr = shift;
78 17         12 my $run_ref = shift;
79             ### print "_run() $fullname $subr\n";
80              
81 17         37 my @ret = &$subr(@_);
82 17 100       68 if (@ret == 1) {
    50          
83             # constant.pm has an optimization to make a constant by storing a scalar
84             # value directly into the %{Foo::Bar::} hash if there's no typeglob for
85             # the name yet. But that doesn't apply here, there's always a glob from
86             # having converted a function.
87             #
88             # The function created only has name __ANON__ in its coderef GV (as
89             # fetched by Sub::Identify for instance). This is the same as most
90             # function creating modules, including Memoize.pm. Plain constant.pm
91             # likewise, except when it uses the scalar ref in symbol table
92             # optimization, in that case a later upgrade to a function gets a name.
93             #
94 14         12 my $value = $ret[0];
95 14     0   83 $subr = sub () { $value };
  0         0  
96              
97             } elsif (@ret == 0) {
98 0         0 $subr = \&_nothing;
99              
100             } else {
101 3     5   8 $subr = sub () { @ret };
  5         129  
102             }
103              
104 17         19 $$run_ref = $subr;
105 1     1   4 { no strict 'refs';
  1         1  
  1         158  
  17         55  
106 17         34 local $^W = 0; # no warnings 'redefine';
107 17 50       15 eval { *$fullname = $subr } or die $@;
  17         85  
108             }
109 17         69 goto $subr;
110             }
111              
112             # not as strict as constant.pm
113             sub _validate_name {
114 18     18   20 my ($class, $name) = @_;
115 18 50       100 if ($name =~ m{[()] # no parens like CODE(0x1234) if miscounted args
116             |^[0-9] # no starting with a number
117             |^$ # not empty
118             }x) {
119 0           require Carp;
120 0           Carp::croak ("Constant name '$name' is invalid");
121             }
122             }
123              
124 0     0     sub _nothing () { } ## no critic (ProhibitSubroutinePrototypes)
125              
126             1;
127             __END__