File Coverage

blib/lib/Module/Runtime.pm
Criterion Covered Total %
statement 54 54 100.0
branch 32 34 94.1
condition 8 12 66.6
subroutine 15 15 100.0
pod 9 9 100.0
total 118 124 95.1


line stmt bran cond sub pod time code
1             package Module::Runtime;
2              
3             # Don't "use 5.006" here, because Perl 5.15.6 will load feature.pm if
4             # the version check is done that way.
5 11     11   1702720 BEGIN { require 5.006; }
6             # Don't "use warnings" here, to avoid dependencies. Do standardise the
7             # warning status by lexical override; unfortunately the only safe bitset
8             # to build in is the empty set, equivalent to "no warnings".
9 11     11   12346 BEGIN { ${^WARNING_BITS} = ""; }
10             # Don't "use strict" here, to avoid dependencies.
11              
12             our $VERSION = '0.018';
13              
14             # Don't use Exporter here, to avoid dependencies.
15             our @EXPORT_OK = qw(
16             $module_name_rx is_module_name is_valid_module_name check_module_name
17             module_notional_filename require_module
18             use_module use_package_optimistically
19             $top_module_spec_rx $sub_module_spec_rx
20             is_module_spec is_valid_module_spec check_module_spec
21             compose_module_name
22             );
23             my %export_ok = map { ($_ => undef) } @EXPORT_OK;
24             sub import {
25 15     15   2351 my $me = shift;
26 15         43 my $callpkg = caller;
27 15         90 my $errs = "";
28 15         67 foreach(@_) {
29 26 100       89 if(exists $export_ok{$_}) {
30             # We would need to do "no strict 'refs'" here
31             # if we had enabled strict at file scope.
32 22 100       72 if(/\A\$(.*)\z/s) {
33 3         13 *{$callpkg."::".$1} = \$$1;
  3         22  
34             } else {
35 19         45 *{$callpkg."::".$_} = \&$_;
  19         110  
36             }
37             } else {
38 4         12 $errs .= "\"$_\" is not exported by the $me module\n";
39             }
40             }
41 15 100       369 if($errs ne "") {
42 3         68 die sprintf "%sCan't continue after import errors at %s line %u.\n",
43             $errs, (caller)[1,2];
44             }
45             }
46              
47             # Logic duplicated from Params::Classify. Duplicating it here avoids
48             # an extensive and potentially circular dependency graph.
49             sub _is_string($) {
50 307     307   535 my($arg) = @_;
51 307   100     4391 return defined($arg) && ref(\$arg) eq "SCALAR";
52             }
53              
54             our $module_name_rx = qr{[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*};
55              
56             my $qual_module_spec_rx =
57             qr{(?:/|::)[A-Z_a-z][0-9A-Z_a-z]*(?:(?:/|::)[0-9A-Z_a-z]+)*};
58              
59             my $unqual_top_module_spec_rx =
60             qr{[A-Z_a-z][0-9A-Z_a-z]*(?:(?:/|::)[0-9A-Z_a-z]+)*};
61              
62             our $top_module_spec_rx = qr{$qual_module_spec_rx|$unqual_top_module_spec_rx};
63              
64             my $unqual_sub_module_spec_rx = qr{[0-9A-Z_a-z]+(?:(?:/|::)[0-9A-Z_a-z]+)*};
65              
66             our $sub_module_spec_rx = qr{$qual_module_spec_rx|$unqual_sub_module_spec_rx};
67              
68 151 100   151 1 255784 sub is_module_name($) { _is_string($_[0]) && $_[0] =~ /\A$module_name_rx\z/o }
69              
70             *is_valid_module_name = \&is_module_name;
71              
72             sub check_module_name($) {
73 134 100   134 1 268 unless(&is_module_name) {
74 12 100       30 die +(_is_string($_[0]) ? "`$_[0]'" : "argument").
75             " is not a module name\n";
76             }
77             }
78              
79             sub module_notional_filename($) {
80 109     109 1 166272 &check_module_name;
81 109         280 my($name) = @_;
82 109         380 $name =~ s{::}{/}g;
83 109         16917 return $name.".pm";
84             }
85              
86             # Don't "use constant" here, to avoid dependencies.
87             BEGIN {
88             ## no critic (ValuesAndExpressions::ProhibitMismatchedOperators)
89             *_WORK_AROUND_HINT_LEAKAGE =
90             "$]" < 5.011 && !("$]" >= 5.009004 && "$]" < 5.010001)
91 11 50 33 11   143 ? sub(){1} : sub(){0};
92 11 50       741 *_WORK_AROUND_BROKEN_MODULE_STATE = "$]" < 5.009 ? sub(){1} : sub(){0};
93             }
94              
95             BEGIN {
96 11     11   8443 if(_WORK_AROUND_BROKEN_MODULE_STATE) {
97             eval <<'END_CODE' or die $@; ## no critic (BuiltinFunctions::ProhibitStringyEval)
98             sub Module::Runtime::__GUARD__::DESTROY {
99             delete $INC{$_[0]->[0]} if @{$_[0]};
100             }
101             1;
102             END_CODE
103             }
104             }
105              
106             sub require_module($) {
107             # Localise %^H to work around [perl #68590], where the bug exists
108             # and this is a satisfactory workaround. The bug consists of
109             # %^H state leaking into each required module, polluting the
110             # module's lexical state.
111 68     68 1 477176 local %^H if _WORK_AROUND_HINT_LEAKAGE;
112 68         96 if(_WORK_AROUND_BROKEN_MODULE_STATE) {
113             my $notional_filename = &module_notional_filename;
114             my $guard = bless([ $notional_filename ],
115             "Module::Runtime::__GUARD__");
116             my $result = CORE::require($notional_filename);
117             pop @$guard;
118             return $result;
119             } else {
120 68         147 return scalar(CORE::require(&module_notional_filename));
121             }
122             }
123              
124             sub use_module($;$) {
125 17     17 1 266738 my($name, $version) = @_;
126 17         55 require_module($name);
127 13 100       43160 $name->VERSION($version) if @_ >= 2;
128 12         164 return $name;
129             }
130              
131             my $FILE = __FILE__;
132             sub use_package_optimistically($;$) {
133 37     37 1 270902 my($name, $version) = @_;
134 37         100 my $fn = module_notional_filename($name);
135             eval {
136 37         145 local $SIG{__DIE__};
137 37         90 require_module($name);
138 22         72133 1;
139 37 100       75 } or do {
140 15 100 66     1399 die $@ if (
141             $@ !~ /\ACan't locate \Q$fn\E .+ at \Q$FILE\E line/s ||
142             $@ =~ /^Compilation\ failed\ in\ require\ at\ \Q$FILE\E\ line/xm
143             );
144             };
145 24 100       192 $name->VERSION($version) if @_ >= 2;
146 22         267 return $name;
147             }
148              
149             sub is_module_spec($$) {
150 116     116 1 233353 my($prefix, $spec) = @_;
151 116   66     210 return _is_string($spec) && (
152             $prefix ? $spec =~ /\A$sub_module_spec_rx\z/o
153             : $spec =~ /\A$top_module_spec_rx\z/o
154             );
155             }
156              
157             *is_valid_module_spec = \&is_module_spec;
158              
159             sub check_module_spec($$) {
160 66 100   66 1 117 unless(&is_module_spec) {
161 28 100       55 die +(_is_string($_[1]) ? "`$_[1]'" : "argument").
162             " is not a module specification\n";
163             }
164             }
165              
166             sub compose_module_name($$) {
167 16     16 1 231474 my($prefix, $spec) = @_;
168 16 100       108 check_module_name($prefix) if defined $prefix;
169 16         46 &check_module_spec;
170 16 100       77 if($spec =~ s{\A(?:/|::)}{}) {
171             # OK
172             } else {
173 8 100       23 $spec = $prefix."::".$spec if defined $prefix;
174             }
175 16         49 $spec =~ s{/}{::}g;
176 16         87 return $spec;
177             }
178              
179             1;
180              
181             __END__