Changelogging
[gitmo/Mouse.git] / lib / Mouse / Util.pm
CommitLineData
4093c859 1package Mouse::Util;
bc69ee88 2use Mouse::Exporter; # enables strict and warnings
6d28c5cf 3
df6dd016 4BEGIN{
5 # Because Mouse::Util is loaded first in all the Mouse sub-modules,
6 # XS loader is placed here, not in Mouse.pm.
7
065f79e7 8 our $VERSION = '0.40_02';
df6dd016 9
10 my $need_pp = !!$ENV{MOUSE_PUREPERL};
11
12 if(!$need_pp && !exists $INC{'Mouse/PurePerl.pm'}){
13 local $@;
34bdc46a 14
15 # XXX: XSLoader tries to get the object path from caller's file name
16 # $hack_mouse_file fools its mechanism
17
18 (my $hack_mouse_file = __FILE__) =~ s/.Util//; # .../Mouse/Util.pm -> .../Mouse.pm
34bdc46a 19 $need_pp = !eval sprintf("#line %d %s\n", __LINE__, $hack_mouse_file) . q{
df6dd016 20 require XSLoader;
21 XSLoader::load('Mouse', $VERSION);
22 };
1a6d349c 23 #warn $@ if $@;
df6dd016 24 }
25
26 if($need_pp){
27 require 'Mouse/PurePerl.pm'; # we don't want to create its namespace
28 }
29}
30
31
5dd5edef 32use Carp ();
33use Scalar::Util ();
4093c859 34
04493075 35use constant _MOUSE_VERBOSE => !!$ENV{MOUSE_VERBOSE};
36
bc69ee88 37Mouse::Exporter->setup_import_methods(
38 as_is => [qw(
39 find_meta
40 does_role
41 resolve_metaclass_alias
42 apply_all_roles
43 english_list
08f7a8db 44
bc69ee88 45 load_class
46 is_class_loaded
08f7a8db 47
bc69ee88 48 get_linear_isa
49 get_code_info
ea249879 50
bc69ee88 51 get_code_package
7d96ae4d 52 get_code_ref
01afd8ff 53
bc69ee88 54 not_supported
53875581 55
bc69ee88 56 does meta dump
57 _MOUSE_VERBOSE
58 )],
59 groups => {
60 default => [], # export no functions by default
0126c27c 61
62 # The ':meta' group is 'use metaclass' for Mouse
bc69ee88 63 meta => [qw(does meta dump _MOUSE_VERBOSE)],
64 },
eae80759 65);
66
739525d0 67# aliases as public APIs
deb9a0f3 68# it must be 'require', not 'use', because Mouse::Meta::Module depends on Mouse::Util
7727a2f0 69require Mouse::Meta::Module; # for the entities of metaclass cache utilities
70
71BEGIN {
739525d0 72 *class_of = \&Mouse::Meta::Module::class_of;
73 *get_metaclass_by_name = \&Mouse::Meta::Module::get_metaclass_by_name;
74 *get_all_metaclass_instances = \&Mouse::Meta::Module::get_all_metaclass_instances;
75 *get_all_metaclass_names = \&Mouse::Meta::Module::get_all_metaclass_names;
76}
77
08f7a8db 78# Moose::Util compatible utilities
79
80sub find_meta{
739525d0 81 return class_of( $_[0] );
08f7a8db 82}
83
84sub does_role{
53875581 85 my ($class_or_obj, $role_name) = @_;
8e64d0fa 86
739525d0 87 my $meta = class_of($class_or_obj);
8e64d0fa 88
53875581 89 (defined $role_name)
90 || ($meta || 'Mouse::Meta::Class')->throw_error("You must supply a role name to does()");
91
92 return defined($meta) && $meta->does_role($role_name);
08f7a8db 93}
94
42d7df00 95BEGIN {
272a1930 96 my $impl;
bcd39bf4 97 if ($] >= 5.009_005) {
388b8ebd 98 require mro;
272a1930 99 $impl = \&mro::get_linear_isa;
100 } else {
e0396a57 101 my $e = do {
102 local $@;
103 eval { require MRO::Compat };
104 $@;
f172d4e7 105 };
e0396a57 106 if (!$e) {
272a1930 107 $impl = \&mro::get_linear_isa;
108 } else {
109# VVVVV CODE TAKEN FROM MRO::COMPAT VVVVV
e0396a57 110 my $_get_linear_isa_dfs; # this recurses so it isn't pretty
111 $_get_linear_isa_dfs = sub {
272a1930 112 no strict 'refs';
113
114 my $classname = shift;
115
116 my @lin = ($classname);
117 my %stored;
118 foreach my $parent (@{"$classname\::ISA"}) {
e0396a57 119 my $plin = $_get_linear_isa_dfs->($parent);
120 foreach my $p(@$plin) {
121 next if exists $stored{$p};
122 push(@lin, $p);
123 $stored{$p} = 1;
272a1930 124 }
125 }
126 return \@lin;
127 };
128# ^^^^^ CODE TAKEN FROM MRO::COMPAT ^^^^^
e0396a57 129 $impl = $_get_linear_isa_dfs;
eae80759 130 }
131 }
bcd39bf4 132
a81cc7b8 133
134 no warnings 'once';
135 *get_linear_isa = $impl;
eae80759 136}
137
3a63a2e7 138
08f7a8db 139# taken from Mouse::Util (0.90)
abfdffe0 140{
141 my %cache;
142
8e64d0fa 143 sub resolve_metaclass_alias {
144 my ( $type, $metaclass_name, %options ) = @_;
145
146 my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' );
147
148 return $cache{$cache_key}{$metaclass_name} ||= do{
abfdffe0 149
08f7a8db 150 my $possible_full_name = join '::',
151 'Mouse::Meta', $type, 'Custom', ($options{trait} ? 'Trait' : ()), $metaclass_name
152 ;
153
8e64d0fa 154 my $loaded_class = load_first_existing_class(
155 $possible_full_name,
156 $metaclass_name
157 );
158
159 $loaded_class->can('register_implementation')
160 ? $loaded_class->register_implementation
08f7a8db 161 : $loaded_class;
8e64d0fa 162 };
abfdffe0 163 }
164}
165
739525d0 166# Utilities from Class::MOP
167
df6dd016 168sub get_code_info;
169sub get_code_package;
739525d0 170
abfdffe0 171# taken from Class/MOP.pm
a81cc7b8 172sub is_valid_class_name {
abfdffe0 173 my $class = shift;
174
175 return 0 if ref($class);
176 return 0 unless defined($class);
abfdffe0 177
178 return 1 if $class =~ /^\w+(?:::\w+)*$/;
179
180 return 0;
181}
182
183# taken from Class/MOP.pm
184sub load_first_existing_class {
185 my @classes = @_
186 or return;
187
23264b5b 188 my %exceptions;
189 for my $class (@classes) {
abfdffe0 190 my $e = _try_load_one_class($class);
191
192 if ($e) {
193 $exceptions{$class} = $e;
194 }
195 else {
53875581 196 return $class;
abfdffe0 197 }
198 }
abfdffe0 199
53875581 200 # not found
5dd5edef 201 Carp::confess join(
abfdffe0 202 "\n",
203 map {
204 sprintf( "Could not load class (%s) because : %s",
205 $_, $exceptions{$_} )
206 } @classes
207 );
208}
209
210# taken from Class/MOP.pm
3aac966d 211my %is_class_loaded_cache;
abfdffe0 212sub _try_load_one_class {
213 my $class = shift;
214
6cfa1e5e 215 unless ( is_valid_class_name($class) ) {
216 my $display = defined($class) ? $class : 'undef';
5dd5edef 217 Carp::confess "Invalid class name ($display)";
6cfa1e5e 218 }
219
3aac966d 220 return undef if $is_class_loaded_cache{$class} ||= is_class_loaded($class);
abfdffe0 221
222 my $file = $class . '.pm';
223 $file =~ s{::}{/}g;
224
225 return do {
226 local $@;
227 eval { require($file) };
228 $@;
229 };
230}
231
6cfa1e5e 232
233sub load_class {
234 my $class = shift;
235 my $e = _try_load_one_class($class);
5dd5edef 236 Carp::confess "Could not load class ($class) because : $e" if $e;
6cfa1e5e 237
238 return 1;
239}
240
df6dd016 241sub is_class_loaded;
6cfa1e5e 242
243
2e92bb89 244sub apply_all_roles {
5dd5edef 245 my $applicant = Scalar::Util::blessed($_[0])
246 ? shift # instance
247 : Mouse::Meta::Class->initialize(shift); # class or role name
2e92bb89 248
21498b08 249 my @roles;
f6715552 250
251 # Basis of Data::OptList
21498b08 252 my $max = scalar(@_);
253 for (my $i = 0; $i < $max ; $i++) {
254 if ($i + 1 < $max && ref($_[$i + 1])) {
b1980b86 255 push @roles, [ $_[$i] => $_[++$i] ];
21498b08 256 } else {
b1980b86 257 push @roles, [ $_[$i] => undef ];
21498b08 258 }
ff687069 259 my $role_name = $roles[-1][0];
260 load_class($role_name);
0126c27c 261
745220df 262 Mouse::Util::TypeConstraints::_is_a_metarole( get_metaclass_by_name($role_name) )
71e7b544 263 || $applicant->meta->throw_error("You can only consume roles, $role_name(".$role_name->meta.") is not a Mouse role");
21498b08 264 }
265
21498b08 266 if ( scalar @roles == 1 ) {
b1980b86 267 my ( $role_name, $params ) = @{ $roles[0] };
268 get_metaclass_by_name($role_name)->apply( $applicant, defined $params ? $params : () );
21498b08 269 }
270 else {
71e7b544 271 Mouse::Meta::Role->combine(@roles)->apply($applicant);
21498b08 272 }
23264b5b 273 return;
2e92bb89 274}
275
2e33bb59 276# taken from Moose::Util 0.90
277sub english_list {
8e64d0fa 278 return $_[0] if @_ == 1;
279
280 my @items = sort @_;
281
282 return "$items[0] and $items[1]" if @items == 2;
283
284 my $tail = pop @items;
285
286 return join q{, }, @items, "and $tail";
2e33bb59 287}
288
53875581 289
290# common utilities
291
fce211ae 292sub not_supported{
293 my($feature) = @_;
294
295 $feature ||= ( caller(1) )[3]; # subroutine name
296
1b9e472d 297 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
298 Carp::confess("Mouse does not currently support $feature");
fce211ae 299}
300
fc8628e3 301# general meta() method
302sub meta :method{
152e5759 303 return Mouse::Meta::Class->initialize(ref($_[0]) || $_[0]);
53875581 304}
305
fc8628e3 306# general dump() method
307sub dump :method {
53875581 308 my($self, $maxdepth) = @_;
309
310 require 'Data/Dumper.pm'; # we don't want to create its namespace
311 my $dd = Data::Dumper->new([$self]);
312 $dd->Maxdepth(defined($maxdepth) ? $maxdepth : 2);
313 $dd->Indent(1);
314 return $dd->Dump();
315}
316
fc8628e3 317# general does() method
53875581 318sub does :method;
319*does = \&does_role; # alias
320
4093c859 3211;
322
f38ce2d0 323__END__
324
325=head1 NAME
326
bedd575c 327Mouse::Util - Features, with or without their dependencies
f38ce2d0 328
a25ca8d6 329=head1 VERSION
330
065f79e7 331This document describes Mouse version 0.40_02
a25ca8d6 332
f38ce2d0 333=head1 IMPLEMENTATIONS FOR
334
ea249879 335=head2 Moose::Util
336
337=head3 C<find_meta>
338
339=head3 C<does_role>
340
341=head3 C<resolve_metaclass_alias>
342
343=head3 C<apply_all_roles>
344
345=head3 C<english_list>
346
347=head2 Class::MOP
348
5bacd9bf 349=head3 C<< is_class_loaded(ClassName) -> Bool >>
ea249879 350
1820fffe 351Returns whether C<ClassName> is actually loaded or not. It uses a heuristic which
352involves checking for the existence of C<$VERSION>, C<@ISA>, and any
353locally-defined method.
354
355=head3 C<< load_class(ClassName) >>
356
739525d0 357This will load a given C<ClassName> (or die if it is not loadable).
1820fffe 358This function can be used in place of tricks like
359C<eval "use $module"> or using C<require>.
ea249879 360
5164490d 361=head3 C<< Mouse::Util::class_of(ClassName or Object) >>
739525d0 362
5164490d 363=head3 C<< Mouse::Util::get_metaclass_by_name(ClassName) >>
739525d0 364
5164490d 365=head3 C<< Mouse::Util::get_all_metaclass_instances() >>
739525d0 366
5164490d 367=head3 C<< Mouse::Util::get_all_metaclass_names() >>
739525d0 368
ea249879 369=head2 MRO::Compat
370
371=head3 C<get_linear_isa>
372
373=head2 Sub::Identify
374
375=head3 C<get_code_info>
376
377=head1 UTILITIES FOR MOUSE
378
bedd575c 379=head3 C<not_supported>
f38ce2d0 380
1820fffe 381=head1 SEE ALSO
382
383L<Moose::Util>
384
5164490d 385L<Class::MOP>
1820fffe 386
387L<Sub::Identify>
388
389L<MRO::Compat>
390
f38ce2d0 391=cut
392