File Coverage

blib/lib/mro/EVERY.pm
Criterion Covered Total %
statement 41 45 91.1
branch 5 12 41.6
condition n/a
subroutine 14 14 100.0
pod n/a
total 60 71 84.5


line stmt bran cond sub pod time code
1             ########################################################################
2             # housekeeping
3             ########################################################################
4              
5             package mro::EVERY v1.0.1;
6 9     9   6867 use v5.24;
  9         32  
7 9     9   41 use mro;
  9         20  
  9         60  
8              
9 9     9   218 use Carp qw( croak );
  9         19  
  9         549  
10 9     9   50 use Scalar::Util qw( blessed );
  9         16  
  9         462  
11 9     9   52 use Symbol qw( qualify_to_ref );
  9         17  
  9         6873  
12              
13             ########################################################################
14             # package varaibles
15             ########################################################################
16              
17             our @CARP_NOT = ( __PACKAGE__, qw( mro ) );
18             my %class2dfs = ();
19              
20             ########################################################################
21             # utility subs
22             ########################################################################
23              
24             my $find_name
25             = sub
26             {
27             my $proto = shift;
28             my $auto = shift;
29             my ($name) = $auto =~ m{ (\w+) $}x;
30             my $class = blessed $proto || $proto;
31              
32             $proto->can( $name )
33             or croak "Botched EVERY: '$proto' cannot '$name'";
34              
35             # class at entry point gets to decide the mro type.
36              
37             my $mro = $class2dfs{ $class } || $class->mro::get_mro;
38             my @isa = $class->mro::get_linear_isa( $mro )->@*;
39              
40             # @found preserves array context of map.
41             #
42             # this should never croak afer the can
43             # check unless they have an overloaded
44             # can and forgot qw( autoload );
45              
46             my @found
47             = map
48             {
49             *{ qualify_to_ref $name => $_ }{ CODE }
50             or
51             ()
52             }
53             @isa
54             or
55             croak "Bogus $proto: '$name' not in @isa";
56              
57             @found
58             };
59              
60             my $find_auto
61             = sub
62             {
63             my $proto = shift;
64             my $auto = shift;
65             my ($name) = $auto =~ m{ (\w+) $}x;
66              
67             $proto->can( $name )
68             or croak "Botched EVERY: '$proto' cannot '$name'";
69              
70             local $" = ',';
71             my @isa = $proto->mro::get_linear_isa->@*;
72              
73             # @found preserves array context of map.
74              
75             my @found
76             = grep
77             {
78             $_
79             }
80             map
81             {
82             *{ qualify_to_ref $name => $_ }{ CODE }
83             or
84             do
85             {
86             my $isa = qualify_to_ref ISA => $_;
87             my $ref = qualify_to_ref AUTOLOAD => $_;
88              
89             local *$isa = [];
90              
91             # at this point can is isolated to the
92             # single pacakge.
93              
94             my $al
95             = $_->can( $name )
96             ? *{ $ref }{ CODE }
97             : ''
98             ;
99              
100             $al
101             ? sub
102             {
103             # at this point if package can $name and
104             # has an AUTOLOAD but not the named sub.
105             #
106             # install $AUTOLOAD and bon voyage!
107              
108             local *{ $ref } = $auto;
109             goto &$al;
110             }
111             : ()
112             ;
113             }
114             }
115             @isa
116             or
117             croak "Bogus $proto: '$name' & AUTOLOAD not in @isa";
118              
119             @found
120             };
121              
122             my $finder = $find_name;
123              
124             sub import
125             {
126 9     9   87 shift;
127 9         22 my $caller = caller;
128              
129 9         23 for( @_ )
130             {
131 4         35 my ( $status, $arg ) = m{ (no)? (dfs|autoload) }x;
132              
133 4 50       22 if( $arg eq 'dfs' )
    50          
134             {
135             # delay the lookup of mro::get_mro until runtim
136             # to allow classes to fiddle with it at runtime.
137              
138 0 0       0 if( $status )
139             {
140 0         0 delete $class2dfs{ $caller }
141             }
142             else
143             {
144 0         0 $class2dfs{ $caller } = 'dfs'
145             }
146             }
147             elsif( $arg eq 'autoload' )
148             {
149 4 50       15 $finder
150             = $status
151             ? $find_name
152             : $find_auto
153             }
154             else
155             {
156 0         0 croak "Botched EVERY: unknown argument '$_'";
157             }
158             }
159              
160             return
161 9         96 }
162              
163             ########################################################################
164             # pseudo-packages
165             ########################################################################
166              
167             package EVERY;
168 9     9   131 use v5.22;
  9         39  
169 9     9   60 use Carp qw( croak );
  9         19  
  9         537  
170 9     9   59 use List::Util qw( uniq );
  9         17  
  9         2259  
171              
172             our @CARP_NOT = ( __PACKAGE__, qw( mro ) );
173             our $AUTOLOAD = '';
174              
175             AUTOLOAD
176             {
177 26 50   26   107934 my $proto = shift
178             or croak "Bogus EVERY, called without an object.";
179              
180             # remaining arguments left on the stack.
181              
182             $proto->$_( @_ )
183 26         69 for uniq $proto->$finder( $AUTOLOAD );
184             }
185              
186             package EVERY::LAST;
187 9     9   118 use v5.22;
  9         32  
188 9     9   51 use Carp qw( croak );
  9         24  
  9         418  
189 9     9   52 use List::Util qw( uniq );
  9         17  
  9         1491  
190              
191             our @CARP_NOT = ( __PACKAGE__, qw( mro ) );
192             our $AUTOLOAD = '';
193              
194             AUTOLOAD
195             {
196 26 50   26   26517 my $proto = shift
197             or croak "Bogus EVERY::LAST, called without an object.";
198              
199             # remaining arguments left on the stack.
200              
201             $proto->$_( @_ )
202 26         64 for uniq reverse $proto->$finder( $AUTOLOAD );
203             }
204              
205             # keep require happy
206             1
207             __END__