File Coverage

blib/lib/Mouse/Util.pm
Criterion Covered Total %
statement 125 160 78.1
branch 43 58 74.1
condition 24 36 66.6
subroutine 26 27 96.3
pod 6 15 40.0
total 224 296 75.6


line stmt bran cond sub pod time code
1             package Mouse::Util;
2 284     284   21598 use Mouse::Exporter; # enables strict and warnings
  284         1678  
  284         4930  
3              
4             # Note that those which don't exist here are defined in XS or Mouse::PurePerl
5              
6             # must be here because it will be referred by other modules loaded
7             sub get_linear_isa($;$); ## no critic
8              
9             # must be here because it will called in Mouse::Exporter
10             sub install_subroutines {
11 18     18 0 32 my $into = shift;
12              
13 18         60 while(my($name, $code) = splice @_, 0, 2){
14 284     284   3301 no strict 'refs';
  284         1441  
  284         12272  
15 284     284   2264 no warnings 'once', 'redefine';
  284         2481  
  284         14999  
16 284     284   1722 use warnings FATAL => 'uninitialized';
  284         1716  
  284         110155  
17 63         90 *{$into . '::' . $name} = \&{$code};
  63         312  
  63         87  
18             }
19 18         43 return;
20             }
21              
22             BEGIN{
23             # This is used in Mouse::PurePerl
24 284     284   3958 Mouse::Exporter->setup_import_methods(
25             as_is => [qw(
26             find_meta
27             does_role
28             resolve_metaclass_alias
29             apply_all_roles
30             english_list
31              
32             load_class
33             is_class_loaded
34              
35             get_linear_isa
36             get_code_info
37              
38             get_code_package
39             get_code_ref
40              
41             not_supported
42              
43             does meta throw_error dump
44             )],
45             groups => {
46             default => [], # export no functions by default
47              
48             # The ':meta' group is 'use metaclass' for Mouse
49             meta => [qw(does meta dump throw_error)],
50             },
51             );
52              
53 284         652 our $VERSION = 'v2.4.10';
54              
55 284   33     6336 my $xs = !(defined(&is_valid_class_name) || $ENV{MOUSE_PUREPERL} || $ENV{PERL_ONLY});
56              
57             # Because Mouse::Util is loaded first in all the Mouse sub-modules,
58             # XSLoader must be placed here, not in Mouse.pm.
59 284 100       3422 if($xs){
60             # XXX: XSLoader tries to get the object path from caller's file name
61             # $hack_mouse_file fools its mechanism
62 283         2276 (my $hack_mouse_file = __FILE__) =~ s/.Util//; # .../Mouse/Util.pm -> .../Mouse.pm
63 283   50     38612 $xs = eval sprintf("#line %d %s\n", __LINE__, $hack_mouse_file) . q{
64             local $^W = 0; # workaround 'redefine' warning to &install_subroutines
65             no warnings 'redefine';
66             require XSLoader;
67             XSLoader::load('Mouse', $VERSION);
68             Mouse::Util->import({ into => 'Mouse::Meta::Method::Constructor::XS' }, ':meta');
69             Mouse::Util->import({ into => 'Mouse::Meta::Method::Destructor::XS' }, ':meta');
70             Mouse::Util->import({ into => 'Mouse::Meta::Method::Accessor::XS' }, ':meta');
71             return 1;
72             } || 0;
73 283 0 33     1260 warn $@ if $@ && $ENV{MOUSE_XS};
74             }
75              
76 284 100       1020 if(!$xs){
77 1         4 require 'Mouse/PurePerl.pm'; # we don't want to create its namespace
78             }
79              
80             {
81 284         575 my $value = $xs; # avoid "Constants from lexical variables potentially modified elsewhere are deprecated"
  284         639  
82 284         2610 *MOUSE_XS = sub(){ $value };
  0         0  
83             }
84              
85             # definition of mro::get_linear_isa()
86 284         772 my $get_linear_isa;
87 284 50       1396 if ($] >= 5.010_000) {
88 284         151921 require 'mro.pm';
89 284         188986 $get_linear_isa = \&mro::get_linear_isa;
90             }
91             else {
92             # this code is based on MRO::Compat::__get_linear_isa
93 0         0 my $_get_linear_isa_dfs; # this recurses so it isn't pretty
94             $_get_linear_isa_dfs = sub {
95 0         0 my($classname) = @_;
96              
97 0         0 my @lin = ($classname);
98 0         0 my %stored;
99              
100 284     284   3466 no strict 'refs';
  284         1397  
  284         80777  
101 0         0 foreach my $parent (@{"$classname\::ISA"}) {
  0         0  
102 0         0 foreach my $p(@{ $_get_linear_isa_dfs->($parent) }) {
  0         0  
103 0 0       0 next if exists $stored{$p};
104 0         0 push(@lin, $p);
105 0         0 $stored{$p} = 1;
106             }
107             }
108 0         0 return \@lin;
109 0         0 };
110              
111             {
112 0         0 package # hide from PAUSE
113             Class::C3;
114 0         0 our %MRO; # avoid 'once' warnings
115             }
116              
117             # MRO::Compat::__get_linear_isa has no prototype, so
118             # we define a prototyped version for compatibility with core's
119             # See also MRO::Compat::__get_linear_isa.
120             $get_linear_isa = sub ($;$){
121 0         0 my($classname, $type) = @_;
122              
123 0 0       0 if(!defined $type){
124 0 0       0 $type = exists $Class::C3::MRO{$classname} ? 'c3' : 'dfs';
125             }
126 0 0       0 if($type eq 'c3'){
127 0         0 require Class::C3;
128 0         0 return [Class::C3::calculateMRO($classname)];
129             }
130             else{
131 0         0 return $_get_linear_isa_dfs->($classname);
132             }
133 0         0 };
134             }
135              
136 284         7831 *get_linear_isa = $get_linear_isa;
137             }
138              
139 284     284   1982 use Carp ();
  284         598  
  284         4427  
140 284     284   1590 use Scalar::Util ();
  284         585  
  284         414058  
141              
142             # aliases as public APIs
143             # it must be 'require', not 'use', because Mouse::Meta::Module depends on Mouse::Util
144             require Mouse::Meta::Module; # for the entities of metaclass cache utilities
145              
146             # aliases
147             {
148             *class_of = \&Mouse::Meta::Module::_class_of;
149             *get_metaclass_by_name = \&Mouse::Meta::Module::_get_metaclass_by_name;
150             *get_all_metaclass_instances = \&Mouse::Meta::Module::_get_all_metaclass_instances;
151             *get_all_metaclass_names = \&Mouse::Meta::Module::_get_all_metaclass_names;
152              
153             *Mouse::load_class = \&load_class;
154             *Mouse::is_class_loaded = \&is_class_loaded;
155              
156             # is-a predicates
157             #generate_isa_predicate_for('Mouse::Meta::TypeConstraint' => 'is_a_type_constraint');
158             #generate_isa_predicate_for('Mouse::Meta::Class' => 'is_a_metaclass');
159             #generate_isa_predicate_for('Mouse::Meta::Role' => 'is_a_metarole');
160              
161             # duck type predicates
162             generate_can_predicate_for(['_compiled_type_constraint'] => 'is_a_type_constraint');
163             generate_can_predicate_for(['create_anon_class'] => 'is_a_metaclass');
164             generate_can_predicate_for(['create_anon_role'] => 'is_a_metarole');
165             }
166              
167             sub in_global_destruction;
168              
169             if (defined ${^GLOBAL_PHASE}) {
170             *in_global_destruction = sub {
171 109     109   11138 return ${^GLOBAL_PHASE} eq 'DESTRUCT';
172             };
173             }
174             else {
175             my $in_global_destruction = 0;
176 284     284   539460 END { $in_global_destruction = 1 }
177             *in_global_destruction = sub {
178             return $in_global_destruction;
179             };
180             }
181              
182             # Moose::Util compatible utilities
183              
184             sub find_meta{
185 12     12 1 55 return class_of( $_[0] );
186             }
187              
188             sub _does_role_impl {
189 178     178   528 my ($class_or_obj, $role_name) = @_;
190              
191 178         712 my $meta = class_of($class_or_obj);
192              
193 178 100 50     611 (defined $role_name)
194             || ($meta || 'Mouse::Meta::Class')->throw_error("You must supply a role name to does()");
195              
196 177   100     949 return defined($meta) && $meta->does_role($role_name);
197             }
198              
199             sub does_role {
200 54     54 1 171 my($thing, $role_name) = @_;
201              
202 54 100 100     666 if( (Scalar::Util::blessed($thing) || is_class_loaded($thing))
      100        
203             && $thing->can('does')) {
204 49         166 return $thing->does($role_name);
205             }
206 5         23 goto &_does_role_impl;
207             }
208              
209             # taken from Mouse::Util (0.90)
210             {
211             my %cache;
212              
213             sub resolve_metaclass_alias {
214 40     40 1 150 my ( $type, $metaclass_name, %options ) = @_;
215              
216 40 100       191 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
217              
218 40   66     220 return $cache{$cache_key}{$metaclass_name} ||= do{
219              
220             my $possible_full_name = join '::',
221 31 100       155 'Mouse::Meta', $type, 'Custom', ($options{trait} ? 'Trait' : ()), $metaclass_name
222             ;
223              
224 31         121 my $loaded_class = load_first_existing_class(
225             $possible_full_name,
226             $metaclass_name
227             );
228              
229 31 100       540 $loaded_class->can('register_implementation')
230             ? $loaded_class->register_implementation
231             : $loaded_class;
232             };
233             }
234             }
235              
236             # Taken from Module::Runtime
237             sub module_notional_filename {
238 818     818 0 2387 my $class = shift;
239              
240 818         3317 $class =~ s{::}{/}g;
241              
242 818         3033 return $class.'.pm';
243             }
244              
245             # Utilities from Class::MOP
246              
247             sub get_code_info;
248             sub get_code_package;
249              
250             sub is_valid_class_name;
251             sub is_class_loaded;
252              
253             # taken from Class/MOP.pm
254             sub load_first_existing_class {
255 31 50   31 0 143 my @classes = @_
256             or return;
257              
258 31         63 my %exceptions;
259 31         81 for my $class (@classes) {
260 52         131 my $e = _try_load_one_class($class);
261              
262 52 100       150 if ($e) {
263 21         82 $exceptions{$class} = $e;
264             }
265             else {
266 31         115 return $class;
267             }
268             }
269              
270             # not found
271             Carp::confess join(
272             "\n",
273             map {
274 0         0 sprintf( "Could not load class (%s) because : %s",
275 0         0 $_, $exceptions{$_} )
276             } @classes
277             );
278             }
279              
280             # taken from Class/MOP.pm
281             sub _try_load_one_class {
282 1349     1349   6550 my $class = shift;
283              
284 1349 100       9331 unless ( is_valid_class_name($class) ) {
285 5 100       20 my $display = defined($class) ? $class : 'undef';
286 5         68 Carp::confess "Invalid class name ($display)";
287             }
288              
289 1344 100       16687 return '' if is_class_loaded($class);
290              
291 47         178 my $filename = module_notional_filename($class);
292              
293 47         112 return do {
294 47         92 local $@;
295 47         119 eval { require $filename };
  47         15322  
296 47         482 $@;
297             };
298             }
299              
300              
301             sub load_class {
302 1297     1297 1 16405 my $class = shift;
303 1297         7447 my $e = _try_load_one_class($class);
304 1292 100       8018 Carp::confess "Could not load class ($class) because : $e" if $e;
305              
306 1288         12450 return $class;
307             }
308              
309              
310             sub apply_all_roles {
311 220 100   220 1 17297 my $consumer = Scalar::Util::blessed($_[0])
312             ? $_[0] # instance
313             : Mouse::Meta::Class->initialize($_[0]); # class or role name
314              
315 220         2396 my @roles;
316              
317             # Basis of Data::OptList
318 220         2479 my $max = scalar(@_);
319 220         2687 for (my $i = 1; $i < $max ; $i++) {
320 285         3160 my $role = $_[$i];
321 285         3108 my $role_name;
322 285 100       3489 if(ref $role) {
323 4         13 $role_name = $role->name;
324             }
325             else {
326 281         3093 $role_name = $role;
327 281         3513 load_class($role_name);
328 281         3405 $role = get_metaclass_by_name($role_name);
329             }
330              
331 285 100 100     3905 if ($i + 1 < $max && ref($_[$i + 1]) eq 'HASH') {
332 35         123 push @roles, [ $role => $_[++$i] ];
333             } else {
334 250         5806 push @roles, [ $role => undef ];
335             }
336 285 100       7402 is_a_metarole($role)
337             || $consumer->meta->throw_error("You can only consume roles, $role_name is not a Mouse role");
338             }
339              
340 219 100       2574 if ( scalar @roles == 1 ) {
341 167         1575 my ( $role, $params ) = @{ $roles[0] };
  167         2984  
342 167 100       2166 $role->apply( $consumer, defined $params ? $params : () );
343             }
344             else {
345 52         957 Mouse::Meta::Role->combine(@roles)->apply($consumer);
346             }
347 199         6847 return;
348             }
349              
350             # taken from Moose::Util 0.90
351             sub english_list {
352 19 100   19 0 314 return $_[0] if @_ == 1;
353              
354 10         47 my @items = sort @_;
355              
356 10 100       56 return "$items[0] and $items[1]" if @items == 2;
357              
358 2         4 my $tail = pop @items;
359              
360 2         14 return join q{, }, @items, "and $tail";
361             }
362              
363             sub quoted_english_list {
364 18     18 0 43 return english_list(map { qq{'$_'} } @_);
  31         103  
365             }
366              
367             # common utilities
368              
369             sub not_supported{
370 1     1 1 3 my($feature) = @_;
371              
372 1   33     6 $feature ||= ( caller(1) )[3] . '()'; # subroutine name
373              
374 1         32 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
375 1         13 Carp::confess("Mouse does not currently support $feature");
376             }
377              
378             # general meta() method
379             sub meta :method{
380 116   66 116 0 2003 return Mouse::Meta::Class->initialize(ref($_[0]) || $_[0]);
381             }
382              
383             # general throw_error() method
384             # $o->throw_error($msg, depth => $leve, longmess => $croak_or_confess)
385             sub throw_error :method {
386 979     979 0 135473 my($self, $message, %args) = @_;
387              
388 979   100     3625 local $Carp::CarpLevel = $Carp::CarpLevel + 1 + ($args{depth} || 0);
389 979         1779 local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though
390              
391 979 50 33     3153 if(exists $args{longmess} && !$args{longmess}) {
392 0         0 Carp::croak($message);
393             }
394             else{
395 979         13540 Carp::confess($message);
396             }
397             }
398              
399             # general dump() method
400             sub dump :method {
401 0     0 0 0 my($self, $maxdepth) = @_;
402              
403 0         0 require 'Data/Dumper.pm'; # we don't want to create its namespace
404 0         0 my $dd = Data::Dumper->new([$self]);
405 0 0       0 $dd->Maxdepth(defined($maxdepth) ? $maxdepth : 3);
406 0         0 $dd->Indent(1);
407 0         0 $dd->Sortkeys(1);
408 0         0 $dd->Quotekeys(0);
409 0         0 return $dd->Dump();
410             }
411              
412             # general does() method
413             sub does :method {
414 173     173 0 37113 goto &_does_role_impl;
415             }
416              
417             1;
418             __END__