File Coverage

blib/lib/Export/These.pm
Criterion Covered Total %
statement 169 197 85.7
branch 35 62 56.4
condition 9 18 50.0
subroutine 19 19 100.0
pod n/a
total 232 296 78.3


line stmt bran cond sub pod time code
1             package Export::These;
2              
3 2     2   147114 use strict;
  2         17  
  2         56  
4 2     2   10 use warnings;
  2         5  
  2         112  
5              
6             our $VERSION="v0.1.2";
7              
8             sub import {
9 7     7   1517 my $package=shift;
10 7         15 my $exporter=caller;
11              
12             #Treat args as key value pairs, unless the value is a string.
13             #in this case it is the name of a symbol to export
14 7         13 my ($k, $v);
15              
16 2     2   11 no strict "refs";
  2         4  
  2         1002  
17              
18             # Locate or create the EXPORT, EXPORT_OK and EXPORT_TAGS package variables.
19             # These are used to accumulate our exported symbol names across multiple
20             # use Export::Terse ...; statements
21             #
22 7         9 my $export_ok= \@{"@{[$exporter]}::EXPORT_OK"};
  7         11  
  7         42  
23 7         12 my $export= \@{"@{[$exporter]}::EXPORT"};
  7         11  
  7         25  
24 7         11 my $export_tags= \%{"@{[$exporter]}::EXPORT_TAGS"};
  7         10  
  7         26  
25              
26 7         22 while(@_){
27 16         22 $k=shift;
28              
29 16 50       37 die "Expecting symbol name or group name" if ref $k;
30 16         36 my $r=ref $_[0];
31 16 100       27 unless($r){
32 12         21 push @$export, $k;
33 12         15 push @$export_ok, $k;
34             next
35 12         24 }
36 4         7 my $v=shift;
37              
38 4         8 for($k){
39 4 50 33     24 if(/export_ok$/ and $r eq "ARRAY"){
    50 33        
    50          
40 0         0 push @$export_ok, @$v;
41             }
42             elsif(/export$/ and $r eq "ARRAY"){
43 0         0 push @$export, @$v;
44 0         0 push @$export_ok, @$v;
45             }
46             elsif($r eq "ARRAY"){
47             #Assume key is a tag name
48 4         16 push $export_tags->{$k}->@*, @$v;
49 4         14 push @$export_ok, @$v;
50             }
51             else {
52 0         0 die "Unkown export grouping: $k";
53             }
54             }
55             }
56              
57             # Generate the import sub here if it doesn't exist already
58              
59 7         13 local $"= " ";
60 7         8 my $exist=eval {*{\${$exporter."::"}{import}}{CODE}};
  7         10  
  7         14  
  7         62  
61 7 100       19 if($exist){
62 2         462 return;
63             }
64              
65 2 100 100 2   15 my $res=eval qq|
  2 50 100 2   3  
  2 100 0 2   139  
  2 50 50 2   12  
  2 100 50 2   4  
  2 100 50 2   520  
  2 50   1   15  
  2 100   1   4  
  2 50   1   523  
  2 100   3   14  
  2 50   3   4  
  2 100   1   159  
  2 100   2   14  
  2 50   4   3  
  2 50   1   528  
  2 0       15  
  2 0       5  
  2 0       513  
  1 0       7  
  1 0       1  
  1 0       75  
  1 50       17  
  1 50       1  
  1 50       254  
  1         8  
  1         2  
  1         257  
  5         11  
  3         3  
  3         6  
  3         5  
  3         5  
  3         14  
  3         10  
  8         13  
  8         17  
  1         4  
  1         2  
  1         3  
  7         13  
  7         17  
  7         76  
  7         20  
  7         13  
  8         26  
  8         12  
  9         19  
  9         12  
  9         16  
  9         20  
  9         30  
  9         10  
  9         14  
  9         36  
  9         11  
  9         24  
  9         35  
  3         5  
  3         6  
  3         5  
  3         5  
  3         6  
  3         10  
  8         11  
  8         19  
  2         7  
  2         5  
  2         7  
  6         10  
  6         15  
  6         64  
  6         15  
  6         13  
  8         25  
  8         12  
  12         27  
  12         15  
  12         19  
  12         40  
  12         36  
  12         25  
  12         16  
  12         49  
  12         13  
  12         36  
  12         44  
  1         1  
  1         2  
  1         2  
  1         2  
  1         2  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         86  
  2         6  
  2         11  
  2         9  
  2         4  
  2         4  
  2         4  
  2         13  
  2         10  
  2         7  
  2         8  
  4         138  
  4         14  
  4         28  
  4         17  
  4         8  
  4         5  
  4         5  
  4         6  
  4         30  
  4         3125  
  0         0  
  1         136  
  1         4  
  1         8  
  1         5  
  1         2  
  1         2  
  1         1  
  1         2  
  1         4  
  1         4  
  1         4  
66             package $exporter;
67             no strict "refs";
68              
69              
70             sub _self_export {
71             shift;
72              
73 5         12 my \$ref_export_ok= \\\@@{[$exporter]}::EXPORT_OK;
74 5         13 my \$ref_export= \\\@@{[$exporter]}::EXPORT;
75 5         436 my \$ref_tags= \\\%@{[$exporter]}::EXPORT_TAGS;
76              
77             my \$target=shift;
78              
79             no strict "refs";
80             for(\@_ ? \@_ : \@\$ref_export){
81             my \@syms;
82             if(/^:/){
83             my \$name= s/^://r;
84              
85             my \$group=\$ref_tags->{\$name};
86             #die "Tag \$name does not exists" unless \$group;
87             push \@syms, \@\$group if \$group;
88             }
89             else {
90             #non tag symbol
91             my \$t=\$_;
92             \$t="\\\\\$t" if \$t =~ /^\\\$/;
93             my \$found=grep /\$t/, \@\$ref_export_ok;
94             die "\$_ is not exported from ".__PACKAGE__."\n" unless \$found;
95             push \@syms, \$_;
96             }
97            
98             my \%map=(
99             '\$'=>"SCALAR",
100             '\@'=>"ARRAY",
101             '\%'=>"HASH",
102             '\&'=>"CODE"
103             );
104              
105             for(\@syms){
106             my \$prefix=substr(\$_,0,1);
107             my \$name=\$_;
108             my \$type=\$map{\$prefix};
109              
110             \$name=substr \$_, 1 if \$type;
111             \$type//="CODE";
112              
113             no warnings "redefine";
114             eval { *{\$target."::".\$name}= *{ \\\${__PACKAGE__ ."::"}{\$name}}{\$type}; };
115             die "Could not export \$prefix\$name from ".__PACKAGE__ if \$\@;
116              
117              
118             }
119             }
120              
121              
122             }
123              
124              
125             sub import {
126             my \$package=shift;
127             \$Exporter::ExportLevel//=0;
128             my \$target=(caller(\$Exporter::ExportLevel))[0];
129              
130             $exporter->_self_export(\$target, \@_);
131            
132             local \$Exporter::ExportLevel=\$Exporter::ExportLevel+3;
133             my \$ref=eval {*{\\\${\$package."::"}{_reexport}}{CODE}};
134              
135             if(\$ref){
136             $exporter->_reexport(\$target, \@_);
137             }
138              
139             }
140              
141             1;
142             |;
143 5 50       249 die $@ unless $res;
144             }
145             1;
146              
147              
148             =head1 NAME
149              
150             Export::These - Terse Symbol (Re)Exporting
151              
152              
153             =head1 SYNOPSIS
154              
155             A fine package, exporting subroutines,
156              
157             package My::ModA;
158              
159             use Export::These "dog", "cat", ":colors"=>[qw];
160              
161             sub dog {...}
162             sub cat {...}
163             sub blue {...}
164             sub green {...}
165             1;
166              
167             Another package which would like to reexport the subs from My::ModA:
168              
169             package My::ModB;
170             use My::ModA;
171              
172             use Export::These ":colors"=>["more_colours"];
173              
174             sub _reexport {
175             my ($packate, $target, @names)=@_;
176             My::ModA->import(":colours") if grep /:colours/, @names;
177             }
178            
179             sub more_colours { .... }
180             1;
181              
182              
183             Use package like usual:
184              
185             use My::ModB qw<:colors dog>
186              
187             # suburtines blue, green , more_colors and dog imported
188              
189              
190              
191             =head1 DESCRIPTION
192              
193             A module to make exporting symbols less verbose and facilitate reexporting of
194             symbols from dependencies with minimal input from the module author.
195              
196             By default listing a symbol for export, even in a group/tag, means it will be
197             automatically marked as 'export_ok', saving on duplication and managing two
198             separate lists.
199              
200             It B inherit from C nor does it utilise the C
201             routine from C. It injects its own C subroutine into the each
202             calling package. This injected subroutine adds the desired symbols to the
203             target package as you would expect.
204              
205             If the exporting package has a C<_reexport> subroutine, it is called when being
206             imported. This is the 'hook' location where its safe to call C<-Eimport> on
207             any dependencies modules it might want to export. The symbols from these
208             packages will automatically be installed into the target package with no extra
209             configuration needed.
210              
211             Finally warnings about symbols redefinition in the export process (i.e. exporting
212             to two subroutines with the same name into the same namespace) are silenced to
213             keep warning noise to a minimum. The last symbol definition will ultimately be
214             the one used.
215              
216              
217              
218             =head1 MOTIVATION
219              
220             Suppose you have a server module, which uses a configuration module to process
221             configuration data. However the main program (which imported the server module)
222             also needs to use the subroutines from the configuration module. The consumer
223             of the server module has to also add the configuration module as a dependency.
224              
225             With this module the server can simply reexport the required configuration
226             routines, injecting the dependency, in stead of hard coding it.
227              
228              
229             =head1 USAGE
230              
231             =head2 Specifying Symbols to Export
232              
233             use Export::These ...;
234              
235             The pragma takes a list of arguments to add to the C<@EXPORT> and C
236             variables. The items are taken as a name of a symbol or tag, unless the
237             following argument in the list is an array ref.
238              
239             eg:
240              
241             use Export::These qw;
242              
243              
244             If the item name is "export_ok", then the items in the following array ref are
245             added to the C<@EXPORT_OK> variable.
246            
247              
248             eg
249             use Export::These export_ok=>[qw];
250              
251              
252             If the item name is "export", then the items in the following array ref are
253             added to the C<@EXPORT_OK> and the C variables. This is the same as
254             simply listing the items at the top level.
255            
256             eg
257              
258             use Export::These export=>[qw];
259             # same as
260             # use Export::These qw;
261              
262              
263             If the item has another name, it is a tag name and the items in the following
264             array ref are added to the C<%EXPORT_TAGS> variable and to C<@EXPORT_OK>
265              
266             eg use Export::These group1=>["sym1"];
267              
268              
269             The list can contain any combination of the above:
270              
271             eq use Export::These "sym1", group1=>["sym2", "sym3"], export_ok=>"sym4";
272              
273              
274             =head2 Rexporting Symbols
275              
276             If a subroutine called C<_reexport> exists in the exporting package, it will be
277             called on (with the -> notation) during import, after the normal symbols have
278             been processed. The first argument is the package name of exporter, the second
279             is the package name of the importer (the target), and the remaining arguments
280             are the names of symbols or tags to import.
281              
282             In this subroutine, you call C on as any packages you want to reexport:
283              
284             eg
285             use Sub::Module;
286             use Another::Mod;
287              
288             sub _reexport {
289             my ($package, $target, @names)=@_;
290              
291             Sub::Module->import;
292             Another::Mod->import(@names);
293             ...
294             }
295              
296             =head2 Conditional Reexporting
297              
298             If you would only like to require and export on certain conditions, some extra
299             steps are needed to ensure correct setup of back end variables. Namely the
300             C<$Exporter::ExportLevel> variable needs to be localized and set to 0 inside a
301             block BEFORE calling the C<-Eimport> subroutine on the package.
302              
303             sub _reexport {
304             my ($package, $target, @names)=@_;
305              
306             if(SOME_CONDITION){
307             {
308             # In an localised block, reset the export level
309             local $Exporter::ExportLevel=0;
310             require Sub::Module;
311             require Another::Module;
312             }
313              
314             Sub::Module->import;
315             Another::Mod->import(@names);
316              
317             }
318             }
319              
320             =head2 Reexport Super Class Symbols
321              
322             Any exported symbols from the inheritance chain can be reexported in the same
323             manner, as long as they are package subroutines and not methods:
324              
325             eg
326              
327             package ModChild;
328             parent ModParent;
329              
330             # or
331            
332             class ModChild :isa(ModParent)
333              
334            
335             sub _reexport {
336             my ($package, $target, @names)=@_;
337             $package->SUPER::import(@names);
338             }
339              
340              
341             =head1 COMPARISON TO OTHER MODULES
342              
343             L Provides clean way to reexport symbols, though you will have to
344             roll your own 'normal' export of symbols from you own package.
345              
346             L Requires a custom package to group the imports and reexports
347             them. This is a different approach and might better suit your needs.
348              
349              
350             Reexporting symbols with C directly is a little cumbersome. You
351             either need to import everything into you module name space (even if you don't
352             need it) and then reexport from there. Alternatively you can import directly
353             into a package, but you need to know at what level in the call stack it is.
354             This is exactly what this module addresses.
355              
356              
357             =head1 REPOSITOTY and BUGS
358              
359             Please report and feature requests or bugs via the github repo:
360              
361             L
362              
363             =head1 AUTHOR
364              
365             Ruben Westerberg, Edrclaw@mac.comE
366              
367             =head1 COPYRIGHT AND LICENSE
368              
369             Copyright (C) 2023 by Ruben Westerberg
370              
371             Licensed under MIT
372              
373             =head1 DISCLAIMER OF WARRANTIES
374              
375             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
376             INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
377             FITNESS FOR A PARTICULAR PURPOSE.
378              
379             =cut
380