File Coverage

blib/lib/CXC/Exporter/Util.pm
Criterion Covered Total %
statement 134 138 97.1
branch 27 34 79.4
condition 27 36 75.0
subroutine 22 23 95.6
pod 4 4 100.0
total 214 235 91.0


line stmt bran cond sub pod time code
1             package CXC::Exporter::Util;
2              
3             # ABSTRACT: Tagged Based Exporting
4              
5 6     6   1380514 use v5.22;
  6         23  
6              
7 6     6   34 use strict;
  6         34  
  6         216  
8 6     6   40 use warnings;
  6         12  
  6         517  
9              
10             our $VERSION = '0.08';
11              
12 6     6   55 use Scalar::Util 'reftype';
  6         20  
  6         465  
13 6     6   60 use List::Util 1.45 'uniqstr';
  6         128  
  6         488  
14 6     6   750 use Import::Into;
  6         3518  
  6         242  
15 6     6   715 use experimental 'signatures', 'postderef', 'lexical_subs';
  6         1994  
  6         51  
16              
17 6     6   1276 use Exporter 'import';
  6         14  
  6         1085  
18              
19             our %EXPORT_TAGS = (
20             default => [qw( install_EXPORTS )],
21             constants => [qw( install_CONSTANTS )],
22             utils => [qw( install_constant_tag install_constant_func )],
23             );
24              
25             our %HOOK;
26              
27             install_EXPORTS();
28              
29             my sub _croak {
30 0     0   0 require Carp;
31 0         0 goto \&Carp::croak;
32             }
33              
34 52     52   80 my sub _EXPORT_TAGS ( $caller = scalar caller ) {
  52         113  
  52         80  
35 6     6   48 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNostrict)
  6         8  
  6         1159  
36 52   100     99 *${ \"${caller}::EXPORT_TAGS" }{HASH} // \%{ *${ \"${caller}::EXPORT_TAGS" } = {} };
  52         404  
  6         14  
  6         60  
37             }
38              
39 16     16   29 my sub _EXPORT_OK ( $caller = scalar caller ) {
  16         29  
  16         39  
40 6     6   36 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNostrict)
  6         9  
  6         936  
41 16   100     34 *${ \"${caller}::EXPORT_OK" }{ARRAY} // \@{ *${ \"${caller}::EXPORT_OK" } = [] };
  16         140  
  15         38  
  15         185  
42             }
43              
44 16     16   28 my sub _EXPORT ( $caller = scalar caller ) {
  16         30  
  16         25  
45 6     6   35 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNostrict)
  6         12  
  6         9478  
46 16   50     23 *${ \"${caller}::EXPORT" }{ARRAY} // \@{ *${ \"${caller}::EXPORT" } = [] };
  16         114  
  16         31  
  16         125  
47             }
48              
49             my sub add_constant_to_tag;
50              
51              
52              
53              
54              
55              
56              
57              
58              
59              
60              
61              
62              
63              
64              
65              
66              
67              
68              
69              
70              
71              
72              
73              
74              
75              
76              
77              
78              
79              
80              
81              
82              
83              
84              
85              
86              
87              
88              
89              
90              
91              
92              
93              
94              
95              
96              
97              
98              
99              
100              
101              
102              
103              
104              
105              
106              
107              
108              
109              
110              
111             sub install_EXPORTS {
112              
113 16 100 100 16 1 1383282 my $export_tags = ( reftype( $_[0] ) // q{} ) eq 'HASH' ? shift : undef;
114 16 100 100     106 my $u_opts = ( reftype( $_[-1] ) // q{} ) eq 'HASH' ? shift : {};
115              
116 16   50     162 my %options = (
117             overwrite => 0,
118             all => 'auto',
119             package => shift // scalar caller,
120             %$u_opts,
121             );
122              
123 16 50       57 _croak( 'too many arguments to INSTALL_EXPORTS' ) if @_;
124              
125 16         48 my $package = delete $options{package};
126 16         36 my $install_all = delete $options{all};
127              
128             # run hooks.
129 16 100       62 if ( defined( my $hooks = delete $HOOK{$package}{pre} ) ) {
130 2         11 $_->() for values $hooks->%*;
131             }
132              
133 16         44 my $EXPORT_TAGS = _EXPORT_TAGS( $package );
134              
135 16 100       48 if ( defined $export_tags ) {
136              
137 7 100       23 if ( delete $options{overwrite} ) {
138 1         6 $EXPORT_TAGS->%* = $export_tags->%*;
139             }
140              
141             else {
142             # cheap one layer deep hash merge
143 6         21 for my $tag ( keys $export_tags->%* ) {
144 10   50     97 push( ( $EXPORT_TAGS->{$tag} //= [] )->@*, $export_tags->{$tag}->@* );
145             }
146             }
147             }
148              
149             # Exporter::Tiny handles the 'all' tag, as does Sub::Exporter, but
150             # I don't know how to detect when the latter is being used.
151 16 100       205 $install_all = !$package->isa( 'Exporter::Tiny' )
152             if $install_all eq 'auto';
153              
154 16 100       44 if ( $install_all ) {
155             # Assign the all tag in two steps to avoid the situation
156             # where $EXPORT_TAGS->{all} is created with an undefined value
157             # before running values on $EXPORT_TAGS->%*;
158              
159 13         38 my @all = map { $_->@* } values $EXPORT_TAGS->%*;
  38         96  
160 13   50     67 $EXPORT_TAGS->{all} //= \@all;
161             }
162              
163 16   100     93 _EXPORT( $package )->@* = ( $EXPORT_TAGS->{default} // [] )->@*;
164 16         51 _EXPORT_OK( $package )->@* = uniqstr map { $_->@* } values $EXPORT_TAGS->%*;
  61         391  
165             }
166              
167              
168              
169              
170              
171              
172              
173              
174              
175              
176              
177              
178              
179              
180              
181              
182              
183              
184              
185              
186              
187              
188              
189              
190              
191              
192              
193              
194              
195              
196              
197              
198              
199              
200              
201              
202              
203              
204              
205              
206              
207              
208              
209              
210              
211              
212              
213              
214              
215              
216              
217              
218              
219              
220              
221              
222              
223              
224              
225              
226              
227             sub install_CONSTANTS {
228 4 50   4 1 239847 my $package = !defined reftype( $_[-1] ) ? pop : scalar caller;
229              
230 4         11 for my $spec ( @_ ) {
231 6         13 my $type = reftype( $spec );
232              
233 6 100       21 if ( 'HASH' eq $type ) {
    50          
234 3         15 install_constant_tag( $_, $spec->{$_}, $package ) for keys $spec->%*;
235             }
236              
237             elsif ( 'ARRAY' eq $type ) {
238 3         5 my $idx = $spec->@*;
239 3 50       11 _croak( 'constant spec passed as array has an odd number of elements' )
240             unless 0 == $idx % 2;
241              
242 3         9 while ( $idx ) {
243 3         8 my $hash = $spec->[ --$idx ];
244 3         5 my $id = $spec->[ --$idx ];
245 3         22 install_constant_tag( $id, $hash, $package );
246             }
247             }
248              
249             else {
250 0         0 _croak( 'expect a HashRef or an ArrayRef' );
251             }
252             }
253             }
254              
255              
256              
257              
258              
259              
260              
261              
262              
263              
264              
265              
266              
267              
268              
269              
270              
271              
272              
273              
274              
275              
276              
277              
278              
279              
280              
281              
282              
283              
284              
285              
286              
287              
288              
289              
290              
291              
292              
293              
294              
295              
296              
297              
298              
299              
300              
301              
302              
303              
304              
305              
306              
307              
308              
309              
310              
311              
312              
313              
314              
315              
316              
317              
318              
319              
320              
321              
322              
323              
324              
325              
326              
327              
328              
329              
330              
331              
332              
333              
334              
335              
336              
337              
338              
339              
340              
341              
342              
343              
344              
345              
346              
347              
348              
349              
350              
351              
352              
353              
354              
355              
356              
357              
358              
359              
360              
361              
362              
363              
364              
365              
366              
367              
368              
369              
370              
371              
372              
373              
374              
375              
376              
377              
378              
379              
380              
381              
382              
383              
384              
385              
386              
387              
388              
389              
390              
391              
392              
393              
394              
395              
396              
397              
398              
399              
400              
401              
402              
403              
404              
405              
406              
407              
408              
409              
410              
411              
412              
413              
414              
415              
416              
417              
418              
419              
420              
421              
422              
423              
424              
425              
426              
427              
428              
429              
430              
431              
432              
433              
434              
435              
436              
437              
438              
439              
440              
441              
442              
443              
444              
445              
446              
447              
448              
449 6     6 1 9 sub install_constant_tag ( $id, $constants, $package = scalar caller ) {
  6         24  
  6         11  
  6         12  
  6         11  
450              
451             # caller may specify distinct tag and enumeration function names.
452 6 100 100     39 my ( $tag, $fn_values, $fn_names )
453             = 'ARRAY' eq ( reftype( $id ) // q{} )
454             ? ( $id->@* )
455             : ( lc( $id ), $id );
456              
457 6   33     14 $fn_values //= uc( $tag );
458 6   66     26 $fn_names //= $fn_values . '_NAMES';
459              
460 6         9 my ( @names );
461 6 100       16 if ( reftype( $constants ) eq 'HASH' ) {
    50          
462 3         10 @names = keys $constants->%*;
463             }
464             elsif ( reftype( $constants ) eq 'ARRAY' ) {
465 3         13 my @copy = $constants->@*;
466 3         14 while ( my ( $name ) = splice( @copy, 0, 2 ) ) {
467 14         31 push @names, $name;
468             }
469 3         14 $constants = { $constants->@* };
470             }
471             else {
472 0         0 _croak( '$constants argument should be either a hashref or an arrayref' );
473             }
474              
475 6         41 constant->import::into( $package, $constants );
476              
477 6   100     1792 push( ( _EXPORT_TAGS( $package )->{$tag} //= [] )->@*, @names );
478              
479             $HOOK{$package}{pre}{$fn_values} //= sub {
480 5     5   17 my $fqdn = join q{::}, $package, $fn_values;
481             _croak( "Error: attempt to redefine enumerating function $fqdn" )
482 5 50       9 if exists &{$fqdn};
  5         24  
483 6     6   50 no strict 'refs'; ## no critic (TestingAndDebugging::ProhibitNostrict)
  6         12  
  6         3502  
484             my @values
485 5         13 = map { &{"${package}::${_}"} } _EXPORT_TAGS( $package )->{$tag}->@*;
  25         29  
  25         83  
486 5         17 install_constant_func( $fn_values, \@values, $package );
487 6   66     53 };
488              
489             $HOOK{$package}{pre}{$fn_names} //= sub {
490 5     5   32 my $fqdn = join q{::}, $package, $fn_names;
491             _croak( "Error: attempt to redefine enumerating function $fqdn" )
492 5 50       9 if exists &{$fqdn};
  5         16  
493             add_constant_to_tag( 'constant_name_funcs', $fn_names,
494 5         14 [ _EXPORT_TAGS( $package )->{$tag}->@* ], $package );
495              
496 6   66     294 };
497              
498             }
499              
500              
501              
502              
503              
504              
505              
506              
507              
508              
509              
510              
511              
512              
513              
514              
515              
516              
517              
518              
519              
520              
521              
522              
523              
524              
525              
526              
527              
528              
529              
530              
531              
532              
533              
534              
535              
536              
537              
538              
539              
540              
541              
542              
543 5     5 1 7 sub install_constant_func ( $tag, $values, $caller = scalar caller ) {
  5         8  
  5         8  
  5         7  
  5         8  
544 5         12 add_constant_to_tag( 'constant_funcs', $tag, $values, $caller );
545             # for backwards compatibility
546 5         41 _EXPORT_TAGS( $caller )->{constants_funcs} = _EXPORT_TAGS( $caller )->{constant_funcs};
547             }
548              
549              
550              
551              
552              
553              
554              
555              
556              
557              
558              
559              
560              
561              
562              
563              
564              
565              
566              
567              
568              
569              
570              
571              
572              
573              
574              
575              
576              
577              
578              
579              
580              
581              
582              
583              
584              
585              
586              
587              
588              
589              
590              
591              
592              
593              
594              
595 10     10   13 sub add_constant_to_tag ( $tag, $name, $values, $caller = scalar caller ) {
  10         16  
  10         14  
  10         14  
  10         13  
  10         15  
596 10         40 constant->import::into( $caller, $name => $values->@* );
597 10   100     1927 push( ( _EXPORT_TAGS( $caller )->{$tag} //= [] )->@*, $name );
598             }
599              
600             1;
601              
602             #
603             # This file is part of CXC-Exporter-Util
604             #
605             # This software is Copyright (c) 2022 by Smithsonian Astrophysical Observatory.
606             #
607             # This is free software, licensed under:
608             #
609             # The GNU General Public License, Version 3, June 2007
610             #
611              
612             __END__