File Coverage

blib/lib/Mouse/Util.pm
Criterion Covered Total %
statement 123 158 77.8
branch 43 58 74.1
condition 24 36 66.6
subroutine 25 26 96.1
pod 6 14 42.8
total 221 292 75.6


line stmt bran cond sub pod time code
1             package Mouse::Util;
2 284     284   18623 use Mouse::Exporter; # enables strict and warnings
  284         341  
  284         3521  
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 16 my $into = shift;
12              
13 18         43 while(my($name, $code) = splice @_, 0, 2){
14 284     284   3061 no strict 'refs';
  284         955  
  284         9599  
15 284     284   1289 no warnings 'once', 'redefine';
  284         1243  
  284         9350  
16 284     284   914 use warnings FATAL => 'uninitialized';
  284         314  
  284         75463  
17 63         39 *{$into . '::' . $name} = \&{$code};
  63         356  
  63         62  
18             }
19 18         33 return;
20             }
21              
22             BEGIN{
23             # This is used in Mouse::PurePerl
24 284     284   5765 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         339 our $VERSION = 'v2.4.9';
54              
55 284   33     3607 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       1958 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         2578 (my $hack_mouse_file = __FILE__) =~ s/.Util//; # .../Mouse/Util.pm -> .../Mouse.pm
63 283   50     47483 $xs = eval sprintf("#line %d %s\n", __LINE__, $hack_mouse_file) . q{
64             local $^W = 0; # workaround 'redefine' warning to &install_subroutines
65             require XSLoader;
66             XSLoader::load('Mouse', $VERSION);
67             Mouse::Util->import({ into => 'Mouse::Meta::Method::Constructor::XS' }, ':meta');
68             Mouse::Util->import({ into => 'Mouse::Meta::Method::Destructor::XS' }, ':meta');
69             Mouse::Util->import({ into => 'Mouse::Meta::Method::Accessor::XS' }, ':meta');
70             return 1;
71             } || 0;
72 283 0 33     1058 warn $@ if $@ && $ENV{MOUSE_XS};
73             }
74              
75 284 100       663 if(!$xs){
76 1         4 require 'Mouse/PurePerl.pm'; # we don't want to create its namespace
77             }
78              
79             {
80 284         276 my $value = $xs; # avoid "Constants from lexical variables potentially modified elsewhere are deprecated"
  284         314  
81 284         2005 *MOUSE_XS = sub(){ $value };
  0         0  
82             }
83              
84             # definition of mro::get_linear_isa()
85 284         319 my $get_linear_isa;
86 284 50       763 if ($] >= 5.010_000) {
87 284         129997 require 'mro.pm';
88 284         157043 $get_linear_isa = \&mro::get_linear_isa;
89             }
90             else {
91             # this code is based on MRO::Compat::__get_linear_isa
92 0         0 my $_get_linear_isa_dfs; # this recurses so it isn't pretty
93             $_get_linear_isa_dfs = sub {
94 0         0 my($classname) = @_;
95              
96 0         0 my @lin = ($classname);
97 0         0 my %stored;
98              
99 284     284   4773 no strict 'refs';
  284         1242  
  284         68746  
100 0         0 foreach my $parent (@{"$classname\::ISA"}) {
  0         0  
101 0         0 foreach my $p(@{ $_get_linear_isa_dfs->($parent) }) {
  0         0  
102 0 0       0 next if exists $stored{$p};
103 0         0 push(@lin, $p);
104 0         0 $stored{$p} = 1;
105             }
106             }
107 0         0 return \@lin;
108 0         0 };
109              
110             {
111 0         0 package # hide from PAUSE
112             Class::C3;
113 0         0 our %MRO; # avoid 'once' warnings
114             }
115              
116             # MRO::Compat::__get_linear_isa has no prototype, so
117             # we define a prototyped version for compatibility with core's
118             # See also MRO::Compat::__get_linear_isa.
119             $get_linear_isa = sub ($;$){
120 0         0 my($classname, $type) = @_;
121              
122 0 0       0 if(!defined $type){
123 0 0       0 $type = exists $Class::C3::MRO{$classname} ? 'c3' : 'dfs';
124             }
125 0 0       0 if($type eq 'c3'){
126 0         0 require Class::C3;
127 0         0 return [Class::C3::calculateMRO($classname)];
128             }
129             else{
130 0         0 return $_get_linear_isa_dfs->($classname);
131             }
132 0         0 };
133             }
134              
135 284         6446 *get_linear_isa = $get_linear_isa;
136             }
137              
138 284     284   1252 use Carp ();
  284         260  
  284         3840  
139 284     284   904 use Scalar::Util ();
  284         257  
  284         323869  
140              
141             # aliases as public APIs
142             # it must be 'require', not 'use', because Mouse::Meta::Module depends on Mouse::Util
143             require Mouse::Meta::Module; # for the entities of metaclass cache utilities
144              
145             # aliases
146             {
147             *class_of = \&Mouse::Meta::Module::_class_of;
148             *get_metaclass_by_name = \&Mouse::Meta::Module::_get_metaclass_by_name;
149             *get_all_metaclass_instances = \&Mouse::Meta::Module::_get_all_metaclass_instances;
150             *get_all_metaclass_names = \&Mouse::Meta::Module::_get_all_metaclass_names;
151              
152             *Mouse::load_class = \&load_class;
153             *Mouse::is_class_loaded = \&is_class_loaded;
154              
155             # is-a predicates
156             #generate_isa_predicate_for('Mouse::Meta::TypeConstraint' => 'is_a_type_constraint');
157             #generate_isa_predicate_for('Mouse::Meta::Class' => 'is_a_metaclass');
158             #generate_isa_predicate_for('Mouse::Meta::Role' => 'is_a_metarole');
159              
160             # duck type predicates
161             generate_can_predicate_for(['_compiled_type_constraint'] => 'is_a_type_constraint');
162             generate_can_predicate_for(['create_anon_class'] => 'is_a_metaclass');
163             generate_can_predicate_for(['create_anon_role'] => 'is_a_metarole');
164             }
165              
166             sub in_global_destruction;
167              
168             if (defined ${^GLOBAL_PHASE}) {
169             *in_global_destruction = sub {
170 109     109   12068 return ${^GLOBAL_PHASE} eq 'DESTRUCT';
171             };
172             }
173             else {
174             my $in_global_destruction = 0;
175 284     284   434352 END { $in_global_destruction = 1 }
176             *in_global_destruction = sub {
177             return $in_global_destruction;
178             };
179             }
180              
181             # Moose::Util compatible utilities
182              
183             sub find_meta{
184 12     12 1 42 return class_of( $_[0] );
185             }
186              
187             sub _does_role_impl {
188 178     178   238 my ($class_or_obj, $role_name) = @_;
189              
190 178         407 my $meta = class_of($class_or_obj);
191              
192 178 100 50     316 (defined $role_name)
193             || ($meta || 'Mouse::Meta::Class')->throw_error("You must supply a role name to does()");
194              
195 177   100     636 return defined($meta) && $meta->does_role($role_name);
196             }
197              
198             sub does_role {
199 54     54 1 66 my($thing, $role_name) = @_;
200              
201 54 100 100     516 if( (Scalar::Util::blessed($thing) || is_class_loaded($thing))
      100        
202             && $thing->can('does')) {
203 49         126 return $thing->does($role_name);
204             }
205 5         17 goto &_does_role_impl;
206             }
207              
208             # taken from Mouse::Util (0.90)
209             {
210             my %cache;
211              
212             sub resolve_metaclass_alias {
213 40     40 1 78 my ( $type, $metaclass_name, %options ) = @_;
214              
215 40 100       127 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
216              
217 40   66     151 return $cache{$cache_key}{$metaclass_name} ||= do{
218              
219             my $possible_full_name = join '::',
220 31 100       113 'Mouse::Meta', $type, 'Custom', ($options{trait} ? 'Trait' : ()), $metaclass_name
221             ;
222              
223 31         202 my $loaded_class = load_first_existing_class(
224             $possible_full_name,
225             $metaclass_name
226             );
227              
228 31 100       367 $loaded_class->can('register_implementation')
229             ? $loaded_class->register_implementation
230             : $loaded_class;
231             };
232             }
233             }
234              
235             # Utilities from Class::MOP
236              
237             sub get_code_info;
238             sub get_code_package;
239              
240             sub is_valid_class_name;
241             sub is_class_loaded;
242              
243             # taken from Class/MOP.pm
244             sub load_first_existing_class {
245 31 50   31 0 145 my @classes = @_
246             or return;
247              
248 31         33 my %exceptions;
249 31         54 for my $class (@classes) {
250 52         78 my $e = _try_load_one_class($class);
251              
252 52 100       91 if ($e) {
253 21         61 $exceptions{$class} = $e;
254             }
255             else {
256 31         95 return $class;
257             }
258             }
259              
260             # not found
261             Carp::confess join(
262             "\n",
263             map {
264 0         0 sprintf( "Could not load class (%s) because : %s",
265 0         0 $_, $exceptions{$_} )
266             } @classes
267             );
268             }
269              
270             # taken from Class/MOP.pm
271             sub _try_load_one_class {
272 1349     1349   5572 my $class = shift;
273              
274 1349 100       7793 unless ( is_valid_class_name($class) ) {
275 5 100       14 my $display = defined($class) ? $class : 'undef';
276 5         78 Carp::confess "Invalid class name ($display)";
277             }
278              
279 1344 100       15007 return '' if is_class_loaded($class);
280              
281 47         203 $class =~ s{::}{/}g;
282 47         77 $class .= '.pm';
283              
284 47         54 return do {
285 47         63 local $@;
286 47         67 eval { require $class };
  47         14572  
287 47         389 $@;
288             };
289             }
290              
291              
292             sub load_class {
293 1297     1297 1 12863 my $class = shift;
294 1297         6612 my $e = _try_load_one_class($class);
295 1292 100       6798 Carp::confess "Could not load class ($class) because : $e" if $e;
296              
297 1288         11517 return $class;
298             }
299              
300              
301             sub apply_all_roles {
302 220 100   220 1 15509 my $consumer = Scalar::Util::blessed($_[0])
303             ? $_[0] # instance
304             : Mouse::Meta::Class->initialize($_[0]); # class or role name
305              
306 220         3070 my @roles;
307              
308             # Basis of Data::OptList
309 220         2478 my $max = scalar(@_);
310 220         2768 for (my $i = 1; $i < $max ; $i++) {
311 285         3211 my $role = $_[$i];
312 285         3108 my $role_name;
313 285 100       3317 if(ref $role) {
314 4         7 $role_name = $role->name;
315             }
316             else {
317 281         3044 $role_name = $role;
318 281         3321 load_class($role_name);
319 281         3308 $role = get_metaclass_by_name($role_name);
320             }
321              
322 285 100 100     3858 if ($i + 1 < $max && ref($_[$i + 1]) eq 'HASH') {
323 35         81 push @roles, [ $role => $_[++$i] ];
324             } else {
325 250         6038 push @roles, [ $role => undef ];
326             }
327 285 100       7307 is_a_metarole($role)
328             || $consumer->meta->throw_error("You can only consume roles, $role_name is not a Mouse role");
329             }
330              
331 219 100       2581 if ( scalar @roles == 1 ) {
332 167         1572 my ( $role, $params ) = @{ $roles[0] };
  167         3049  
333 167 100       2297 $role->apply( $consumer, defined $params ? $params : () );
334             }
335             else {
336 52         925 Mouse::Meta::Role->combine(@roles)->apply($consumer);
337             }
338 199         6604 return;
339             }
340              
341             # taken from Moose::Util 0.90
342             sub english_list {
343 19 100   19 0 267 return $_[0] if @_ == 1;
344              
345 10         37 my @items = sort @_;
346              
347 10 100       54 return "$items[0] and $items[1]" if @items == 2;
348              
349 2         2 my $tail = pop @items;
350              
351 2         13 return join q{, }, @items, "and $tail";
352             }
353              
354             sub quoted_english_list {
355 18     18 0 28 return english_list(map { qq{'$_'} } @_);
  31         83  
356             }
357              
358             # common utilities
359              
360             sub not_supported{
361 1     1 1 2 my($feature) = @_;
362              
363 1   33     10 $feature ||= ( caller(1) )[3] . '()'; # subroutine name
364              
365 1         19 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
366 1         17 Carp::confess("Mouse does not currently support $feature");
367             }
368              
369             # general meta() method
370             sub meta :method{
371 116   66 116 0 1912 return Mouse::Meta::Class->initialize(ref($_[0]) || $_[0]);
372             }
373              
374             # general throw_error() method
375             # $o->throw_error($msg, depth => $leve, longmess => $croak_or_confess)
376             sub throw_error :method {
377 979     979 0 81540 my($self, $message, %args) = @_;
378              
379 979   100     2886 local $Carp::CarpLevel = $Carp::CarpLevel + 1 + ($args{depth} || 0);
380 979         944 local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though
381              
382 979 50 33     2440 if(exists $args{longmess} && !$args{longmess}) {
383 0         0 Carp::croak($message);
384             }
385             else{
386 979         12209 Carp::confess($message);
387             }
388             }
389              
390             # general dump() method
391             sub dump :method {
392 0     0 0 0 my($self, $maxdepth) = @_;
393              
394 0         0 require 'Data/Dumper.pm'; # we don't want to create its namespace
395 0         0 my $dd = Data::Dumper->new([$self]);
396 0 0       0 $dd->Maxdepth(defined($maxdepth) ? $maxdepth : 3);
397 0         0 $dd->Indent(1);
398 0         0 $dd->Sortkeys(1);
399 0         0 $dd->Quotekeys(0);
400 0         0 return $dd->Dump();
401             }
402              
403             # general does() method
404             sub does :method {
405 173     173 0 24797 goto &_does_role_impl;
406             }
407              
408             1;
409             __END__