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