File Coverage

blib/lib/Exporter/Proxy.pm
Criterion Covered Total %
statement 61 74 82.4
branch 14 30 46.6
condition 3 4 75.0
subroutine 13 16 81.2
pod n/a
total 91 124 73.3


line stmt bran cond sub pod time code
1             ########################################################################
2             # housekeeping
3             ########################################################################
4              
5             package Exporter::Proxy;
6              
7 6     6   4241 use v5.12;
  6         18  
8 6     6   29 use strict;
  6         11  
  6         127  
9              
10 6     6   37 use Carp;
  6         9  
  6         461  
11              
12 6     6   30 use List::Util qw( first );
  6         10  
  6         561  
13 6     6   4686 use Symbol qw( qualify_to_ref );
  6         5401  
  6         5886  
14              
15             ########################################################################
16             # package variables
17             ########################################################################
18              
19             our $VERSION = '1.4';
20             $VERSION = eval $VERSION;
21              
22             my $disp_list = 'DISPATCH_OK';
23              
24             ########################################################################
25             # utility functions
26             ########################################################################
27              
28             ########################################################################
29             # methods (public interface)
30             ########################################################################
31              
32             sub import
33             {
34 5     0   48 state $stub = sub{};
        5      
35              
36             # discard this package.
37             # left on the stack are assignment operators and
38             # exported names.
39              
40 5         10 shift;
41              
42             # use "$source" avoid colliding with '$caller' in the
43             # exported subs.
44              
45 5         11 my $source = caller;
46 5         11 my @exportz = grep { ! /=/ } @_;
  8         95  
47             my %argz
48             = map
49             {
50 5         16 split /=/, $_, 2
  2         11  
51             }
52             grep /=/, @_;
53              
54             # maybe carp about extraneous arguments here?
55              
56 5   100     48 my $disp = delete $argz{ dispatch } || '';
57 5   50     53 my $preproc = delete $argz{ prefilter } || '';
58              
59             # if a dispatcher is being used then it must
60             # be exported. in most cases this will be the
61             # only thing exported.
62              
63 5 100       19 if( $disp )
64             {
65 2         8 my $list = qualify_to_ref $disp_list, $source;
66              
67 2     2   6 first { $disp eq $_ } @exportz
68 2 50       64 or push @exportz, $disp;
69              
70 2 50       30 unless( $source->can( $disp ) )
71             {
72 2         10 my $sub = qualify_to_ref $disp, $source;
73 2         34 my $can = qualify_to_ref $disp_list, $source;
74              
75 2 50       28 if( my $sanity = *{ $can }{ ARRAY } )
  2         9  
76             {
77             *$sub
78             = sub
79             {
80 0     0   0 my $op = splice @_, 1, 1;
81              
82 0         0 first { $op eq $_ } @$sanity
83             or do
84 0 0       0 {
85 0         0 local $" = ' ';
86              
87 0         0 confess "Bogus $disp: '$op' not in @$sanity"
88             };
89              
90             # this could happen if someone plays with
91             # the symbol table after installing the sub.
92              
93 0 0       0 my $handler = $source->can( $op )
94             or croak "Bogus $disp: $source cannot '$op'";
95              
96 0         0 goto &$handler
97 0         0 };
98             }
99             else
100             {
101             *$sub
102             = sub
103             {
104 4     4   24356 my $op = splice @_, 1, 1;
105              
106 4 50       35 my $handler = $source->can( $op )
107             or croak "Bogus $disp: $source cannot '$op'";
108              
109 4         17 goto &$handler
110 2         10 };
111             }
112             }
113             }
114              
115             my $pre_handler
116             = do
117 5         7 {
118 5 50       15 if( $preproc )
119             {
120             sub
121             {
122 0 0   0   0 my $handler = $source->can( $preproc )
123             or die "$source cannot '$preproc'\n";
124              
125 0         0 &$handler
126             }
127 0         0 }
128             else
129             {
130       4     state $stub = sub{}
131 5         17 }
132             };
133              
134             @exportz
135 5 50       18 or carp "Oddity: nothing requested for export!";
136              
137 5         16 my $exports = qualify_to_ref 'exports', $source;
138 5         103 my $import = qualify_to_ref 'import', $source;
139              
140 5         164 undef &{ *$_ } for ( $exports, $import );
  10         65  
141              
142             *$exports
143             = sub
144             {
145             # avoid giving away ref's to the closed-over
146             # variable.
147              
148             wantarray
149             ? @exportz
150 4 50   4   2640 : [ @exportz ]
151 5         22 };
152              
153             *$import
154             = sub
155             {
156             # discard the package as first argument:
157             # $pkg->import
158              
159 4     4   81 shift;
160              
161 4         12 my $caller = caller;
162            
163             # allow the caller to pre-process the arguments.
164             # notice this happens *before* ":noexport" is
165             # processed.
166              
167 4         15 &$pre_handler;
168              
169             # empty list => use @exportz.
170             # :noexport => use empty list.
171              
172 4 50   3   51 if( first { ':noexport' eq $_ } @_ )
  3 100       15  
173             {
174 0         0 @_ = ();
175             }
176             elsif( @_ )
177             {
178             # nothing more for the moment.
179             }
180             else
181             {
182 2         7 @_ = @exportz;
183             }
184              
185             # resolve these at runtime to account for
186             # possible autoloading, etc.
187              
188 4         20 for my $arg ( @_ )
189             {
190 5 50       24 index $arg, ':'
191             or next;
192              
193 5 50   7   47 if( first { $arg eq $_ } @exportz )
  7         38  
194             {
195 5         24 my $source = qualify_to_ref $arg, $source;
196 5         117 my $install = qualify_to_ref $arg, $caller;
197              
198 5         109 *$install = *$source;
199             }
200             else
201             {
202 0         0 die "Bogus $source: '$arg' not exported";
203             }
204             }
205 5         24 };
206              
207             return
208 5         425 }
209              
210             # keep require happy
211              
212             1
213              
214             __END__