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   1173912 use strict;
  228         483  
  228         6725  
3 228     228   1218 use warnings;
  228         455  
  228         6580  
4              
5             {
6 228     228   1212 no strict 'refs';
  228         468  
  228         6661  
7 228     228   1195 no warnings 'once';
  228         488  
  228         111539  
8 8506     8506   10568 sub _getglob { \*{$_[0]} }
  8506         41821  
9 1796     1796   4676 sub _getstash { \%{"$_[0]::"} }
  1796         7885  
10             }
11              
12             BEGIN {
13 228     228   1238 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     3231 or $sn = eval { require Sub::Name; };
  4   66     133  
      66        
      100        
18              
19             *_subname = $su ? \&Sub::Util::set_subname
20             : $sn ? \&Sub::Name::subname
21 228 100   2   34342 : sub { $_[1] };
  2 100       184  
22 228 100 100     1122 *_CAN_SUBNAME = ($su || $sn) ? sub(){1} : sub(){0};
23              
24 228 50       1547 *_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     1315 ? sub(){1} : sub(){0};
28              
29 228         1438 my $module_name_rx = qr/\A(?!\d)\w+(?:::\w+)*\z/;
30 228         6350 *_module_name_rx = sub(){$module_name_rx};
  0         0  
31             }
32              
33 228     228   1666 use Exporter ();
  228         521  
  228         6130  
34 228     228   4330 BEGIN { *import = \&Exporter::import }
35 228     228   1341 use Config ();
  228         533  
  228         5323  
36 228     228   1282 use Scalar::Util qw(weaken);
  228         500  
  228         13170  
37 228     228   1586 use Carp qw(croak);
  228         539  
  228         175155  
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   356 my $target = $_[0];
67 68         118 my $type = $_[1];
68 68         124 my $code = $_[-1];
69 68         273 my @names = @_[2 .. $#_ - 1];
70              
71 68 100       297 @names = @{ $names[0] }
  2         7  
72             if ref($names[0]) eq 'ARRAY';
73              
74 68         244 my @tracked = _check_tracked($target, \@names);
75              
76 68 100       243 if ($INC{'Sub/Defer.pm'}) {
77 60         123 for my $name (@names) {
78             # CMM will throw for us if it doesn't exist
79 62 100       535 if (my $to_modify = $target->can($name)) {
80 60         231 Sub::Defer::undefer_sub($to_modify);
81             }
82             }
83             }
84              
85 68         16622 require Class::Method::Modifiers;
86 68         40629 Class::Method::Modifiers::install_modifier(@_);
87              
88 66 100       18781 if (@tracked) {
89 6         16 my $exports = $EXPORTS{$target};
90             weaken($exports->{$_} = $target->can($_))
91 6         49 for @tracked;
92             }
93              
94 66         3334 return;
95             }
96              
97             sub _install_tracked {
98 5772     5772   11035 my ($target, $name, $code) = @_;
99 5772         9183 my $from = caller;
100 5772         17819 weaken($EXPORTS{$target}{$name} = $code);
101 5772         15855 _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   563 my ($file) = @_;
110 174         396 my $guard = _WORK_AROUND_BROKEN_MODULE_STATE
111             && bless([ $file ], 'Moo::_Util::__GUARD__');
112 174         313 local %^H if _WORK_AROUND_HINT_LEAKAGE;
113 174 100       379 if (!eval { require $file; 1 }) {
  174         64249  
  106         274941  
114 68   33     7293 my $e = $@ || "Can't locate $file";
115 68         156 my $me = __FILE__;
116 68         1329 $e =~ s{ at \Q$me\E line \d+\.\n\z}{};
117 68         442 return $e;
118             }
119 106         381 pop @$guard if _WORK_AROUND_BROKEN_MODULE_STATE;
120 106         353 return undef;
121             }
122              
123             sub _load_module {
124 606     606   10406 my ($module) = @_;
125 606 100       4844 croak qq{"$module" is not a module name!}
126             unless $module =~ _module_name_rx;
127 604         2250 (my $file = "$module.pm") =~ s{::}{/}g;
128             return 1
129 604 100       2385 if $INC{$file};
130              
131 76         226 my $e = _require $file;
132 76 100       286 return 1
133             if !defined $e;
134              
135 64 100       1589 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     253 my $stash = _getstash($module)||{};
141 228     228   1950 no strict 'refs';
  228         580  
  228         101958  
142 60 100       393 return 1 if grep +exists &{"${module}::$_"}, grep !/::\z/, keys %$stash;
  102         480  
143             return 1
144 12 100 66     200 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         1721 croak $e;
148             }
149              
150             our %MAYBE_LOADED;
151             sub _maybe_load_module {
152 100     100   5118 my $module = $_[0];
153             return $MAYBE_LOADED{$module}
154 100 100       498 if exists $MAYBE_LOADED{$module};
155 98         790 (my $file = "$module.pm") =~ s{::}{/}g;
156              
157 98         460 my $e = _require $file;
158 98 100       523 if (!defined $e) {
    100          
159 94         981 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         43 return $MAYBE_LOADED{$module} = 0;
165             }
166              
167             BEGIN {
168             # optimize for newer perls
169             require mro
170 228 50   228   3088 if "$]" >= 5.009_005;
171              
172 228 50       1362 if (defined &mro::get_linear_isa) {
173 228         24069 *_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   2202 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         2807 *_in_global_destruction_code = sub () { $gd_code };
  0         0  
217 228 50   52   21433 eval "sub _in_global_destruction () { $gd_code }; 1"
  52         643  
218             or die $@;
219             }
220              
221             sub _set_loaded {
222 1026     1026   5214 (my $file = "$_[0].pm") =~ s{::}{/}g;
223 1026   66     6936 $INC{$file} ||= $_[1];
224             }
225              
226             sub _install_coderef {
227 5782     5782   9815 my ($glob, $code) = (_getglob($_[0]), _name_coderef(@_));
228 228     228   2263 no warnings 'redefine';
  228         638  
  228         14945  
229 5782 100       9268 if (*{$glob}{CODE}) {
  5782         11772  
230 24         32 *{$glob} = $code;
  24         84  
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   2795 no warnings 'prototype';
  228         2509  
  228         81331  
236 5758         6948 *{$glob} = $code;
  5758         20293  
237             }
238             }
239              
240             sub _name_coderef {
241 5916 100   5916   12904 shift if @_ > 2; # three args is (target, name, sub)
242 5916         26931 _CAN_SUBNAME ? _subname(@_) : $_[1];
243             }
244              
245             sub _check_tracked {
246 538     538   1554 my ($target, $names) = @_;
247 538         1430 my $stash = _getstash($target);
248 538 100       2291 my $exports = $EXPORTS{$target}
249             or return;
250              
251 310 100       1037 $names = [keys %$exports]
252             if !$names;
253             my %rev =
254             map +($exports->{$_} => $_),
255 310         4395 grep defined $exports->{$_},
256             keys %$exports;
257              
258             return
259             grep {
260 310         1075 my $g = $stash->{$_};
  2304         5104  
261 2304 100 100     13918 $g && defined &$g && exists $rev{\&$g};
262             }
263             @$names;
264             }
265              
266             sub _unimport_coderefs {
267 26     26   61 my ($target) = @_;
268              
269 26         109 my $stash = _getstash($target);
270 26         66 my @exports = _check_tracked($target);
271              
272 26         153 foreach my $name (@exports) {
273 112         236 my $old = delete $stash->{$name};
274 112         240 my $full_name = join('::',$target,$name);
275             # Copy everything except the code slot back into place (e.g. $has)
276 112         173 foreach my $type (qw(SCALAR HASH ARRAY IO)) {
277 448 100       530 next unless defined(*{$old}{$type});
  448         5354  
278 228     228   2141 no strict 'refs';
  228         1248  
  228         26180  
279 112         177 *$full_name = *{$old}{$type};
  112         422  
280             }
281             }
282             }
283              
284             if ($Config::Config{useithreads}) {
285             require Moo::HandleMoose::_TypeMap;
286             }
287              
288             1;