Cleanup Makefile.PL, etc.
[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);
53875581 349 return $dd->Dump();
350}
351
fc8628e3 352# general does() method
b64e2007 353sub does :method {
354 goto &does_role;
355}
53875581 356
4093c859 3571;
f38ce2d0 358__END__
359
360=head1 NAME
361
a672bf86 362Mouse::Util - Utilities for working with Mouse classes
f38ce2d0 363
a25ca8d6 364=head1 VERSION
365
86eb0b5e 366This document describes Mouse version 0.70
a25ca8d6 367
a672bf86 368=head1 SYNOPSIS
369
370 use Mouse::Util; # turns on strict and warnings
371
372=head1 DESCRIPTION
373
374This module provides a set of utility functions. Many of these
375functions are intended for use in Mouse itself or MouseX modules, but
376some of them may be useful for use in your own code.
377
f38ce2d0 378=head1 IMPLEMENTATIONS FOR
379
a672bf86 380=head2 Moose::Util functions
381
382The following functions are exportable.
383
384=head3 C<find_meta($class_or_obj)>
385
386The same as C<Mouse::Util::class_of()>.
ea249879 387
a672bf86 388=head3 C<does_role($class_or_obj, $role_or_obj)>
ea249879 389
a672bf86 390=head3 C<resolve_metaclass_alias($category, $name, %options)>
ea249879 391
a672bf86 392=head3 C<apply_all_roles($applicant, @roles)>
ea249879 393
a672bf86 394=head3 C<english_listi(@items)>
ea249879 395
a672bf86 396=head2 Class::MOP functions
ea249879 397
2af88019 398The following functions are not exportable.
ea249879 399
a672bf86 400=head3 C<< Mouse::Util::is_class_loaded($classname) -> Bool >>
ea249879 401
a672bf86 402Returns whether I<$classname> is actually loaded or not.
403It uses a heuristic which involves checking for the existence of
404C<$VERSION>, C<@ISA>, and any locally-defined method.
1820fffe 405
a672bf86 406=head3 C<< Mouse::Util::load_class($classname) -> ClassName >>
1820fffe 407
a672bf86 408This will load a given I<$classname> (or die if it is not loadable).
1820fffe 409This function can be used in place of tricks like
a672bf86 410C<eval "use $module ()"> or using C<require>.
ea249879 411
a672bf86 412=head3 C<< Mouse::Util::class_of($classname_or_object) -> MetaClass >>
739525d0 413
a672bf86 414=head3 C<< Mouse::Util::get_metaclass_by_name($classname) -> MetaClass >>
739525d0 415
a672bf86 416=head3 C<< Mouse::Util::get_all_metaclass_instances() -> (MetaClasses) >>
739525d0 417
a672bf86 418=head3 C<< Mouse::Util::get_all_metaclass_names() -> (ClassNames) >>
739525d0 419
ea249879 420=head2 MRO::Compat
421
422=head3 C<get_linear_isa>
423
424=head2 Sub::Identify
425
426=head3 C<get_code_info>
427
5482cd4c 428=head1 Mouse specific utilities
ea249879 429
bedd575c 430=head3 C<not_supported>
f38ce2d0 431
5482cd4c 432=head3 C<get_code_package>
433
434=head3 C<get_code_ref>
435
1820fffe 436=head1 SEE ALSO
437
438L<Moose::Util>
439
5164490d 440L<Class::MOP>
1820fffe 441
442L<Sub::Identify>
443
444L<MRO::Compat>
445
f38ce2d0 446=cut
447