Clean up
[gitmo/Mouse.git] / lib / Mouse / Util.pm
CommitLineData
4093c859 1package Mouse::Util;
bc69ee88 2use Mouse::Exporter; # enables strict and warnings
6d28c5cf 3
a4b15169 4# must be here because it will be refered by other modules loaded
5sub get_linear_isa($;$); ## no critic
ba153b33 6
a4b15169 7# must be here because it will called in Mouse::Exporter
8sub install_subroutines {
1194aede 9 my $into = shift;
10
11 while(my($name, $code) = splice @_, 0, 2){
12 no strict 'refs';
13 no warnings 'once', 'redefine';
14 use warnings FATAL => 'uninitialized';
15 *{$into . '::' . $name} = \&{$code};
16 }
17 return;
18}
19
df6dd016 20BEGIN{
8aba926d 21 # This is used in Mouse::PurePerl
22 Mouse::Exporter->setup_import_methods(
23 as_is => [qw(
24 find_meta
25 does_role
26 resolve_metaclass_alias
27 apply_all_roles
28 english_list
29
30 load_class
31 is_class_loaded
32
33 get_linear_isa
34 get_code_info
35
36 get_code_package
37 get_code_ref
38
39 not_supported
40
41 does meta dump
42 )],
43 groups => {
44 default => [], # export no functions by default
45
46 # The ':meta' group is 'use metaclass' for Mouse
47 meta => [qw(does meta dump)],
48 },
49 );
50
86eb0b5e 51 our $VERSION = '0.70';
df6dd016 52
bdef60b4 53 my $xs = !(defined(&is_valid_class_name) || $ENV{MOUSE_PUREPERL} || $ENV{PERL_ONLY});
df6dd016 54
4bef84ef 55 # Because Mouse::Util is loaded first in all the Mouse sub-modules,
56 # XSLoader must be placed here, not in Mouse.pm.
db5e4409 57 if($xs){
34bdc46a 58 # XXX: XSLoader tries to get the object path from caller's file name
59 # $hack_mouse_file fools its mechanism
34bdc46a 60 (my $hack_mouse_file = __FILE__) =~ s/.Util//; # .../Mouse/Util.pm -> .../Mouse.pm
db5e4409 61 $xs = eval sprintf("#line %d %s\n", __LINE__, $hack_mouse_file) . q{
4bef84ef 62 local $^W = 0; # workaround 'redefine' warning to &install_subroutines
df6dd016 63 require XSLoader;
64 XSLoader::load('Mouse', $VERSION);
923a04ba 65 Mouse::Util->import({ into => 'Mouse::Meta::Method::Constructor::XS' }, ':meta');
66 Mouse::Util->import({ into => 'Mouse::Meta::Method::Destructor::XS' }, ':meta');
3821b191 67 Mouse::Util->import({ into => 'Mouse::Meta::Method::Accessor::XS' }, ':meta');
923a04ba 68 return 1;
029463f4 69 } || 0;
1a6d349c 70 #warn $@ if $@;
df6dd016 71 }
72
db5e4409 73 if(!$xs){
df6dd016 74 require 'Mouse/PurePerl.pm'; # we don't want to create its namespace
75 }
db5e4409 76
ecd4a125 77 *MOUSE_XS = sub(){ $xs };
df6dd016 78}
79
5dd5edef 80use Carp ();
81use Scalar::Util ();
4093c859 82
739525d0 83# aliases as public APIs
deb9a0f3 84# it must be 'require', not 'use', because Mouse::Meta::Module depends on Mouse::Util
7727a2f0 85require Mouse::Meta::Module; # for the entities of metaclass cache utilities
86
01f892fa 87# aliases
88{
542f20ad 89 *class_of = \&Mouse::Meta::Module::_class_of;
90 *get_metaclass_by_name = \&Mouse::Meta::Module::_get_metaclass_by_name;
91 *get_all_metaclass_instances = \&Mouse::Meta::Module::_get_all_metaclass_instances;
92 *get_all_metaclass_names = \&Mouse::Meta::Module::_get_all_metaclass_names;
f48920c1 93
01f892fa 94 *Mouse::load_class = \&load_class;
95 *Mouse::is_class_loaded = \&is_class_loaded;
96
f48920c1 97 # is-a predicates
6a4ab70d 98 #generate_isa_predicate_for('Mouse::Meta::TypeConstraint' => 'is_a_type_constraint');
99 #generate_isa_predicate_for('Mouse::Meta::Class' => 'is_a_metaclass');
100 #generate_isa_predicate_for('Mouse::Meta::Role' => 'is_a_metarole');
101
102 # duck type predicates
103 generate_can_predicate_for(['_compiled_type_constraint'] => 'is_a_type_constraint');
104 generate_can_predicate_for(['create_anon_class'] => 'is_a_metaclass');
105 generate_can_predicate_for(['create_anon_role'] => 'is_a_metarole');
739525d0 106}
107
39a8df63 108our $in_global_destruction = 0;
109END{ $in_global_destruction = 1 }
f48920c1 110
08f7a8db 111# Moose::Util compatible utilities
112
113sub find_meta{
739525d0 114 return class_of( $_[0] );
08f7a8db 115}
116
117sub does_role{
53875581 118 my ($class_or_obj, $role_name) = @_;
8e64d0fa 119
739525d0 120 my $meta = class_of($class_or_obj);
8e64d0fa 121
53875581 122 (defined $role_name)
123 || ($meta || 'Mouse::Meta::Class')->throw_error("You must supply a role name to does()");
124
125 return defined($meta) && $meta->does_role($role_name);
08f7a8db 126}
127
42d7df00 128BEGIN {
f15868c3 129 my $get_linear_isa;
bcd39bf4 130 if ($] >= 5.009_005) {
388b8ebd 131 require mro;
f15868c3 132 $get_linear_isa = \&mro::get_linear_isa;
272a1930 133 } else {
74690b26 134 # this code is based on MRO::Compat::__get_linear_isa
ce5a7699 135 my $_get_linear_isa_dfs; # this recurses so it isn't pretty
136 $_get_linear_isa_dfs = sub {
137 my($classname) = @_;
138
139 my @lin = ($classname);
140 my %stored;
141
142 no strict 'refs';
143 foreach my $parent (@{"$classname\::ISA"}) {
74690b26 144 foreach my $p(@{ $_get_linear_isa_dfs->($parent) }) {
ce5a7699 145 next if exists $stored{$p};
146 push(@lin, $p);
147 $stored{$p} = 1;
272a1930 148 }
ce5a7699 149 }
150 return \@lin;
151 };
ce5a7699 152
74690b26 153 {
154 package # hide from PAUSE
155 Class::C3;
4bef84ef 156 our %MRO; # avoid 'once' warnings
74690b26 157 }
ce5a7699 158
159 # MRO::Compat::__get_linear_isa has no prototype, so
160 # we define a prototyped version for compatibility with core's
161 # See also MRO::Compat::__get_linear_isa.
162 $get_linear_isa = sub ($;$){
163 my($classname, $type) = @_;
74690b26 164
ce5a7699 165 if(!defined $type){
74690b26 166 $type = exists $Class::C3::MRO{$classname} ? 'c3' : 'dfs';
167 }
168 if($type eq 'c3'){
169 require Class::C3;
170 return [Class::C3::calculateMRO($classname)];
171 }
172 else{
173 return $_get_linear_isa_dfs->($classname);
ce5a7699 174 }
ce5a7699 175 };
eae80759 176 }
bcd39bf4 177
f15868c3 178 *get_linear_isa = $get_linear_isa;
eae80759 179}
180
3a63a2e7 181
08f7a8db 182# taken from Mouse::Util (0.90)
abfdffe0 183{
184 my %cache;
185
8e64d0fa 186 sub resolve_metaclass_alias {
187 my ( $type, $metaclass_name, %options ) = @_;
188
189 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
190
191 return $cache{$cache_key}{$metaclass_name} ||= do{
abfdffe0 192
08f7a8db 193 my $possible_full_name = join '::',
194 'Mouse::Meta', $type, 'Custom', ($options{trait} ? 'Trait' : ()), $metaclass_name
195 ;
196
8e64d0fa 197 my $loaded_class = load_first_existing_class(
198 $possible_full_name,
199 $metaclass_name
200 );
201
202 $loaded_class->can('register_implementation')
203 ? $loaded_class->register_implementation
08f7a8db 204 : $loaded_class;
8e64d0fa 205 };
abfdffe0 206 }
207}
208
739525d0 209# Utilities from Class::MOP
210
df6dd016 211sub get_code_info;
212sub get_code_package;
739525d0 213
0ffc4183 214sub is_valid_class_name;
abfdffe0 215
216# taken from Class/MOP.pm
217sub load_first_existing_class {
218 my @classes = @_
219 or return;
220
23264b5b 221 my %exceptions;
222 for my $class (@classes) {
abfdffe0 223 my $e = _try_load_one_class($class);
224
225 if ($e) {
226 $exceptions{$class} = $e;
227 }
228 else {
53875581 229 return $class;
abfdffe0 230 }
231 }
abfdffe0 232
53875581 233 # not found
5dd5edef 234 Carp::confess join(
abfdffe0 235 "\n",
236 map {
237 sprintf( "Could not load class (%s) because : %s",
238 $_, $exceptions{$_} )
239 } @classes
240 );
241}
242
243# taken from Class/MOP.pm
244sub _try_load_one_class {
245 my $class = shift;
246
6cfa1e5e 247 unless ( is_valid_class_name($class) ) {
248 my $display = defined($class) ? $class : 'undef';
5dd5edef 249 Carp::confess "Invalid class name ($display)";
6cfa1e5e 250 }
251
be0ba859 252 return '' if is_class_loaded($class);
abfdffe0 253
637d4f17 254 $class =~ s{::}{/}g;
255 $class .= '.pm';
abfdffe0 256
257 return do {
258 local $@;
637d4f17 259 eval { require $class };
abfdffe0 260 $@;
261 };
262}
263
6cfa1e5e 264
265sub load_class {
266 my $class = shift;
267 my $e = _try_load_one_class($class);
5dd5edef 268 Carp::confess "Could not load class ($class) because : $e" if $e;
6cfa1e5e 269
637d4f17 270 return $class;
6cfa1e5e 271}
272
df6dd016 273sub is_class_loaded;
6cfa1e5e 274
2e92bb89 275sub apply_all_roles {
45f22b92 276 my $consumer = Scalar::Util::blessed($_[0])
5dd5edef 277 ? shift # instance
278 : Mouse::Meta::Class->initialize(shift); # class or role name
2e92bb89 279
21498b08 280 my @roles;
f6715552 281
282 # Basis of Data::OptList
21498b08 283 my $max = scalar(@_);
284 for (my $i = 0; $i < $max ; $i++) {
285 if ($i + 1 < $max && ref($_[$i + 1])) {
b1980b86 286 push @roles, [ $_[$i] => $_[++$i] ];
21498b08 287 } else {
b1980b86 288 push @roles, [ $_[$i] => undef ];
21498b08 289 }
ff687069 290 my $role_name = $roles[-1][0];
291 load_class($role_name);
0126c27c 292
f48920c1 293 is_a_metarole( get_metaclass_by_name($role_name) )
45f22b92 294 || $consumer->meta->throw_error("You can only consume roles, $role_name is not a Mouse role");
21498b08 295 }
296
21498b08 297 if ( scalar @roles == 1 ) {
b1980b86 298 my ( $role_name, $params ) = @{ $roles[0] };
45f22b92 299 get_metaclass_by_name($role_name)->apply( $consumer, defined $params ? $params : () );
21498b08 300 }
301 else {
45f22b92 302 Mouse::Meta::Role->combine(@roles)->apply($consumer);
21498b08 303 }
23264b5b 304 return;
2e92bb89 305}
306
2e33bb59 307# taken from Moose::Util 0.90
308sub english_list {
8e64d0fa 309 return $_[0] if @_ == 1;
310
311 my @items = sort @_;
312
313 return "$items[0] and $items[1]" if @items == 2;
314
315 my $tail = pop @items;
316
317 return join q{, }, @items, "and $tail";
2e33bb59 318}
319
5af36247 320sub quoted_english_list {
53f661ad 321 return english_list(map { qq{'$_'} } @_);
5af36247 322}
323
53875581 324# common utilities
325
fce211ae 326sub not_supported{
327 my($feature) = @_;
328
329 $feature ||= ( caller(1) )[3]; # subroutine name
330
1b9e472d 331 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
332 Carp::confess("Mouse does not currently support $feature");
fce211ae 333}
334
fc8628e3 335# general meta() method
336sub meta :method{
152e5759 337 return Mouse::Meta::Class->initialize(ref($_[0]) || $_[0]);
53875581 338}
339
fc8628e3 340# general dump() method
341sub dump :method {
53875581 342 my($self, $maxdepth) = @_;
343
344 require 'Data/Dumper.pm'; # we don't want to create its namespace
345 my $dd = Data::Dumper->new([$self]);
0cf6f1be 346 $dd->Maxdepth(defined($maxdepth) ? $maxdepth : 3);
53875581 347 $dd->Indent(1);
a672bf86 348 $dd->Sortkeys(1);
902174eb 349 $dd->Quotekeys(0);
53875581 350 return $dd->Dump();
351}
352
fc8628e3 353# general does() method
b64e2007 354sub does :method {
355 goto &does_role;
356}
53875581 357
4093c859 3581;
f38ce2d0 359__END__
360
361=head1 NAME
362
a672bf86 363Mouse::Util - Utilities for working with Mouse classes
f38ce2d0 364
a25ca8d6 365=head1 VERSION
366
86eb0b5e 367This document describes Mouse version 0.70
a25ca8d6 368
a672bf86 369=head1 SYNOPSIS
370
371 use Mouse::Util; # turns on strict and warnings
372
373=head1 DESCRIPTION
374
375This module provides a set of utility functions. Many of these
376functions are intended for use in Mouse itself or MouseX modules, but
377some of them may be useful for use in your own code.
378
f38ce2d0 379=head1 IMPLEMENTATIONS FOR
380
a672bf86 381=head2 Moose::Util functions
382
383The following functions are exportable.
384
385=head3 C<find_meta($class_or_obj)>
386
387The same as C<Mouse::Util::class_of()>.
ea249879 388
a672bf86 389=head3 C<does_role($class_or_obj, $role_or_obj)>
ea249879 390
a672bf86 391=head3 C<resolve_metaclass_alias($category, $name, %options)>
ea249879 392
a672bf86 393=head3 C<apply_all_roles($applicant, @roles)>
ea249879 394
a672bf86 395=head3 C<english_listi(@items)>
ea249879 396
a672bf86 397=head2 Class::MOP functions
ea249879 398
2af88019 399The following functions are not exportable.
ea249879 400
a672bf86 401=head3 C<< Mouse::Util::is_class_loaded($classname) -> Bool >>
ea249879 402
a672bf86 403Returns whether I<$classname> is actually loaded or not.
404It uses a heuristic which involves checking for the existence of
405C<$VERSION>, C<@ISA>, and any locally-defined method.
1820fffe 406
a672bf86 407=head3 C<< Mouse::Util::load_class($classname) -> ClassName >>
1820fffe 408
a672bf86 409This will load a given I<$classname> (or die if it is not loadable).
1820fffe 410This function can be used in place of tricks like
a672bf86 411C<eval "use $module ()"> or using C<require>.
ea249879 412
a672bf86 413=head3 C<< Mouse::Util::class_of($classname_or_object) -> MetaClass >>
739525d0 414
a672bf86 415=head3 C<< Mouse::Util::get_metaclass_by_name($classname) -> MetaClass >>
739525d0 416
a672bf86 417=head3 C<< Mouse::Util::get_all_metaclass_instances() -> (MetaClasses) >>
739525d0 418
a672bf86 419=head3 C<< Mouse::Util::get_all_metaclass_names() -> (ClassNames) >>
739525d0 420
ea249879 421=head2 MRO::Compat
422
423=head3 C<get_linear_isa>
424
425=head2 Sub::Identify
426
427=head3 C<get_code_info>
428
5482cd4c 429=head1 Mouse specific utilities
ea249879 430
bedd575c 431=head3 C<not_supported>
f38ce2d0 432
5482cd4c 433=head3 C<get_code_package>
434
435=head3 C<get_code_ref>
436
1820fffe 437=head1 SEE ALSO
438
439L<Moose::Util>
440
5164490d 441L<Class::MOP>
1820fffe 442
443L<Sub::Identify>
444
445L<MRO::Compat>
446
f38ce2d0 447=cut
448