File Coverage

blib/lib/mro/EVERY.pm
Criterion Covered Total %
statement 44 48 91.6
branch 5 12 41.6
condition n/a
subroutine 14 14 100.0
pod n/a
total 63 74 85.1


line stmt bran cond sub pod time code
1             ########################################################################
2             # housekeeping
3             ########################################################################
4              
5             package mro::EVERY v1.0.0;
6 9     9   5336 use v5.24;
  9         26  
7 9     9   37 use mro;
  9         12  
  9         43  
8              
9 9     9   168 use Carp qw( croak );
  9         13  
  9         375  
10 9     9   39 use Scalar::Util qw( blessed );
  9         13  
  9         345  
11 9     9   52 use Symbol qw( qualify_to_ref );
  9         12  
  9         5291  
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   76 $DB::single = 1;
127              
128 9         14 shift;
129 9         16 my $caller = caller;
130              
131 9         27 for( @_ )
132             {
133 4         22 my ( $status, $arg ) = m{ (no)? (dfs|autoload) }x;
134              
135 4 50       17 if( $arg eq 'dfs' )
    50          
136             {
137             # delay the lookup of mro::get_mro until runtim
138             # to allow classes to fiddle with it at runtime.
139              
140 0 0       0 if( $status )
141             {
142 0         0 delete $class2dfs{ $caller }
143             }
144             else
145             {
146 0         0 $class2dfs{ $caller } = 'dfs'
147             }
148             }
149             elsif( $arg eq 'autoload' )
150             {
151 4 50       9 $finder
152             = $status
153             ? $find_name
154             : $find_auto
155             }
156             else
157             {
158 0         0 croak "Botched EVERY: unknown argument '$_'";
159             }
160             }
161              
162             return
163 9         69 }
164              
165             ########################################################################
166             # pseudo-packages
167             ########################################################################
168              
169             package EVERY;
170 9     9   107 use v5.22;
  9         32  
171 9     9   41 use Carp qw( croak );
  9         16  
  9         393  
172 9     9   48 use List::Util qw( uniq );
  9         13  
  9         1520  
173              
174             our @CARP_NOT = ( __PACKAGE__, qw( mro ) );
175             our $AUTOLOAD = '';
176              
177             AUTOLOAD
178             {
179 26     26   79340 $DB::single = 1;
180              
181 26 50       74 my $proto = shift
182             or croak "Bogus EVERY, called without an object.";
183              
184             # remaining arguments left on the stack.
185              
186             $proto->$_( @_ )
187 26         60 for uniq $proto->$finder( $AUTOLOAD );
188             }
189              
190             package EVERY::LAST;
191 9     9   128 use v5.22;
  9         31  
192 9     9   43 use Carp qw( croak );
  9         14  
  9         334  
193 9     9   47 use List::Util qw( uniq );
  9         21  
  9         1192  
194              
195             our @CARP_NOT = ( __PACKAGE__, qw( mro ) );
196             our $AUTOLOAD = '';
197              
198             AUTOLOAD
199             {
200 26     26   19312 $DB::single = 1;
201              
202 26 50       80 my $proto = shift
203             or croak "Bogus EVERY::LAST, called without an object.";
204              
205             # remaining arguments left on the stack.
206              
207             $proto->$_( @_ )
208 26         52 for uniq reverse $proto->$finder( $AUTOLOAD );
209             }
210              
211             # keep require happy
212             1
213             __END__