File Coverage

blib/lib/Moo/_Utils.pm
Criterion Covered Total %
statement 141 150 94.0
branch 54 68 79.4
condition 25 38 65.7
subroutine 30 31 96.7
pod n/a
total 250 287 87.1


line stmt bran cond sub pod time code
1             package Moo::_Utils;
2 228     228   1173768 use strict;
  228         459  
  228         6452  
3 228     228   1199 use warnings;
  228         461  
  228         6140  
4              
5             {
6 228     228   1129 no strict 'refs';
  228         466  
  228         6053  
7 228     228   1120 no warnings 'once';
  228         491  
  228         104729  
8 8506     8506   10481 sub _getglob { \*{$_[0]} }
  8506         39916  
9 1796     1796   5343 sub _getstash { \%{"$_[0]::"} }
  1796         7291  
10             }
11              
12             BEGIN {
13 228     228   1095 my ($su, $sn);
14             $su = $INC{'Sub/Util.pm'} && defined &Sub::Util::set_subname
15             or $sn = $INC{'Sub/Name.pm'}
16             or $su = eval { require Sub::Util; } && defined &Sub::Util::set_subname
17 228 100 66     3210 or $sn = eval { require Sub::Name; };
  4   66     193  
      66        
      100        
18              
19             *_subname = $su ? \&Sub::Util::set_subname
20             : $sn ? \&Sub::Name::subname
21 228 100   2   32221 : sub { $_[1] };
  2 100       211  
22 228 100 100     1062 *_CAN_SUBNAME = ($su || $sn) ? sub(){1} : sub(){0};
23              
24 228 50       1438 *_WORK_AROUND_BROKEN_MODULE_STATE = "$]" < 5.009 ? sub(){1} : sub(){0};
25             *_WORK_AROUND_HINT_LEAKAGE
26             = "$]" < 5.011 && !("$]" >= 5.009004 && "$]" < 5.010001)
27 228 50 33     1320 ? sub(){1} : sub(){0};
28              
29 228         1303 my $module_name_rx = qr/\A(?!\d)\w+(?:::\w+)*\z/;
30 228         6108 *_module_name_rx = sub(){$module_name_rx};
  0         0  
31             }
32              
33 228     228   1484 use Exporter ();
  228         522  
  228         5852  
34 228     228   4015 BEGIN { *import = \&Exporter::import }
35 228     228   1265 use Config ();
  228         492  
  228         4944  
36 228     228   1264 use Scalar::Util qw(weaken);
  228         464  
  228         12610  
37 228     228   1542 use Carp qw(croak);
  228         486  
  228         163848  
38              
39             # this should be empty, but some CPAN modules expect these
40             our @EXPORT = qw(
41             _install_coderef
42             _load_module
43             );
44              
45             our @EXPORT_OK = qw(
46             _check_tracked
47             _getglob
48             _getstash
49             _install_coderef
50             _install_modifier
51             _install_tracked
52             _load_module
53             _maybe_load_module
54             _module_name_rx
55             _name_coderef
56             _set_loaded
57             _unimport_coderefs
58             _linear_isa
59             _in_global_destruction
60             _in_global_destruction_code
61             );
62              
63             my %EXPORTS;
64              
65             sub _install_modifier {
66 68     68   332 my $target = $_[0];
67 68         108 my $type = $_[1];
68 68         105 my $code = $_[-1];
69 68         264 my @names = @_[2 .. $#_ - 1];
70              
71 68 100       227 @names = @{ $names[0] }
  2         6  
72             if ref($names[0]) eq 'ARRAY';
73              
74 68         201 my @tracked = _check_tracked($target, \@names);
75              
76 68 100       223 if ($INC{'Sub/Defer.pm'}) {
77 60         114 for my $name (@names) {
78             # CMM will throw for us if it doesn't exist
79 62 100       440 if (my $to_modify = $target->can($name)) {
80 60         221 Sub::Defer::undefer_sub($to_modify);
81             }
82             }
83             }
84              
85 68         14920 require Class::Method::Modifiers;
86 68         38258 Class::Method::Modifiers::install_modifier(@_);
87              
88 66 100       17083 if (@tracked) {
89 6         16 my $exports = $EXPORTS{$target};
90             weaken($exports->{$_} = $target->can($_))
91 6         53 for @tracked;
92             }
93              
94 66         3151 return;
95             }
96              
97             sub _install_tracked {
98 5772     5772   10373 my ($target, $name, $code) = @_;
99 5772         8634 my $from = caller;
100 5772         16688 weaken($EXPORTS{$target}{$name} = $code);
101 5772         15351 _install_coderef("${target}::${name}", "${from}::${name}", $code);
102             }
103              
104             sub Moo::_Util::__GUARD__::DESTROY {
105 0 0   0   0 delete $INC{$_[0]->[0]} if @{$_[0]};
  0         0  
106             }
107              
108             sub _require {
109 174     174   534 my ($file) = @_;
110 174         345 my $guard = _WORK_AROUND_BROKEN_MODULE_STATE
111             && bless([ $file ], 'Moo::_Util::__GUARD__');
112 174         277 local %^H if _WORK_AROUND_HINT_LEAKAGE;
113 174 100       427 if (!eval { require $file; 1 }) {
  174         59507  
  106         257839  
114 68   33     6643 my $e = $@ || "Can't locate $file";
115 68         134 my $me = __FILE__;
116 68         1204 $e =~ s{ at \Q$me\E line \d+\.\n\z}{};
117 68         449 return $e;
118             }
119 106         256 pop @$guard if _WORK_AROUND_BROKEN_MODULE_STATE;
120 106         340 return undef;
121             }
122              
123             sub _load_module {
124 606     606   11280 my ($module) = @_;
125 606 100       4487 croak qq{"$module" is not a module name!}
126             unless $module =~ _module_name_rx;
127 604         2277 (my $file = "$module.pm") =~ s{::}{/}g;
128             return 1
129 604 100       2247 if $INC{$file};
130              
131 76         211 my $e = _require $file;
132 76 100       306 return 1
133             if !defined $e;
134              
135 64 100       1577 croak $e
136             if $e !~ /\ACan't locate \Q$file\E /;
137              
138             # can't just ->can('can') because a sub-package Foo::Bar::Baz
139             # creates a 'Baz::' key in Foo::Bar's symbol table
140 60   50     231 my $stash = _getstash($module)||{};
141 228     228   1953 no strict 'refs';
  228         535  
  228         95241  
142 60 100       334 return 1 if grep +exists &{"${module}::$_"}, grep !/::\z/, keys %$stash;
  102         421  
143             return 1
144 12 100 66     166 if $INC{"Moose.pm"} && Class::MOP::class_of($module)
      33        
      66        
145             or Mouse::Util->can('find_meta') && Mouse::Util::find_meta($module);
146              
147 10         1528 croak $e;
148             }
149              
150             our %MAYBE_LOADED;
151             sub _maybe_load_module {
152 100     100   6033 my $module = $_[0];
153             return $MAYBE_LOADED{$module}
154 100 100       457 if exists $MAYBE_LOADED{$module};
155 98         734 (my $file = "$module.pm") =~ s{::}{/}g;
156              
157 98         429 my $e = _require $file;
158 98 100       479 if (!defined $e) {
    100          
159 94         979 return $MAYBE_LOADED{$module} = 1;
160             }
161             elsif ($e !~ /\ACan't locate \Q$file\E /) {
162 2         21 warn "$module exists but failed to load with error: $e";
163             }
164 4         33 return $MAYBE_LOADED{$module} = 0;
165             }
166              
167             BEGIN {
168             # optimize for newer perls
169             require mro
170 228 50   228   2952 if "$]" >= 5.009_005;
171              
172 228 50       1257 if (defined &mro::get_linear_isa) {
173 228         22328 *_linear_isa = \&mro::get_linear_isa;
174             }
175             else {
176 0         0 my $e;
177             {
178 0         0 local $@;
  0         0  
179 0 0       0 eval <<'END_CODE' or $e = $@;
180             sub _linear_isa($;$) {
181             my $class = shift;
182             my $type = shift || exists $Class::C3::MRO{$class} ? 'c3' : 'dfs';
183              
184             if ($type eq 'c3') {
185             require Class::C3;
186             return [Class::C3::calculateMRO($class)];
187             }
188              
189             my @check = ($class);
190             my @lin;
191              
192             my %found;
193             while (defined(my $check = shift @check)) {
194             push @lin, $check;
195             no strict 'refs';
196             unshift @check, grep !$found{$_}++, @{"$check\::ISA"};
197             }
198              
199             return \@lin;
200             }
201              
202             1;
203             END_CODE
204             }
205 0 0       0 die $e if defined $e;
206             }
207             }
208              
209             BEGIN {
210 228 0   228   2062 my $gd_code
    50          
211             = "$]" >= 5.014
212             ? q[${^GLOBAL_PHASE} eq 'DESTRUCT']
213             : _maybe_load_module('Devel::GlobalDestruction::XS')
214             ? 'Devel::GlobalDestruction::XS::in_global_destruction()'
215             : 'do { use B (); ${B::main_cv()} == 0 }';
216 228         2664 *_in_global_destruction_code = sub () { $gd_code };
  0         0  
217 228 50   52   20285 eval "sub _in_global_destruction () { $gd_code }; 1"
  52         627  
218             or die $@;
219             }
220              
221             sub _set_loaded {
222 1026     1026   4864 (my $file = "$_[0].pm") =~ s{::}{/}g;
223 1026   66     6389 $INC{$file} ||= $_[1];
224             }
225              
226             sub _install_coderef {
227 5782     5782   9362 my ($glob, $code) = (_getglob($_[0]), _name_coderef(@_));
228 228     228   2198 no warnings 'redefine';
  228         604  
  228         14038  
229 5782 100       8631 if (*{$glob}{CODE}) {
  5782         10874  
230 24         31 *{$glob} = $code;
  24         80  
231             }
232             # perl will sometimes warn about mismatched prototypes coming from the
233             # inheritance cache, so disable them if we aren't redefining a sub
234             else {
235 228     228   2660 no warnings 'prototype';
  228         2146  
  228         76231  
236 5758         6604 *{$glob} = $code;
  5758         19169  
237             }
238             }
239              
240             sub _name_coderef {
241 5916 100   5916   12435 shift if @_ > 2; # three args is (target, name, sub)
242 5916         25134 _CAN_SUBNAME ? _subname(@_) : $_[1];
243             }
244              
245             sub _check_tracked {
246 538     538   1385 my ($target, $names) = @_;
247 538         1310 my $stash = _getstash($target);
248 538 100       2200 my $exports = $EXPORTS{$target}
249             or return;
250              
251 310 100       1015 $names = [keys %$exports]
252             if !$names;
253             my %rev =
254             map +($exports->{$_} => $_),
255 310         4225 grep defined $exports->{$_},
256             keys %$exports;
257              
258             return
259             grep {
260 310         1043 my $g = $stash->{$_};
  2304         4732  
261 2304 100 100     13042 $g && defined &$g && exists $rev{\&$g};
262             }
263             @$names;
264             }
265              
266             sub _unimport_coderefs {
267 26     26   62 my ($target) = @_;
268              
269 26         123 my $stash = _getstash($target);
270 26         76 my @exports = _check_tracked($target);
271              
272 26         150 foreach my $name (@exports) {
273 112         226 my $old = delete $stash->{$name};
274 112         246 my $full_name = join('::',$target,$name);
275             # Copy everything except the code slot back into place (e.g. $has)
276 112         164 foreach my $type (qw(SCALAR HASH ARRAY IO)) {
277 448 100       508 next unless defined(*{$old}{$type});
  448         5764  
278 228     228   2445 no strict 'refs';
  228         1145  
  228         24445  
279 112         168 *$full_name = *{$old}{$type};
  112         754  
280             }
281             }
282             }
283              
284             if ($Config::Config{useithreads}) {
285             require Moo::HandleMoose::_TypeMap;
286             }
287              
288             1;