File Coverage

blib/lib/CXC/Exporter/Util.pm
Criterion Covered Total %
statement 117 121 96.6
branch 25 30 83.3
condition 20 24 83.3
subroutine 19 20 95.0
pod 4 4 100.0
total 185 199 92.9


line stmt bran cond sub pod time code
1             package CXC::Exporter::Util;
2              
3             # ABSTRACT: Tagged Based Exporting
4              
5 4     4   974728 use v5.20;
  4         38  
6              
7 4     4   25 use strict;
  4         10  
  4         80  
8 4     4   20 use warnings;
  4         8  
  4         191  
9              
10             our $VERSION = '0.03'; # TRIAL
11              
12 4     4   24 use Scalar::Util 'reftype';
  4         8  
  4         304  
13 4     4   30 use List::Util 1.45 'uniqstr';
  4         88  
  4         258  
14 4     4   25 use Import::Into;
  4         10  
  4         140  
15 4     4   29 use experimental 'signatures', 'postderef';
  4         8  
  4         24  
16              
17 4     4   723 use Exporter 'import';
  4         11  
  4         666  
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             install_EXPORTS();
26              
27             sub _croak {
28 0     0   0 require Carp;
29 0         0 goto \&Carp::croak;
30             }
31              
32 21     21   37 sub _EXPORT_TAGS ( $caller = scalar caller ) {
  21         40  
  21         29  
33 4     4   36 no strict 'refs'; ## no critic
  4         20  
  4         680  
34 21         227 *${ \"${caller}::EXPORT_TAGS" }{HASH}
35 21   100     34 // \%{ *${ \"${caller}::EXPORT_TAGS" } = {} };
  5         10  
  5         39  
36             }
37              
38 13     13   22 sub _EXPORT_OK ( $caller = scalar caller ) {
  13         25  
  13         18  
39 4     4   34 no strict 'refs'; ## no critic
  4         8  
  4         628  
40 13         96 *${ \"${caller}::EXPORT_OK" }{ARRAY}
41 13   100     19 // \@{ *${ \"${caller}::EXPORT_OK" } = [] };
  12         25  
  12         106  
42             }
43              
44 13     13   22 sub _EXPORT ( $caller = scalar caller ) {
  13         23  
  13         19  
45 4     4   29 no strict 'refs'; ## no critic
  4         8  
  4         4664  
46 13   50     20 *${ \"${caller}::EXPORT" }{ARRAY} // \@{ *${ \"${caller}::EXPORT" } = [] };
  13         89  
  13         60  
  13         96  
47             }
48              
49              
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             sub install_EXPORTS {
110              
111 13 100 100 13 1 787 my $export_tags = ( reftype( $_[0] ) // '' ) eq 'HASH' ? shift : undef;
112 13 100 100     105 my $u_opts = ( reftype( $_[-1] ) // '' ) eq 'HASH' ? shift : {};
113              
114 13   50     120 my %options = (
115             overwrite => 0,
116             all => 'auto',
117             package => shift // scalar caller,
118             %$u_opts
119             );
120              
121 13 50       41 _croak( "too many arguments to INSTALL_EXPORTS" ) if @_;
122              
123 13         29 my $package = delete $options{package};
124 13         31 my $install_all = delete $options{all};
125              
126 13         33 my $EXPORT_TAGS = _EXPORT_TAGS( $package );
127              
128 13 100       45 if ( defined $export_tags ) {
129              
130 7 100       23 if ( delete $options{overwrite} ) {
131 1         5 $EXPORT_TAGS->%* = $export_tags->%*;
132             }
133              
134             else {
135             # cheap one layer deep hash merge
136 6         20 for my $tag ( keys $export_tags->%* ) {
137             push(
138             ( $EXPORT_TAGS->{$tag} //= [] )->@*,
139 10   50     51 $export_tags->{$tag}->@*
140             );
141             }
142             }
143             }
144              
145             # Exporter::Tiny handles the 'all' tag, as does Sub::Exporter, but
146             # I don't know how to detect when the latter is being used.
147 13 100       143 $install_all = !$package->isa( 'Exporter::Tiny' )
148             if $install_all eq 'auto';
149              
150 13 100       41 if ( $install_all ) {
151             # Assign the all tag in two steps to avoid the situation
152             # where $EXPORT_TAGS->{all} is created with an undefined value
153             # before running values on $EXPORT_TAGS->%*;
154              
155 10         30 my @all = map { $_->@* } values $EXPORT_TAGS->%*;
  25         67  
156 10   50     55 $EXPORT_TAGS->{all} //= \@all;
157             }
158              
159 13   100     60 _EXPORT( $package )->@* = ( $EXPORT_TAGS->{default} // [] )->@*;
160 13         65 _EXPORT_OK( $package )->@* = uniqstr map { $_->@* } values $EXPORT_TAGS->%*;
  45         276  
161             }
162              
163              
164              
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             sub install_CONSTANTS {
197 3 50   3 1 148 my $caller = !defined reftype( $_[-1] ) ? pop : scalar caller;
198              
199 3         8 for my $spec ( @_ ) {
200 4         11 my $type = reftype( $spec );
201              
202 4 100       13 if ( 'HASH' eq $type ) {
    50          
203 2         12 install_constant_tag( $_, $spec->{$_}, $caller ) for keys $spec->%*;
204             }
205              
206             elsif ( 'ARRAY' eq $type ) {
207 2         5 my $idx = $spec->@*;
208 2 50       8 _croak(
209             "constant spec passed as array has an odd number of elements" )
210             unless 0 == $idx % 2;
211              
212 2         5 while ( $idx ) {
213 2         5 my $hash = $spec->[ --$idx ];
214 2         4 my $id = $spec->[ --$idx ];
215 2         5 install_constant_tag( $id, $hash, $caller );
216             }
217             }
218              
219             else {
220 0         0 _croak( "expect a HashRef or an ArrayRef" );
221             }
222             }
223             }
224              
225              
226              
227              
228              
229              
230              
231              
232              
233              
234              
235              
236              
237              
238              
239              
240              
241              
242              
243              
244              
245              
246              
247              
248              
249              
250              
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 4     4 1 6 sub install_constant_tag ( $id, $constants, $caller = scalar caller ) {
  4         8  
  4         5  
  4         8  
  4         5  
352              
353 4         9 my ( @names, @values );
354 4 100       15 if ( reftype( $constants ) eq 'HASH' ) {
    50          
355 2         8 @names = keys $constants->%*;
356 2         5 @values = values $constants->%*;
357             }
358             elsif ( reftype( $constants ) eq 'ARRAY' ) {
359 2         5 my $idx = $constants->@*;
360 2         7 while ( $idx ) {
361             # pulling things off in reverse order, so it's (value,
362             # name), not (name, value)
363 13         22 push @values, $constants->[ --$idx ];
364 13         25 push @names, $constants->[ --$idx ];
365             }
366             # reverse order to keep in user specified order, as it was
367             # constructed in reverse order
368 2         3 @values = reverse @values;
369 2         11 $constants = { $constants->@* };
370             }
371             else {
372 0         0 _croak(
373             '$constants argument should be either a hashref or an arrayref' );
374             }
375              
376 4         21 constant->import::into( $caller, $constants );
377              
378             # caller may specify distinct tag and enumeration function names.
379 4 100 100     950 my ( $tag, $fname )
380             = 'ARRAY' eq ( reftype( $id ) // '' )
381             ? ( $id->[0], $id->[1] )
382             : ( lc( $id ), $id );
383              
384 4   100     14 push( ( _EXPORT_TAGS( $caller )->{$tag} //= [] )->@*, @names );
385              
386             # supplement previous enumerating function, if it exists
387 4         13 my $fqfn = "${caller}::${fname}";
388 4 100       6 if ( defined &{$fqfn} ) {
  4         24  
389 4     4   34 no strict 'refs'; ## no critic
  4         9  
  4         934  
390 1         8 @values = ( &$fqfn, @values );
391             }
392              
393 4         14 install_constant_func( $fname, \@values, $caller );
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 4     4 1 6 sub install_constant_func ( $tag, $values, $caller = scalar caller ) {
  4         7  
  4         5  
  4         5  
  4         5  
440 4         18 constant->import::into( $caller, $tag => $values->@* );
441 4   100     801 push( ( _EXPORT_TAGS( $caller )->{constants_funcs} //= [] )->@*, $tag );
442             }
443              
444              
445             1;
446              
447             #
448             # This file is part of CXC-Exporter-Util
449             #
450             # This software is Copyright (c) 2022 by Smithsonian Astrophysical Observatory.
451             #
452             # This is free software, licensed under:
453             #
454             # The GNU General Public License, Version 3, June 2007
455             #
456              
457             __END__