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