0.09
[gitmo/MRO-Compat.git] / lib / MRO / Compat.pm
CommitLineData
399a1dc7 1package MRO::Compat;
4c4e4170 2use strict;
3use warnings;
e9b18837 4require 5.006_000;
4c4e4170 5
763002b3 6# Keep this < 1.00, so people can tell the fake
7# mro.pm from the real one
c80e00b4 8our $VERSION = '0.09';
4c4e4170 9
4c4e4170 10BEGIN {
e9b18837 11 # Alias our private functions over to
12 # the mro:: namespace and load
13 # Class::C3 if Perl < 5.9.5
399a1dc7 14 if($] < 5.009_005) {
cbb1ce9a 15 $mro::VERSION # to fool Module::Install when generating META.yml
16 = $VERSION;
7fbc4482 17 $INC{'mro.pm'} = __FILE__;
399a1dc7 18 *mro::import = \&__import;
19 *mro::get_linear_isa = \&__get_linear_isa;
20 *mro::set_mro = \&__set_mro;
21 *mro::get_mro = \&__get_mro;
22 *mro::get_isarev = \&__get_isarev;
23 *mro::is_universal = \&__is_universal;
24 *mro::method_changed_in = \&__method_changed_in;
25 *mro::invalidate_all_method_caches
26 = \&__invalidate_all_method_caches;
a9edfcb9 27 require Class::C3;
28 if($Class::C3::XS::VERSION && $Class::C3::XS::VERSION > 0.03) {
29 *mro::get_pkg_gen = \&__get_pkg_gen_c3xs;
30 }
31 else {
32 *mro::get_pkg_gen = \&__get_pkg_gen_pp;
33 }
4c4e4170 34 }
e9b18837 35
0f01303c 36 # Load mro.pm and provide no-op Class::C3::.*initialize() funcs for 5.9.5+
e9b18837 37 else {
0f01303c 38 require mro;
e9b18837 39 no warnings 'redefine';
40 *Class::C3::initialize = sub { 1 };
41 *Class::C3::reinitialize = sub { 1 };
42 *Class::C3::uninitialize = sub { 1 };
43 }
4c4e4170 44}
45
4c4e4170 46=head1 NAME
47
42915ba4 48MRO::Compat - mro::* interface compatibility for Perls < 5.9.5
4c4e4170 49
50=head1 SYNOPSIS
51
52 package FooClass; use base qw/X Y Z/;
53 package X; use base qw/ZZZ/;
54 package Y; use base qw/ZZZ/;
55 package Z; use base qw/ZZZ/;
56
57 package main;
399a1dc7 58 use MRO::Compat;
4c4e4170 59 my $linear = mro::get_linear_isa('FooClass');
399a1dc7 60 print join(q{, }, @$linear);
4c4e4170 61
62 # Prints: "FooClass, X, ZZZ, Y, Z"
63
64=head1 DESCRIPTION
65
66The "mro" namespace provides several utilities for dealing
399a1dc7 67with method resolution order and method caching in general
68in Perl 5.9.5 and higher.
4c4e4170 69
42915ba4 70This module provides those interfaces for
e9b18837 71earlier versions of Perl (back to 5.6.0 anyways).
72
81350029 73It is a harmless no-op to use this module on 5.9.5+. That
74is to say, code which properly uses L<MRO::Compat> will work
75unmodified on both older Perls and 5.9.5+.
76
77If you're writing a piece of software that would like to use
42915ba4 78the parts of 5.9.5+'s mro:: interfaces that are supported
e9b18837 79here, and you want compatibility with older Perls, this
80is the module for you.
4c4e4170 81
81350029 82Some parts of this code will work better and/or faster with
83L<Class::C3::XS> installed (which is an optional prereq
84of L<Class::C3>, which is in turn a prereq of this
85package), but it's not a requirement.
a9edfcb9 86
399a1dc7 87This module never exports any functions. All calls must
88be fully qualified with the C<mro::> prefix.
4c4e4170 89
a9edfcb9 90The interface documentation here serves only as a quick
91reference of what the function basically does, and what
92differences between L<MRO::Compat> and 5.9.5+ one should
93look out for. The main docs in 5.9.5's L<mro> are the real
94interface docs, and contain a lot of other useful information.
221173f0 95
4c4e4170 96=head1 Functions
97
98=head2 mro::get_linear_isa($classname[, $type])
99
602f6319 100Returns an arrayref which is the linearized "ISA" of the given class.
4c4e4170 101Uses whichever MRO is currently in effect for that class by default,
102or the given MRO (either C<c3> or C<dfs> if specified as C<$type>).
103
602f6319 104The linearized ISA of a class is a single ordered list of all of the
4c4e4170 105classes that would be visited in the process of resolving a method
106on the given class, starting with itself. It does not include any
107duplicate entries.
108
4c4e4170 109Note that C<UNIVERSAL> (and any members of C<UNIVERSAL>'s MRO) are not
110part of the MRO of a class, even though all classes implicitly inherit
111methods from C<UNIVERSAL> and its parents.
112
399a1dc7 113=cut
114
ed71cabb 115sub __get_linear_isa_dfs {
116 no strict 'refs';
117
118 my $classname = shift;
119
120 my @lin = ($classname);
121 my %stored;
122 foreach my $parent (@{"$classname\::ISA"}) {
123 my $plin = __get_linear_isa_dfs($parent);
124 foreach (@$plin) {
125 next if exists $stored{$_};
126 push(@lin, $_);
127 $stored{$_} = 1;
128 }
129 }
130 return \@lin;
131}
132
399a1dc7 133sub __get_linear_isa {
ed71cabb 134 my ($classname, $type) = @_;
81350029 135 die "mro::get_mro requires a classname" if !defined $classname;
ed71cabb 136
137 $type ||= __get_mro($classname);
138 if($type eq 'dfs') {
139 return __get_linear_isa_dfs($classname);
140 }
141 elsif($type eq 'c3') {
142 return [Class::C3::calculateMRO($classname)];
143 }
144 die "type argument must be 'dfs' or 'c3'";
399a1dc7 145}
146
147=head2 mro::import
148
e9b18837 149This allows the C<use mro 'dfs'> and
150C<use mro 'c3'> syntaxes, providing you
151L<use MRO::Compat> first. Please see the
152L</USING C3> section for additional details.
399a1dc7 153
154=cut
155
156sub __import {
e9b18837 157 if($_[1]) {
158 goto &Class::C3::import if $_[1] eq 'c3';
159 __set_mro(scalar(caller), $_[1]);
160 }
399a1dc7 161}
162
4c4e4170 163=head2 mro::set_mro($classname, $type)
164
e9b18837 165Sets the mro of C<$classname> to one of the types
166C<dfs> or C<c3>. Please see the L</USING C3>
167section for additional details.
399a1dc7 168
169=cut
170
171sub __set_mro {
e9b18837 172 my ($classname, $type) = @_;
fd0bf490 173
81350029 174 if(!defined $classname || !$type) {
e9b18837 175 die q{Usage: mro::set_mro($classname, $type)};
176 }
fd0bf490 177
e9b18837 178 if($type eq 'c3') {
179 eval "package $classname; use Class::C3";
180 die $@ if $@;
181 }
fd0bf490 182 elsif($type eq 'dfs') {
183 # In the dfs case, check whether we need to undo C3
184 if(defined $Class::C3::MRO{$classname}) {
185 Class::C3::_remove_method_dispatch_table($classname);
186 }
187 delete $Class::C3::MRO{$classname};
e9b18837 188 }
fd0bf490 189 else {
190 die qq{Invalid mro type "$type"};
e9b18837 191 }
e9b18837 192
193 return;
399a1dc7 194}
4c4e4170 195
196=head2 mro::get_mro($classname)
197
198Returns the MRO of the given class (either C<c3> or C<dfs>).
199
e9b18837 200It considers any Class::C3-using class to have C3 MRO
201even before L<Class::C3::initialize()> is called.
202
399a1dc7 203=cut
204
205sub __get_mro {
ed71cabb 206 my $classname = shift;
81350029 207 die "mro::get_mro requires a classname" if !defined $classname;
e9b18837 208 return 'c3' if exists $Class::C3::MRO{$classname};
399a1dc7 209 return 'dfs';
210}
211
4c4e4170 212=head2 mro::get_isarev($classname)
213
a9edfcb9 214Returns an arrayref of classes who are subclasses of the
215given classname. In other words, classes who we exist,
42915ba4 216however indirectly, in the @ISA inheritancy hierarchy of.
217
218This is much slower on pre-5.9.5 Perls with MRO::Compat
219than it is on 5.9.5+, as it has to search the entire
220package namespace.
399a1dc7 221
222=cut
223
42915ba4 224sub __get_all_pkgs_with_isas {
225 no strict 'refs';
226 no warnings 'recursion';
227
228 my @retval;
229
230 my $search = shift;
231 my $pfx;
232 my $isa;
66b426e8 233 if(defined $search) {
42915ba4 234 $isa = \@{"$search\::ISA"};
235 $pfx = "$search\::";
236 }
237 else {
238 $search = 'main';
239 $isa = \@main::ISA;
240 $pfx = '';
241 }
242
243 push(@retval, $search) if scalar(@$isa);
244
245 foreach my $cand (keys %{"$search\::"}) {
81350029 246 if($cand =~ s/::$//) {
42915ba4 247 next if $cand eq $search; # skip self-reference (main?)
248 push(@retval, @{__get_all_pkgs_with_isas($pfx . $cand)});
249 }
250 }
251
252 return \@retval;
253}
254
255sub __get_isarev_recurse {
256 no strict 'refs';
257
258 my ($class, $all_isas, $level) = @_;
259
260 die "Recursive inheritance detected" if $level > 100;
261
262 my %retval;
263
264 foreach my $cand (@$all_isas) {
265 my $found_me;
266 foreach (@{"$cand\::ISA"}) {
267 if($_ eq $class) {
268 $found_me = 1;
269 last;
270 }
271 }
272 if($found_me) {
273 $retval{$cand} = 1;
274 map { $retval{$_} = 1 }
275 @{__get_isarev_recurse($cand, $all_isas, $level+1)};
276 }
277 }
278 return [keys %retval];
279}
280
399a1dc7 281sub __get_isarev {
42915ba4 282 my $classname = shift;
81350029 283 die "mro::get_isarev requires a classname" if !defined $classname;
42915ba4 284
a9edfcb9 285 __get_isarev_recurse($classname, __get_all_pkgs_with_isas(), 0);
399a1dc7 286}
4c4e4170 287
288=head2 mro::is_universal($classname)
289
290Returns a boolean status indicating whether or not
291the given classname is either C<UNIVERSAL> itself,
292or one of C<UNIVERSAL>'s parents by C<@ISA> inheritance.
293
294Any class for which this function returns true is
295"universal" in the sense that all classes potentially
296inherit methods from it.
297
399a1dc7 298=cut
299
300sub __is_universal {
301 my $classname = shift;
81350029 302 die "mro::is_universal requires a classname" if !defined $classname;
399a1dc7 303
ac5a5a7f 304 my $lin = __get_linear_isa('UNIVERSAL');
399a1dc7 305 foreach (@$lin) {
306 return 1 if $classname eq $_;
307 }
308
309 return 0;
310}
311
312=head2 mro::invalidate_all_method_caches
4c4e4170 313
314Increments C<PL_sub_generation>, which invalidates method
315caching in all packages.
316
a9edfcb9 317Please note that this is rarely necessary, unless you are
318dealing with a situation which is known to confuse Perl's
319method caching.
320
399a1dc7 321=cut
322
323sub __invalidate_all_method_caches {
324 # Super secret mystery code :)
81350029 325 @f845a9c1ac41be33::ISA = @f845a9c1ac41be33::ISA;
399a1dc7 326 return;
327}
328
4c4e4170 329=head2 mro::method_changed_in($classname)
330
331Invalidates the method cache of any classes dependent on the
399a1dc7 332given class. In L<MRO::Compat> on pre-5.9.5 Perls, this is
333an alias for C<mro::invalidate_all_method_caches> above, as
334pre-5.9.5 Perls have no other way to do this. It will still
335enforce the requirement that you pass it a classname, for
336compatibility.
337
a9edfcb9 338Please note that this is rarely necessary, unless you are
339dealing with a situation which is known to confuse Perl's
340method caching.
341
399a1dc7 342=cut
343
344sub __method_changed_in {
345 my $classname = shift;
81350029 346 die "mro::method_changed_in requires a classname" if !defined $classname;
399a1dc7 347
348 __invalidate_all_method_caches();
349}
4c4e4170 350
a9edfcb9 351=head2 mro::get_pkg_gen($classname)
352
353Returns an integer which is incremented every time a local
354method of or the C<@ISA> of the given package changes on
355Perl 5.9.5+. On earlier Perls with this L<MRO::Compat> module,
356it will probably increment a lot more often than necessary.
357
358=cut
359
81350029 360{
361 my $__pkg_gen = 2;
362 sub __get_pkg_gen_pp {
363 my $classname = shift;
364 die "mro::get_pkg_gen requires a classname" if !defined $classname;
365 return $__pkg_gen++;
366 }
a9edfcb9 367}
368
369sub __get_pkg_gen_c3xs {
370 my $classname = shift;
81350029 371 die "mro::get_pkg_gen requires a classname" if !defined $classname;
a9edfcb9 372
373 return Class::C3::XS::_plsubgen();
374}
375
e9b18837 376=head1 USING C3
377
378While this module makes the 5.9.5+ syntaxes
379C<use mro 'c3'> and C<mro::set_mro("Foo", 'c3')> available
380on older Perls, it does so merely by passing off the work
381to L<Class::C3>.
382
383It does not remove the need for you to call
81350029 384C<Class::C3::initialize()>, C<Class::C3::reinitialize()>, and/or
385C<Class::C3::uninitialize()> at the appropriate times
386as documented in the L<Class::C3> docs. These three functions
387are always provided by L<MRO::Compat>, either via L<Class::C3>
388itself on older Perls, or directly as no-ops on 5.9.5+.
e9b18837 389
4c4e4170 390=head1 SEE ALSO
391
392L<Class::C3>
393
399a1dc7 394L<mro>
395
4c4e4170 396=head1 AUTHOR
397
398Brandon L. Black, E<lt>blblack@gmail.comE<gt>
399
400=head1 COPYRIGHT AND LICENSE
401
602f6319 402Copyright 2007-2008 Brandon L. Black E<lt>blblack@gmail.comE<gt>
4c4e4170 403
404This library is free software; you can redistribute it and/or modify
405it under the same terms as Perl itself.
406
407=cut
408
4091;