File Coverage

blib/lib/Exporter/Simple.pm
Criterion Covered Total %
statement 98 105 93.3
branch 16 22 72.7
condition 1 5 20.0
subroutine 26 29 89.6
pod 0 12 0.0
total 141 173 81.5


line stmt bran cond sub pod time code
1             package Exporter::Simple;
2              
3 4     4   155448 use 5.008;
  4         2502  
  4         243  
4 4     4   30 use warnings;
  4         10  
  4         175  
5 4     4   22 use strict;
  4         21  
  4         168  
6 4     4   4318 use Attribute::Handlers;
  4         39827  
  4         35  
7 4     4   218 use base 'Exporter';
  4         9  
  4         579  
8              
9             our $VERSION = '1.10';
10 4     4   28 no warnings 'redefine';
  4         10  
  4         316  
11              
12 4     4 0 30 sub UNIVERSAL::Exported :ATTR(SCALAR,BEGIN) { export('$', BEGIN => @_) }
  4     4   7  
  4         22  
  4         1868  
13 4     4 0 1371 sub UNIVERSAL::Exported :ATTR(ARRAY,BEGIN) { export('@', BEGIN => @_) }
  4     0   10  
  4         20  
  0         0  
14 4     4 0 1264 sub UNIVERSAL::Exported :ATTR(HASH,BEGIN) { export('%', BEGIN => @_) }
  4     4   10  
  4         24  
  4         1078  
15 4     4 0 1245 sub UNIVERSAL::Exported :ATTR(CODE,BEGIN,CHECK) { export('', INIT => @_) }
  4     16   10  
  4         20  
  16         5682  
16              
17 4     4 0 1594 sub UNIVERSAL::Exportable :ATTR(SCALAR,BEGIN) { exportable('$', BEGIN => @_) }
  4     0   7  
  4         17  
  0         0  
18 4     4 0 1074 sub UNIVERSAL::Exportable :ATTR(ARRAY,BEGIN) { exportable('@', BEGIN => @_) }
  4     4   6  
  4         17  
  4         1623  
19 4     4 0 1190 sub UNIVERSAL::Exportable :ATTR(HASH,BEGIN) { exportable('%', BEGIN => @_) }
  4     0   8  
  4         15  
  0         0  
20 4     4 0 1330 sub UNIVERSAL::Exportable :ATTR(CODE,BEGIN,CHECK) { exportable('', INIT => @_) }
  4     24   7  
  4         19  
  24         6510  
21              
22             # Build a structure in which we remember what to export when (in
23             # which phase, BEGIN or INIT) to whom. Scalars, arrays and hashes are exported
24             # during BEGIN, but subroutines need to be exported during CHECK, because
25             # their names aren't known during BEGIN (they're 'ANON' in this phase). But
26             # because of a bug in Attribute::Handlers, we can't just declare
27             # :ATTR(CODE,CHECK), because that would make the handlers for scalars, arrays
28             # and hashes run during CHECK as well, even though they were declared as
29             # :ATTR(...,BEGIN). But each handler specifies in the call to export() or
30             # exportable() which phase the symbol is to be exported in.
31             #
32             # The structure is %EXPORTDEF and is built when the attribute handlers run,
33             # and consulted during do_export(), which is called both from import() and
34             # INIT(), see below.
35             #
36             # An example structure is shown here and is built by declaring the following
37             # exports in a module that subclasses Exporter::Simple:
38             #
39             # our @bar : Exportable(vars) = (2, 3, 5, 7);
40             # our $foo : Exported(vars) = 42;
41             # our %baz : Exported = (a => 65, b => 66);
42             #
43             # sub hello : Exported(greet,uk) { "hello there" }
44             # sub askme : Exportable { "what you will" }
45             # sub hi : Exportable(greet,us) { "hi there" }
46             #
47             # sub get_foo : Exported(vars) { $foo }
48             # sub get_bar : Exportable(vars) { @bar }
49             #
50             # results in:
51             #
52             # %EXPORTDEF =
53             # --- #YAML:1.0
54             # BEGIN:
55             # MyExport:
56             # EXPORT:
57             # - '$foo'
58             # - '%baz'
59             # EXPORT_OK:
60             # - '@bar'
61             # EXPORT_TAGS:
62             # all:
63             # - '@bar'
64             # - '$foo'
65             # - '%baz'
66             # greet: []
67             # uk: []
68             # us: []
69             # vars:
70             # - '@bar'
71             # - '$foo'
72             # INIT:
73             # MyExport:
74             # EXPORT:
75             # - hello
76             # - get_foo
77             # EXPORT_OK:
78             # - askme
79             # - hi
80             # - get_bar
81             # EXPORT_TAGS:
82             # all:
83             # - hello
84             # - askme
85             # - hi
86             # - get_foo
87             # - get_bar
88             # greet:
89             # - hello
90             # - hi
91             # uk:
92             # - hello
93             # us:
94             # - hi
95             # vars:
96             # - get_foo
97             # - get_bar
98              
99             sub add {
100 52     52 0 113 my ($arrname, $sigil, $exp_phase, $pkg, $symbol, $ref, $attr, $tags) = @_;
101 52 50       139 $symbol = *{$symbol}{NAME} if ref $symbol;
  52         259  
102 52         115 $symbol = "$sigil$symbol";
103 52 100 33     181 $tags = [ $tags || () ] unless ref $tags eq 'ARRAY';
104              
105 52         73 our %EXPORTDEF;
106              
107 52 50       116 if ($symbol eq 'ANON') {
108              
109             # see the empty arrays in keys 'greet', 'uk' and 'us' in the above
110             # sample of $EXPORT{BEGIN}{MyExport}{EXPORT_TAGS} ? They need to be
111             # there because these tags are only defined by subroutines (hello()
112             # and hi(); see sample code above), and hence they would appear in
113             # %EXPORTDEF only during CHECK, but the tag ':greet' still gets passed
114             # to Exporter::import() during BEGIN (which is necessary because some
115             # scalars, arrays and hashes *could* still have used these tags in
116             # their attribute declarations). Therefore, when we handle a subroutine
117             # attribute during BEGIN (recognized by the symbol name being 'ANON'),
118             # we make empty entries for the tags in %EXPORTDEF. Now Exporter is
119             # happy and the tests are happy and we are all happy.
120              
121 0   0     0 $EXPORTDEF{BEGIN}{$pkg}{EXPORT_TAGS}{$_} ||= [] for @$tags, 'all';
122              
123             # we'll see the sub again during CHECK, to be exported during INIT, so:
124              
125 0         0 return;
126             }
127              
128 32         91 push @{ $EXPORTDEF{$exp_phase}{$pkg}{$arrname} } => $symbol unless
  72         183  
129 52 100       60 grep { $_ eq $symbol } @{ $EXPORTDEF{$exp_phase}{$pkg}{$arrname} };
  52         173  
130              
131 52         102 for my $tag (@$tags, 'all') {
132 64         282 push @{ $EXPORTDEF{$exp_phase}{$pkg}{EXPORT_TAGS}{$tag} } => $symbol
  204         510  
133 108         305 unless grep { $_ eq $symbol }
134 108 100       123 @{ $EXPORTDEF{$exp_phase}{$pkg}{EXPORT_TAGS}{$tag} };
135             }
136             }
137              
138 24     24 0 57 sub export { add(EXPORT => @_) }
139 28     28 0 65 sub exportable { add(EXPORT_OK => @_) }
140              
141             # import() could be called several times, from different packages
142             # who want to import symbols from us. So we remember who gets to
143             # import what in which phase. Scalars, arrays and hashes are imported
144             # during BEGIN (that's why import() also calls do_export('BEGIN') at
145             # the end, while subroutines are exported during INIT. Tags, starting
146             # with a colon, need to be seen both during BEGIN and END.
147              
148             sub import {
149 4     4   1022 my $pkg = shift;
150 4         9 our %wants_import;
151              
152 4         14 for (@_) {
153 6 100       34 if (/^:/) {
    50          
154 5         8 push @{ $wants_import{BEGIN}{$pkg} } => $_;
  5         17  
155 5         8 push @{ $wants_import{INIT}{$pkg} } => $_;
  5         19  
156             } elsif (/^[\$\@%]/) {
157 0         0 push @{ $wants_import{BEGIN}{$pkg} } => $_;
  0         0  
158             } else {
159 1         2 push @{ $wants_import{INIT}{$pkg} } => $_;
  1         4  
160             }
161             }
162              
163 4         18 do_export('BEGIN');
164             }
165              
166             sub do_export {
167 7     7 0 17 my $phase = shift;
168 7         17 our (%EXPORTDEF, %wants_import);
169              
170 7         16 while (my ($pkg, $def) = each %{ $EXPORTDEF{$phase} }) {
  13         2569  
171 4     4   3605 no strict 'refs';
  4         8  
  4         917  
172              
173             # remove export cache; without this, we can't export in both BEGIN
174             # and INIT phases
175              
176 7         15 undef %{ "$pkg\::EXPORT" };
  7         55  
177              
178             # build the variables Exporter requires to do its work and ask it to export
179             # the symbols we remembered during import().
180              
181 7 50       15 @{ "$pkg\::EXPORT" } = @{ $def->{EXPORT} || [] };
  7         78  
  7         37  
182 7 50       13 @{ "$pkg\::EXPORT_OK" } = @{ $def->{EXPORT_OK} || [] };
  7         44  
  7         31  
183 7 50       47 %{ "$pkg\::EXPORT_TAGS" } = %{ $def->{EXPORT_TAGS} || {} };
  7         58  
  7         50  
184              
185 7         21 local $Exporter::ExportLevel = 2;
186 7 100       11 Exporter::import($pkg => @{ $wants_import{$phase}{$pkg} || [] });
  7         1873  
187             }
188             }
189              
190 3     3   203 INIT { do_export('INIT') }
191              
192             1;
193              
194             __END__