File Coverage

blib/lib/Class/AutoloadCAN.pm
Criterion Covered Total %
statement 62 63 98.4
branch 23 26 88.4
condition 2 3 66.6
subroutine 9 9 100.0
pod 0 2 0.0
total 96 103 93.2


line stmt bran cond sub pod time code
1             package Class::AutoloadCAN;
2             $VERSION = 0.03;
3 1     1   1600 use strict;
  1         1  
  1         40  
4 1     1   5 no strict 'refs';
  1         1  
  1         26  
5 1     1   4 use vars qw($AUTOLOAD);
  1         1  
  1         1005  
6              
7             my %base_install;
8              
9             sub import {
10 4     4   657 shift; # Get rid of class
11 4 100       20 @_ = scalar caller unless @_;
12 4         8 for (@_) {
13             # For giggles and grins, archaic compatibility. This should work with
14             # Perl 5.003. (Untested.)
15 4         6 my $class = $_;
16 4         9 $base_install{$class}++;
17 4         2393 *{"$class\::AUTOLOAD"} = sub {
18 5     5   37 my $method = _can($AUTOLOAD, @_);
19 5 100       13 if ($method) {
20 4         8 return &$method;
21             }
22 1         4 my ($package, $file, $line) = caller;
23 1         6 my $where = qq(package "$class" at $file line $line.);
24 1 50       8 if ($AUTOLOAD =~ /(.*)::([^:]+)/) {
25 1         2 my $package = $1;
26 1         2 my $method = $2;
27 1         14 die qq(Can't locate object method "$method" via package "$package" at $where\n);
28             }
29             else {
30 0         0 die qq(AUTOLOAD saw no \$AUTOLOAD after $where\n);
31             }
32 4         21 };
33             }
34             }
35              
36             # The arguments have been rearranged here. That is for the promise I made
37             # that you can do anything with this strategy that you can with AUTOLOAD.
38             # I even support the case where you've AUTOLOADed calling an autoloaded
39             # function directly without arguments.
40             sub _can {
41 990     990   1661 my ($method, @args) = @_;
42 990         1143 my $self = $args[0];
43              
44 990         1052 my %checked;
45             # Need to reset these on the off chance that people are dynamically
46             # changing @ISA. Right behaviour over speed...
47 990         1390 reset_installed();
48              
49 990   66     2117 my $base_class = ref($self) || $self;
50 990         1365 $method =~ s/'/::/g;
51 990 100       2024 if ($method =~ /^(.*)::([^:]+)/) {
52 6         13 $base_class = $1;
53 6         13 $method = $2;
54             }
55 990         979 my %seen;
56 990         1690 my @classes = ($base_class, 'UNIVERSAL');
57 990         2251 while (@classes) {
58 3943         5194 my $class = shift @classes;
59 3943 50       8623 next if $seen{$class}++;
60              
61              
62 3943 100       3770 if (my $CAN = *{"$class\::CAN"}{CODE}) {
  3943         10114  
63             # Need to figure out whether I pay attention to CAN.
64             # I probably do - I'm only called if you inherit from
65             # someone who does, but I might have gone past where I
66             # was installed to, in which case I can prune the
67             # inheritance tree slightly.
68 23 100       39 next unless installed($class);
69 19         46 my $sub = $CAN->($base_class, $method, @args);
70 19 100       178 return $sub if $sub;
71             }
72              
73 3932         4006 unshift @classes, @{"$class\::ISA"};
  3932         51704  
74              
75             }
76             };
77              
78             local $^W;
79             my $original_can = \&UNIVERSAL::can;
80             *UNIVERSAL::can = sub {
81 5688     5688   32969 my $sub = $original_can->(@_[0,1]);
82 5688 100       77983 return $sub if $sub;
83 985         2075 _can(@_[1,0,2..$#_]);
84             };
85              
86             # These hashes track which classes I'm paying attention to CAN in.
87             my %installed;
88             my %not_installed;
89             my %testing_install;
90             sub reset_installed {
91 990     990 0 2551 %installed = %base_install;
92 990         1837 %not_installed = %testing_install = ();
93             }
94              
95             # This function takes a class and sets %installed or %not_installed
96             # appropriately for that class;
97             sub installed {
98 41     41 0 50 my $base_class = shift;
99 41 100       132 return 1 if $installed{$base_class};
100 22 50       47 return if $not_installed{$base_class};
101 22 100       66 return if $testing_install{$base_class}++; # Avoid infinite recursion.
102 18         15 my @classes = (@{"$base_class\::ISA"}, 'UNIVERSAL');
  18         59  
103 18         40 foreach (@classes) {
104             # For giggles and grins, archaic compatibility. This should work with
105             # Perl 5.003. (Untested.)
106 18         20 my $class = $_;
107 18 100       37 return $installed{$base_class} = 1
108             if installed($class);
109             }
110 8         22 $not_installed{$base_class} = 1;
111 8         5155 return;
112             }
113              
114             1;
115              
116             __END__