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