File Coverage

blib/lib/MRO/Compat.pm
Criterion Covered Total %
statement 27 133 20.3
branch 1 56 1.7
condition 0 9 0.0
subroutine 9 24 37.5
pod n/a
total 37 222 16.6


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