File Coverage

blib/lib/Exporter/Extensible.pm
Criterion Covered Total %
statement 340 383 88.7
branch 180 284 63.3
condition 108 213 50.7
subroutine 43 49 87.7
pod 9 25 36.0
total 680 954 71.2


line stmt bran cond sub pod time code
1             package Exporter::Extensible;
2 12     12   10730 use v5;
  12         47  
3 12     12   71 use strict; no strict 'refs';
  12     12   22  
  12         294  
  12         59  
  12         21  
  12         394  
4 12     12   66 use warnings; no warnings 'redefine';
  12     12   21  
  12         397  
  12         67  
  12         32  
  12         6900  
5             require Exporter::Extensible::Compat if "$]" < "5.012";
6             require mro;
7              
8             # ABSTRACT: Create easy-to-extend modules which export symbols
9             our $VERSION = '0.08'; # VERSION
10              
11             our %EXPORT_FAST_SUB_CACHE;
12             our %EXPORT_PKG_CACHE;
13             our %EXPORT_TAGS_PKG_CACHE;
14              
15             our %EXPORT= (
16             -exporter_setup => [ 'exporter_setup', 1 ],
17             );
18              
19             our %sigil_to_reftype= (
20             '$' => 'SCALAR',
21             '@' => 'ARRAY',
22             '%' => 'HASH',
23             '*' => 'GLOB',
24             '&' => 'CODE',
25             '' => 'CODE',
26             '-' => 'CODE',
27             );
28             our %reftype_to_sigil= (
29             'SCALAR' => '$',
30             'ARRAY' => '@',
31             'HASH' => '%',
32             'GLOB' => '*',
33             'CODE' => '',
34             );
35             our %sigil_to_generator_prefix= (
36             '$' => [ '_generateSCALAR_', '_generateScalar_' ],
37             '@' => [ '_generateARRAY_', '_generateArray_' ],
38             '%' => [ '_generateHASH_', '_generateHash_' ],
39             '*' => [ '_generateGLOB_', '_generateGlob_' ],
40             '&' => [ '_generate_', '_generateCODE_', '_generateCode' ],
41             );
42             $sigil_to_generator_prefix{''}= $sigil_to_generator_prefix{'&'};
43             our %ord_is_sigil= ( ord '$', 1, ord '@', 1, ord '%', 1, ord '*', 1, ord '&', 1, ord '-', 1, ord ':', 1 );
44             our %ord_is_directive= ( ord '-', 1, ord ':', 1 );
45              
46             my ($carp, $croak, $weaken, $colon, $hyphen);
47             $carp= sub { require Carp; $carp= \&Carp::carp; goto $carp; };
48             $croak= sub { require Carp; $croak= \&Carp::croak; goto $croak; };
49             $weaken= sub { require Scalar::Util; $weaken= \&Scalar::Util::weaken; goto $weaken; };
50             $colon= ord ':';
51             $hyphen= ord '-';
52              
53             sub import {
54 105     105   42776 my $self= shift;
55             # Can be called as class method or instance method
56 105 100       499 $self= bless { into => scalar caller }, $self
57             unless ref $self;
58             # Optional config hash might be given as first argument
59 105 100       408 $self->exporter_apply_global_config(shift)
60             if ref $_[0] eq 'HASH';
61 105         209 my $class= ref $self;
62 105 100       378 my @todo= @_? @_ : @{ $self->exporter_get_tag('default') || [] };
  14 100       45  
63 105 100       448 return 1 unless @todo;
64             # If only installing subs without generators or unusual options, use a more direct code path.
65             # This only takes effect the second time a symbol is requested, since the cache is not pre-populated.
66             # (abuse a while loop as a if/goto construct)
67 93   100     517 fast: while (!$self->{_complex} && !grep ref, @todo) {
68 68   100     229 my $fastsub= $EXPORT_FAST_SUB_CACHE{$class} || last; # can't optimize if no cache is built
69 15         37 my $prefix= $self->{into}.'::'; # {into} can be a hashref, but not when {_complex} is false
70 15   100     48 my $replace= $self->{replace} || 'carp';
71 15 100       46 if ($replace eq 'carp') {
    100          
72             # Use perl's own warning system to detect attempts to overwrite the GLOB. Only warn if the
73             # new reference isn't the same as existing.
74 12     12   103 use warnings 'redefine';
  12         24  
  12         77585  
75 11 0   0   88 local $SIG{__WARN__}= sub { *{$prefix.$_}{CODE} == $fastsub->{$_} or $carp->($_[0]) };
  0         0  
  0         0  
76 10         87 ord == $colon || (*{$prefix.$_}= ($fastsub->{$_} || last fast))
77 11   100     109 for @todo;
      66        
78             }
79             elsif ($replace eq 1) {
80 4         22 ord == $colon || (*{$prefix.$_}= ($fastsub->{$_} || last fast))
81 2   50     9 for @todo;
      66        
82             }
83 2         5 else { last } # replace==croak and replace==skip require more logic
84             # Now apply any tags that were requested. Each will get its own determination of whether it
85             # can use the 'fast' method.
86 3         11 ord == $colon && $self->import(@{$self->exporter_get_tag(substr $_, 1)})
87 7   66     32 for @todo;
88 7         54 return 1;
89             }
90 86         263 my $install= $self->_exporter_build_install_set(\@todo);
91              
92             # Install might actually be uninstall. It also might be overridden by the user.
93             # The exporter_combine_config sets this up so we don't need to think about details.
94 86   33     372 my $method= $self->{installer} || ($self->{no}? 'exporter_uninstall' : 'exporter_install');
95             # Convert
96             # { foo => { SCALAR => \$foo, HASH => \%foo } }
97             # into
98             # [ foo => \$foo, foo => \%foo ]
99 86         251 my @flat_install= %$install;
100 86         239 for my $i (reverse 1..$#flat_install) {
101 103 100       269 if (ref $flat_install[$i] eq 'HASH') {
102 9         22 splice @flat_install, $i-1, 2, map +($flat_install[$i-1] => $_), values %{$flat_install[$i]};
  9         66  
103             }
104             }
105             # Then pass that list to the installer (or uninstaller)
106 86         439 $self->$method(\@flat_install);
107             # If scope requested, create the scope-guard object
108 84 100       213 if (my $scope= $self->{scope}) {
109 1         5 $$scope= bless [ $self, \@flat_install ], 'Exporter::Extensible::UnimportScopeGuard';
110 1         4 $weaken->($self->{scope});
111             }
112             # It's entirely likely that a generator might curry $self inside the sub it generated.
113             # So, we end up with a circular reference if we're holding onto the set of all things we
114             # exported. Clear the set.
115 84         172 %$install= ();
116 84         2826 1;
117             }
118              
119             sub _exporter_build_install_set {
120 87     87   170 my ($self, $todo)= @_;
121 87         183 $self->{todo}= $todo;
122 87   100     337 my $install= $self->{install_set} ||= {};
123 87   100     292 my $inventory= $EXPORT_PKG_CACHE{ref $self} ||= {};
124 87         212 while (@$todo) {
125 139         260 my $symbol= shift @$todo;
126            
127             # If it is a tag, then recursively call import on that list
128 139 100       315 if (ord $symbol == $colon) {
129 13         34 my $name= substr $symbol, 1;
130 13 50       51 my $tag_cache= $self->exporter_get_tag($name)
131             or $croak->("Tag ':$name' is not exported by ".ref($self));
132             # If first element of tag is a hashref, they count as nested global options.
133             # If tag was followed by hashref, those are user-supplied options.
134 13 100 66     123 if (ref $tag_cache->[0] eq 'HASH' || ref $todo->[0] eq 'HASH') {
135 1         3 $tag_cache= [ @$tag_cache ]; # don't destroy cache
136 1         4 my $self2= $self;
137 1 50       3 $self2= $self2->exporter_apply_global_config(shift @$tag_cache)
138             if ref $tag_cache->[0] eq 'HASH';
139 1 50       9 $self2= $self2->exporter_apply_inline_config(shift @$todo)
140             if ref $todo->[0] eq 'HASH';
141 1 50       4 if ($self != $self2) {
142 1         18 $self2->_exporter_build_install_set($tag_cache);
143 1         4 next;
144             }
145             }
146 12         52 unshift @$todo, @$tag_cache;
147 12         38 next;
148             }
149             # Else, it is an option or plain symbol to be exported
150             # Check current package cache first, else do the full lookup.
151 126 100       452 my $ref= (exists $inventory->{$symbol}? $inventory->{$symbol} : $self->exporter_get_inherited($symbol))
    50          
152             or $croak->("'$symbol' is not exported by ".ref($self));
153            
154             # If it starts with '-', it is an option, and might consume additional args
155 126 100       253 if (ord $symbol == $hyphen) {
156 39         90 my ($method, $count)= @$ref;
157 39 100       130 if ($count eq '*') {
    100          
158 4         61 my $consumed= $self->$method(@$todo);
159 4 50       1514 $consumed =~ /^[0-9]+$/ or $croak->("Method $method in ".ref($self)." must return a number of arguments consumed");
160 4         18 splice(@$todo, 0, $consumed);
161             }
162             elsif ($count eq '?') {
163 3 100       8 if (ref $todo->[0]) {
164 1         2 my $arg= shift @$todo;
165 1 50       10 (ref $arg eq 'HASH'? $self->exporter_apply_inline_config($arg) : $self)
166             ->$method($arg);
167             } else {
168 2         37 $self->$method();
169             }
170             }
171             else {
172 32         198 $self->$method(splice(@$todo, 0, $count));
173             }
174             }
175             else {
176 87 100       292 my ($sigil, $name)= $ord_is_sigil{ord $symbol}? ( substr($symbol,0,1), substr($symbol,1) ) : ( '', $symbol );
177 87         152 my $self2= $self;
178             # If followed by a hashref, add those options to the current ones.
179 87 100       241 $self2= $self->exporter_apply_inline_config(shift @$todo)
180             if ref $todo->[0] eq 'HASH';
181 87 100       183 if ($self2->{_name_mangle}) {
182 33 100 100     94 next if defined $self2->{not} and $self2->_exporter_is_excluded($symbol);
183 23   66     122 $name= delete $self2->{as} || ($self2->{prefix}||'') . $name . ($self2->{suffix}||'');
184             # If 'as' was the only reason for _name_mangle, then disable it to return to fast-path
185 23 100 100     129 delete $self2->{_name_mangle} unless defined $self2->{prefix} || defined $self2->{suffix} || defined $self2->{not};
      100        
186             }
187             # If $ref is a generator (ref-ref) then run it, unless it was already run for the
188             # current symbol exporting to the current dest.
189 77 100       180 if (ref $ref eq 'REF') {
190 6   33     31 $ref= $self2->{_generator_cache}{$symbol.";".$name} ||= do {
191             # Run the generator.
192 6         12 my $method= $$ref;
193 6 100       15 $method= $$method unless ref $method eq 'CODE';
194 6         114 $self2->$method($symbol, $self2->{generator_arg});
195             };
196             # Verify generator output matches sigil
197             ref $ref eq $sigil_to_reftype{$sigil} or (ref $ref eq 'REF' && $sigil eq '$')
198             or $croak->("Trying to export '$symbol', but generator returned "
199 6 0 0     1079 .ref($ref).' (need '.$sigil_to_reftype{$sigil}.')');
      33        
200             }
201             # Check for collisions. Unlikely scenario in typical usage, but could occur if two
202             # tags include the same symbol, or if user adds a prefix or suffix that collides
203             # with another exported name.
204 77 50       204 if ($install->{$name}) {
    100          
205 0 0       0 if ($install->{$name} != $ref) { # most common case of duplicate export, ignore it.
206 0 0 0     0 if (ref $ref eq 'GLOB' || ref $install->{$name} eq 'GLOB') {
207             # globrefs will never be equal - compare the glob itself.
208 0         0 ref $ref eq 'GLOB' && ref $install->{dest} eq 'GLOB' && *{$install->{$name}} eq *$ref
209             # can't install an entire glob at the same time as a piece of a glob.
210 0 0 0     0 or $croak->("Can't install ".ref($ref)." and ".$install->{dest}." into the same symbol '".$name."'");
      0        
211             }
212             # Upgrade this item to a hashref of reftype if it wasn't already (hashrefs are always stored this way)
213             $install->{$name}= { ref($install->{$name}) => $install->{$name} }
214 0 0       0 unless ref $install->{$name} eq 'HASH';
215             # Assign this new ref into a slot of that hash, unless something different was already there
216 0 0 0     0 ($install->{$name}{ref $ref} ||= $ref) == $ref
217             or $croak->("Trying to import conflicting ".ref($ref)." values for '".$name."'");
218             }
219             }
220             # Only make install->{$name} a hashref if we really have to, for performance.
221             elsif (ref $ref eq 'HASH') {
222 9         46 $install->{$name}{HASH}= $ref;
223             }
224             else {
225 68         222 $install->{$name}= $ref;
226             }
227             }
228             }
229 87         345 return $install;
230             }
231              
232             sub Exporter::Extensible::UnimportScopeGuard::clean {
233 1     1   2 my $self= shift;
234 1 50       9 $self->[0]->exporter_uninstall($self->[1]) if $self->[1];
235 1         12 $self->[1]= undef; # Ignore subsequent calls
236             }
237              
238             sub Exporter::Extensible::UnimportScopeGuard::DESTROY {
239 1     1   683 shift->clean;
240             }
241              
242             sub exporter_install {
243 79     79 0 186 my $self= shift;
244 79 50       197 my $into= $self->{into} or $croak->("'into' must be defined before exporter_install");
245 79 100       170 return $self->_exporter_install_to_ref(@_) if ref $into;
246 77   100     227 my $replace= $self->{replace} || 'warn';
247 77         114 my $stash= \%{$into.'::'};
  77         290  
248 77 50 33     345 my $list= @_ == 1 && ref $_[0] eq 'ARRAY'? $_[0] : \@_;
249 77         235 for (my $i= 0; $i < @$list; $i+= 2) {
250 65         124 my ($name, $ref)= @{$list}[$i..1+$i];
  65         158  
251 65         181 my $pkg_dest= $into.'::'.$name;
252             # Each value is either a hashref with keys matching the parts of a typeglob,
253             # or it is a single ref that can be assigned directly to the typeglob.
254 65 100 100     221 if (defined $stash->{$name} and $replace ne 1) {
255             # there is actually no way I know of to test existence of *foo{SCALAR}.
256             # It auto-vivifies when accessed.
257             my $conflict= (ref $ref eq 'GLOB')? $stash->{$name} ne *$ref
258             : (ref $ref eq 'SCALAR')? 0 # TODO: How to test existence of *foo{SCALAR} ? It auto-vivifies
259 19 100 100     160 : (*$pkg_dest{ref $ref} && *$pkg_dest{ref $ref} != $ref);
    50          
260 19 100       46 if ($conflict) {
261 4 100       10 next if $replace eq 'skip';
262 3         10 $name= $reftype_to_sigil{ref $ref} . $name; # include sigil for user's benefit
263 3 100       119 $replace eq 'warn'? $carp->("Overwriting '$name' with $ref from ".ref($self))
264             : $croak->("Refusing to overwrite '$name' with $ref from ".ref($self));
265             }
266             }
267 62         318 *$pkg_dest= $ref;
268             }
269             }
270              
271             sub exporter_uninstall {
272 8     8 0 43 my $self= shift;
273 8 50       41 my $into= $self->{into} or $croak->("'into' must be defined before exporter_uninstall");
274 8 100       22 return $self->_exporter_install_to_ref(@_) if ref $into;
275 7         12 my $stash= \%{$into.'::'};
  7         23  
276 7 50 33     54 my $list= @_ == 1 && ref $_[0] eq 'ARRAY'? $_[0] : \@_;
277 7         22 for (my $i= 0; $i < @$list; $i+= 2) {
278 9         19 my ($name, $ref)= @{$list}[$i..1+$i];
  9         34  
279             # Each value is either a hashref with keys matching the parts of a typeglob,
280             # or it is a single ref that can be assigned directly to the typeglob.
281 9 100       42 if (ref $ref eq 'GLOB') {
282             # If the value we installed is no longer there, do nothing
283 1 50 50     19 next unless *$ref eq ($stash->{$name}||'');
284 1         8 delete $stash->{$name};
285             }
286             else {
287 8         22 my $pkg_dest= $into.'::'.$name;
288             # If the value we installed is no longer there, do nothing
289 8 50 50     12 next unless $ref == (*{$pkg_dest}{ref $ref}||0);
290             # Remove old typeglob, then copy all slots except reftype back to that typeglob name
291 8         33 my $old= delete $stash->{$name};
292 32         143 ($_ ne ref $ref) && *{$old}{$_} && (*$pkg_dest= *{$old}{$_})
  12         77  
293 8   100     43 for qw( SCALAR HASH ARRAY CODE IO );
      100        
294             }
295             }
296             }
297              
298             sub _exporter_install_to_ref {
299 3     3   5 my $self= shift;
300 3         6 my $into= $self->{into};
301 3 50       7 ref $into eq 'HASH' or $croak->("'into' must be a hashref");
302 3   50     11 my $replace= $self->{replace} || 'warn';
303 3 50 33     12 my $list= @_ == 1 && ref $_[0] eq 'ARRAY'? $_[0] : \@_;
304 3         9 for (my $i= 0; $i < @$list; $i+= 2) {
305 6         11 my ($name, $ref)= @{$list}[$i..1+$i];
  6         13  
306 6         16 $name= $reftype_to_sigil{ref $ref} . $name; # include sigil when installing to hashref
307 6 100       12 if ($self->{no}) {
308 1         4 delete $into->{$name};
309             }
310             else {
311 5 50 33     11 if (defined $into->{$name} && $into->{name} != $ref) {
312 0 0       0 $replace eq 'skip' and next;
313 0 0       0 $replace eq 'warn' and $carp->("Overwriting '$name' with $ref from ".ref($self));
314 0 0       0 $replace eq 'die' and $croak->("Refusing to overwrite '$name' with $ref from ".ref($self));
315             }
316 5         15 $into->{$name}= $ref;
317             }
318             }
319             }
320              
321 4 50   4 0 17 sub exporter_config_prefix { $_[0]->_exporter_set_attr(prefix => $_[1]) if @_ > 1; $_[0]{prefix} }
  4         9  
322 3 50   3 0 13 sub exporter_config_suffix { $_[0]->_exporter_set_attr(suffix => $_[1]) if @_ > 1; $_[0]{suffix} }
  3         6  
323 6 50   6 0 24 sub exporter_config_as { $_[0]->_exporter_set_attr(as => $_[1]) if @_ > 1; $_[0]{as} }
  6         24  
324 7 50   7 0 34 sub exporter_config_no { $_[0]->_exporter_set_attr(no => $_[1]) if @_ > 1; $_[0]{no} }
  7         17  
325 50 50   50 0 275 sub exporter_config_into { $_[0]->_exporter_set_attr(into => $_[1]) if @_ > 1; $_[0]{into} }
  50         116  
326 1 50   1 0 5 sub exporter_config_scope { $_[0]->_exporter_set_attr(scope => $_[1]) if @_ > 1; $_[0]{scope}; }
  1         3  
327 5 50   5 0 22 sub exporter_config_not { $_[0]->_exporter_set_attr(not => $_[1]) if @_ > 1; $_[0]{not}; }
  5         10  
328 0 0   0 0 0 sub exporter_config_installer { $_[0]->_exporter_set_attr(installer => $_[1]) if @_ > 1; $_[0]{installer}; }
  0         0  
329              
330             sub _exporter_set_attr {
331 76     76   163 my ($self, $name, $val)= @_;
332 76         162 $self->{$name}= $val;
333             # After changing config, update the optimization flags.
334             # _name_mangle is set if there is any deviation from normal installation of the symbol name
335             $self->{_name_mangle}= defined $self->{not}
336             || defined $self->{as}
337             || (defined $self->{prefix} && length $self->{prefix})
338 76   100     612 || (defined $self->{suffix} && length $self->{suffix});
339             # _complex is set if the required algorithm is anything more than a simple *{$into.'::'.$name}= $ref
340             # but 'replace' does not trigger _complex currently because I handled that in the fast installer.
341             $self->{_complex}= $self->{no} || $self->{_name_mangle}
342             || defined $self->{scope}
343 76   66     522 || $self->{installer} || ref $self->{into};
344             }
345              
346             our %replace_aliases= (
347             1 => 1,
348             carp => 'carp',
349             warn => 'carp',
350             croak => 'croak',
351             fatal => 'croak',
352             die => 'croak',
353             skip => 'skip',
354             );
355             sub exporter_config_replace {
356 11 50 33 11 0 49 $_[0]{replace}= $replace_aliases{$_[1]} or $croak->("Invalid 'replace' value: '$_[1]'")
357             if @_ > 1;
358 11         24 $_[0]{replace};
359             }
360              
361             sub exporter_apply_global_config {
362 55     55 0 127 my ($self, $conf)= @_;
363 55         177 for my $k (keys %$conf) {
364 76 0 0     450 my $setter= $self->can('exporter_config_'.$k)
      33        
365             or (substr($k,0,1) eq '-' && $self->can('exporter_config_'.substr($k,1)))
366             or $croak->("No such exporter configuration '$k'");
367 76         221 $self->$setter($conf->{$k});
368             }
369 55         101 $self;
370             }
371              
372             sub exporter_apply_inline_config {
373 11     11 0 62 my ($self, $conf)= @_;
374 11         48 my @for_global_config= grep ord == $hyphen, keys %$conf;
375             # In the event that only "-as" was given, we don't actually need to create a new object
376 11 100 100     66 if (@for_global_config == 1 && $for_global_config[0] eq '-as' && keys %$conf == 1) {
      100        
377 5         24 $self->exporter_config_as($conf->{-as});
378 5         22 return $self;
379             }
380             # Else clone and apply temporary settings
381 6         38 my $self2= bless { %$self, parent => $self }, ref $self;
382 6         18 for my $k (@for_global_config) {
383 6 50       66 my $setter= $self2->can('exporter_config_'.substr($k,1))
384             or $croak->("No such exporter configuration '$k'");
385 6         34 $self2->$setter($conf->{$k});
386             }
387             # If any options didn't start with '-', then the config becomes a parameter to the generator.
388             # The generator cache isn't valid for $self2 since the arg changed.
389 6 100       25 if (@for_global_config < scalar keys %$conf) {
390 2         6 $self2->{generator_arg}= $conf;
391 2         4 delete $self2->{_generator_cache};
392             }
393 6         41 $self2;
394             }
395              
396             sub unimport {
397             # If first option is a hashref (global options), merge that with { no => 1 }
398 7 100   7   8215 my %opts= ( (ref $_[1] eq 'HASH'? %{splice(@_,1,1)} : () ), no => 1 );
  2         12  
399             # Use this as the global options
400 7         21 splice @_, 1, 0, \%opts;
401 7         74 goto $_[0]->can('import'); # to preserve caller
402             }
403              
404             sub import_into {
405 39 100   39 1 48152 shift->import({ into => shift, (ref $_[0] eq 'HASH'? %{+shift} : ()) }, @_);
  15         98  
406             }
407              
408             sub exporter_register_symbol {
409 4     4 1 380 my ($class, $export_name, $ref)= @_;
410 4   33     14 $class= ref($class)||$class;
411 4 50 33     12 $ref ||= $class->_exporter_get_ref_to_package_var($export_name)
412             or $croak->("Symbol $export_name not found in package $class");
413 4         6 ${$class.'::EXPORT'}{$export_name}= $ref;
  4         53  
414             }
415              
416             sub exporter_autoload_symbol {
417 0     0 1 0 my ($class, $export_name)= @_;
418 0         0 return;
419             }
420              
421             sub exporter_get_inherited {
422 58     58 0 121 my ($self, $sym)= @_;
423 58   33     144 my $class= ref($self)||$self;
424             # Make the common case fast.
425             return $EXPORT_PKG_CACHE{$class}{$sym} ||=
426 58   33     197 do {
      33        
427             my $x;
428             # quick check of own package first
429             unless ($x= ${$class.'::EXPORT'}{$sym}) {
430             # search package hierarchy
431             ($x= ${$_.'::EXPORT'}{$sym}) && last for @{ mro::get_linear_isa($class) }
432             }
433             # If it is a plain sub, it is elligible for "fast export"
434             $EXPORT_FAST_SUB_CACHE{$class}{$sym}= $x if ref $x eq 'CODE' and !$ord_is_sigil{ord $sym};
435             #print "# ref=".ref($x)." sym=$sym\n";
436             $x;
437             }
438             # Isn't exported, but maybe autoload.
439             || $self->exporter_autoload_symbol($sym);
440             }
441              
442             sub exporter_register_option {
443 7     7 1 25 my ($class, $option_name, $method_name, $arg_count)= @_;
444 7   33     31 $class= ref($class)||$class;
445 7   100     49 ${$class.'::EXPORT'}{'-'.$option_name}= [ $method_name, $arg_count||0 ];
  7         127  
446             }
447              
448             sub exporter_register_generator {
449 7     7 1 15 my ($class, $export_name, $method_name)= @_;
450 7   33     25 $class= ref($class)||$class;
451 7 50       18 if (ord $export_name == $colon) {
452 0 0 0     0 (${$class.'::EXPORT_TAGS'}{substr($export_name,1)} ||= $method_name) eq $method_name
  0         0  
453             or $croak->("Cannot set generator for $export_name when that tag is already populated within this class ($class)");
454             } else {
455             # If method name is a scalar, make it a scalar-ref-ref. If it is a coderef, make it a coderef-ref
456 7 50       26 ${$class.'::EXPORT'}{$export_name}= ref $method_name? \$method_name : \\$method_name;
  7         39  
457             }
458             }
459              
460             sub exporter_register_tag_members {
461 7     7 1 17 my ($class, $tag_name)= (shift, shift);
462 7   33     26 $class= ref($class)||$class;
463 7         12 push @{ ${$class.'::EXPORT_TAGS'}{$tag_name} }, @_;
  7         11  
  7         56  
464             }
465              
466             sub _exporter_build_tag_cache {
467 26     26   60 my ($self, $tagname)= @_;
468 26   66     87 my $class= ref($self)||$self;
469             # Collect all members of this tag from any parent class, but stop at the first undef
470 26         48 my ($dynamic, @keep, %seen, $known);
471 26         46 for (@{ mro::get_linear_isa($class) }) {
  26         166  
472             my $add= ${$_.'::EXPORT_TAGS'}{$tagname}
473             # Special case, ':all' is built from all known keys of the %EXPORT var at each inherited package
474             # Also exclude anything exported as part of the Exporter API, but right now that is only
475             # the '-exporter_setup' option.
476             || ($tagname eq 'all' && defined *{$_.'::EXPORT'}{HASH}
477 52 100 100     86 && [ grep !$ord_is_directive{+ord}, keys %{$_.'::EXPORT'} ]
478             )
479             or next;
480 25         48 ++$known;
481 25 100       68 if (ref $add ne 'ARRAY') {
482             # Found a generator (coderef or method name ref). Call it to get the list of tags.
483 1 50       6 $add= ref $add eq 'CODE'? $add
    50          
484             : ref $add eq 'SCALAR'? $$add
485             : $croak->("Tag must expand to an array, code, or a method name ref (not $add)");
486 1         22 $add= $self->$add($self->{generator_arg});
487 1 50       7 ref $add eq 'ARRAY' or $croak->("Tag generator must return an arrayref");
488 1         3 ++$dynamic;
489             }
490             # If first element of the list is undef it means this class wanted to reset the tag.
491             # Since we're iterating *up* the hierarchy, it just means end here.
492 25 50 66     133 my $start= (@$add && !defined $add->[0])? 1 : 0;
493             # symbol might be followed by options, so need to skip over refs, but also need to allow
494             # duplicate symbols if they were followed by a ref.
495             (ref $add->[$_] || !$seen{$add->[$_]}++ || ref $add->[$_+1]) && push @keep, $add->[$_]
496 25   66     262 for $start .. $#$add;
      100        
497 25 50       80 last if $start;
498             }
499 26 100       96 my $ret= $known? \@keep : $self->exporter_autoload_tag($tagname);
500 26 100       86 $EXPORT_TAGS_PKG_CACHE{$class}{$tagname}= $ret unless $dynamic;
501 26         75 return $ret;
502             }
503              
504             sub exporter_get_tag {
505 36     36 0 5946 my ($self, $tagname)= @_;
506 36   66     108 my $class= ref($self)||$self;
507             # Make the common case fast
508 36         90 my $list= $EXPORT_TAGS_PKG_CACHE{$class}{$tagname};
509             $list= $self->_exporter_build_tag_cache($tagname)
510 36 50 66     227 unless $list or exists $EXPORT_TAGS_PKG_CACHE{$class}{$tagname};
511 36         219 return $list;
512             }
513              
514             sub _exporter_is_excluded {
515 20     20   35 my ($self, $symbol)= @_;
516 20 50 33     62 return unless ref $self && (my $not= $self->{not});
517             # N^2 exclusion iteration isn't cool, but doing something smarter requires a
518             # lot more setup that probably won't pay off for the usual tiny lists of 'not'.
519 20 100       45 for my $filter (ref $not eq 'ARRAY'? @$not : ($not)) {
520 22 100       59 if (!ref $filter) {
    100          
    50          
521 8 100       25 return 1 if $symbol eq $filter;
522             }
523             elsif (ref $filter eq 'Regexp') {
524 6 100       53 return 1 if $symbol =~ $filter;
525             }
526             elsif (ref $filter eq 'CODE') {
527 8   100     15 &$filter && return 1 for $symbol;
528             }
529 0         0 else { $croak->("Unhandled 'not' filter: $filter") }
530             }
531 10         36 return;
532             }
533              
534             sub exporter_autoload_tag {
535 12     12 1 31 my ($self, $tagname)= @_;
536 12         30 return;
537             }
538              
539             sub exporter_also_import {
540 3     3 1 56 my $self= shift;
541 3 50 33     15 ref $self && $self->{todo} or $croak->('exporter_also_import can only be called on $self during an import()');
542 3         5 push @{$self->{todo}}, @_;
  3         13  
543             }
544              
545             my %method_attrs;
546             sub FETCH_CODE_ATTRIBUTES {
547 0     0   0 my ($class, $coderef)= (shift, shift);
548 0         0 my $super= $class->next::can;
549 0 0       0 return @{$method_attrs{$class}{$coderef} || []},
  0 0       0  
550             ($super? $super->($class, $coderef, @_) : ());
551             }
552             sub MODIFY_CODE_ATTRIBUTES {
553 19     19   1004 my ($class, $coderef)= (shift, shift);
554 19         88 my @unknown= grep !$class->_exporter_process_attribute($coderef, $_), @_;
555 19         76 my $super= $class->next::can;
556 19 50       283 return $super? $super->($class, $coderef, @unknown) : @unknown;
557             }
558              
559             sub _exporter_get_coderef_name {
560             # Sub::Identify has an XS version that we take advantage of if available
561             my $impl= (eval 'require Sub::Identify;1')? sub {
562 0 0   0     &Sub::Identify::sub_name
563             or $croak->("Can't determine export name of $_[0]");
564             }
565 0 0   0     : do {
566 0           require B;
567             sub {
568 16     16   63 my $cv= &B::svref_2object;
  0            
569 16 50 33     331 $cv->isa('B::CV') && !$cv->GV->isa('B::SPECIAL') && $cv->GV->NAME
  0 0 33        
      0        
      0        
570             or $croak->("Can't determine export name of $_[0]");
571 0           };
572             };
573 0           *_exporter_get_coderef_name= $impl;
574 0           $impl->(shift);
575             }
576              
577             sub _exporter_get_ref_to_package_var {
578 4     4   9 my ($class, $sigil, $name)= @_;
579 4 50       8 unless (defined $name) {
580 0 0       0 ($sigil, $name)= ($_[1] =~ /^([\$\@\%\*\&]?)(\w+)$/)
581             or $croak->("'$_[1]' is not an allowed variable name");
582             }
583 4         9 my $reftype= $sigil_to_reftype{$sigil};
584 4 50       6 return undef unless ${$class.'::'}{$name};
  4         15  
585 4 100       9 return $reftype eq 'GLOB'? \*{$class.'::'.$name} : *{$class.'::'.$name}{$reftype};
  1         6  
  3         15  
586             }
587              
588             sub _exporter_process_attribute {
589 20     20   40 my ($class, $coderef, $attr)= @_;
590 20 50       121 if ($attr =~ /^Export(?:\(\s*(.*?)\s*\))?$/) {
591 20         42 my (%tags, $subname, @export_names);
592             # If given a list in parenthesees, split on space and proces each. Else use the name of the sub itself.
593 20 100       117 for my $token ($1? split(/\s+/, $1) : ()) {
594 23 100       120 if ($token =~ /^:(.*)$/) {
    100          
    100          
    50          
595 7         21 $tags{$1}++; # save tags until we have the export_names
596             }
597             elsif ($token =~ /^\w+$/) {
598 6         13 push @export_names, $token;
599 6         7 ${$class.'::EXPORT'}{$token}= $coderef;
  6         26  
600             }
601             elsif ($token =~ /^-(\w*)(?:\(([0-9]+|\*)\))?$/) {
602 3   33     13 $subname ||= _exporter_get_coderef_name($coderef);
603 3 50       14 push @export_names, length $1? $token : "-$subname";
604 3         18 $class->exporter_register_option(substr($export_names[-1],1), $subname, $2);
605             }
606             elsif (my($sym, $name)= ($token =~ /^=([\&\$\@\%\*:]?(\w*))$/)) {
607 7   33     27 $subname ||= _exporter_get_coderef_name($coderef);
608 7 100       18 my $export_name= length $name? $sym : do {
609 4         16 (my $x= $subname) =~ s/^_generate[A-Za-z]*_//;
610 4         11 $sym . $x
611             };
612 7         11 $export_name =~ s/^[&]//;
613 7         37 $class->exporter_register_generator($export_name, $subname);
614 7         34 push @export_names, $export_name;
615             }
616             else {
617 0         0 $croak->("Invalid export notation '$token'");
618             }
619             }
620 20 100       49 if (!@export_names) { # if list was empty or only tags...
621 6         15 push @export_names, _exporter_get_coderef_name($coderef);
622 6         14 ${$class.'::EXPORT'}{$export_names[-1]}= $coderef;
  6         35  
623             }
624 20         79 $class->exporter_register_tag_members($_, @export_names) for keys %tags;
625 20         80 return 1;
626             }
627 0         0 return;
628             }
629              
630             sub exporter_setup {
631 27     27 0 54 my ($self, $version)= @_;
632 27         40 push @{$self->{into}.'::ISA'}, ref($self);
  27         291  
633 27         164 strict->import;
634 27         278 warnings->import;
635 27 100       133 if ($version == 1) {
    50          
636             # Declare 'our %EXPORT'
637 5         10 *{$self->{into}.'::EXPORT'}= \%{$self->{into}.'::EXPORT'};
  5         20  
  5         35  
638             # Make @EXPORT and $EXPORT_TAGS{default} be the same arrayref.
639             # Allow either one to have been declared already.
640 5         9 my $tags= \%{$self->{into}.'::EXPORT_TAGS'};
  5         19  
641 0         0 *{$self->{into}.'::EXPORT'}= $tags->{default}
642 5 50       19 if ref $tags->{default} eq 'ARRAY';
643 5   50     24 $tags->{default} ||= \@{$self->{into}.'::EXPORT'};
  5         21  
644             # Export the 'export' function.
645 5         10 *{$self->{into}.'::export'}= \&_exporter_export_from_caller;
  5         34  
646             }
647             elsif ($version) {
648 0         0 $croak->("Unknown export API version $version");
649             }
650             }
651              
652             sub _exporter_export_from_caller {
653 14     14   16137 unshift @_, scalar caller;
654 14         90 goto $_[0]->can('exporter_export');
655             }
656             sub exporter_export {
657 14     14 1 31 my $class= shift;
658 14         46 for (my $i= 0; $i < @_;) {
659 22         38 my ($is_gen, $sigil, $name, $args, $ref);
660 22         42 my $export= $_[$i++];
661 22 50       42 ref $export and $croak->("Expected non-ref export name at argument $i");
662             # If they provided the ref, capture it from arg list.
663 22 100       48 $ref= $_[$i++] if ref $_[$i];
664             # Common case first - ordinary functions
665 22 100       155 if ($export =~ /^\w+$/) {
    100          
    100          
    50          
666 10 50 66     50 $ref ||= $class->can($export) or $croak->("Export '$export' not found in $class");
667 10         17 ${$class.'::EXPORT'}{$export}= $ref;
  10         86  
668             }
669             # Next, check for generators or variables with sigils
670             elsif (($is_gen, $sigil, $name)= ($export =~ /^(=?)([\$\@\%\*]?)(\w+)$/)) {
671 7 100 33     44 $ref ||= $class->_exporter_get_ref_to_package_var($sigil, $name)
672             unless $is_gen;
673 7 100       17 if (!$ref) {
    50          
674 3         5 for (@{ $sigil_to_generator_prefix{$sigil} }) {
  3         11  
675 5         13 my $gen= $_ . $name;
676 5 100       27 next unless $class->can($gen);
677 3         7 $ref= \\$gen; # REF REF to method name
678 3         16 last;
679             }
680 3 50       9 $ref or $croak->("Export '$export' not found in package $class, nor a generator $sigil_to_generator_prefix{$sigil}[0]");
681             }
682             elsif ($is_gen) {
683 0 0       0 ref $ref eq 'CODE' or $croak->("Export '$export' should be followed by a generator coderef");
684 0         0 my $coderef= $ref;
685 0         0 $ref= \$coderef; # REF to coderef
686             }
687             else {
688 4 0 0     26 ref $ref eq $sigil_to_reftype{$sigil} or (ref $ref eq 'REF' && $sigil eq '$')
      33        
689             or $croak->("'$export' should be $sigil_to_reftype{$sigil} but you supplied ".ref($ref));
690             }
691 7         12 ${$class.'::EXPORT'}{$sigil.$name}= $ref;
  7         124  
692             }
693             # Tags ":foo"
694             elsif (($is_gen, $name)= ($export =~ /^(=?):(\w+)$/)) {
695 1 50 33     4 if ($is_gen && !$ref) {
696 0         0 my $gen= $sigil_to_generator_prefix{':'}.$name;
697 0 0       0 $class->can($gen)
698             or $croak->("Can't find generator for tag $name : '$gen'");
699 0         0 $ref= $gen;
700             }
701 1 50       11 ref $ref eq 'ARRAY'? $class->exporter_register_tag_members($name, @$ref)
702             : $class->exporter_register_generator($export, $ref);
703             }
704             # Options "-foo" or "-foo(3)"
705             elsif (($name, $args)= ($export =~ /^-(\w+)(?:\(([0-9]+|\*|\?)\))?$/)) {
706 4 50       9 if ($ref) {
707 0 0 0     0 ref $ref eq 'CODE' or (ref $ref eq 'SCALAR' and $class->can($ref= $$ref))
      0        
708             or $croak->("Option '$export' must be followed by coderef or method name as scalar ref");
709             } else {
710 4 50       17 $class->can($name)
711             or $croak->("Option '$export' defaults to a method '$name' which does not exist on $class");
712 4         8 $ref= $name;
713             }
714 4         14 $class->exporter_register_option($name, $ref, $args);
715             }
716             else {
717 0           $croak->("'$export' is not a valid export syntax");
718             }
719             }
720             }
721              
722             1;
723              
724             __END__