File Coverage

blib/lib/Exporter/Declare/Specs.pm
Criterion Covered Total %
statement 102 131 77.8
branch 32 38 84.2
condition 7 9 77.7
subroutine 17 24 70.8
pod 13 13 100.0
total 171 215 79.5


line stmt bran cond sub pod time code
1             package Exporter::Declare::Specs;
2 5     5   3716 use strict;
  5         11  
  5         152  
3 5     5   23 use warnings;
  5         10  
  5         144  
4              
5 5     5   23 use Carp qw/croak/;
  5         8  
  5         7372  
6             our @CARP_NOT = qw/Exporter::Declare/;
7              
8             sub new {
9 19     19 1 7855 my $class = shift;
10 19         52 my ( $package, @args ) = @_;
11 19         95 my $self = bless( [$package,{},{},[]], $class );
12 19 100       77 @args = (':default') unless @args;
13 19         70 $self->_process( "import list", @args );
14 19         78 return $self;
15             }
16              
17 129     129 1 798 sub package { shift->[0] }
18 168     168 1 15807 sub config { shift->[1] }
19 275     275 1 841 sub exports { shift->[2] }
20 41     41 1 144 sub excludes { shift->[3] }
21              
22             sub export {
23 15     15 1 26 my $self = shift;
24 15         73 my ( $dest ) = @_;
25 15         26 for my $item ( keys %{ $self->exports }) {
  15         38  
26 77         111 my ( $export, $conf, $args ) = @{ $self->exports->{$item} };
  77         165  
27 77         339 my ( $sigil, $name ) = ( $item =~ m/^([\&\%\$\@])(.*)$/ );
28 77   66     390 $name = $conf->{as} || join(
29             '',
30             $conf->{prefix} || $self->config->{prefix} || '',
31             $name,
32             $conf->{suffix} || $self->config->{suffix} || '',
33             );
34 77         301 $export->inject( $dest, $name, @$args );
35             }
36             }
37              
38             sub add_export {
39 3     3 1 22 my $self = shift;
40 3         8 my ( $name, $value, $config ) = @_;
41 3 50       14 my $type = ref $value eq 'CODE' ? 'Sub' : 'Variable';
42 3         17 "Exporter::Declare::Export::$type"->new( $value, exported_by => scalar caller() );
43 3   50     26 $self->exports->{$name} = [
44             $value,
45             $config || {},
46             [],
47             ];
48             }
49              
50             sub arguments {
51 0     0 1 0 my $self = shift;
52 0         0 my $meta = $self->package->export_meta;
53 0         0 return grep { $meta->is_argument($_) } keys %{$self->config};
  0         0  
  0         0  
54             }
55              
56             sub options {
57 0     0 1 0 my $self = shift;
58 0         0 my $meta = $self->package->export_meta;
59 0         0 return grep { $meta->is_option($_) } keys %{$self->config};
  0         0  
  0         0  
60             }
61              
62             sub tags {
63 0     0 1 0 my $self = shift;
64 0         0 my $meta = $self->package->export_meta;
65 0         0 return grep { $meta->is_tag($_) } keys %{$self->config};
  0         0  
  0         0  
66             }
67              
68             sub _make_info {
69 0     0   0 my $self = shift;
70 0         0 my $config = $self->config;
71 0         0 return { map { $_, $config->{$_} } @_ };
  0         0  
72             }
73              
74             sub argument_info {
75 0     0 1 0 my $self = shift;
76 0         0 return $self->_make_info($self->arguments);
77             }
78              
79             sub option_info {
80 0     0 1 0 my $self = shift;
81 0         0 return $self->_make_info($self->options);
82             }
83              
84             sub tag_info {
85 0     0 1 0 my $self = shift;
86 0         0 my $all_tags = $self->package->export_meta->export_tags;
87 0         0 return { map { $_, $all_tags->{$_} } $self->tags };
  0         0  
88             }
89              
90              
91             sub _process {
92 19     19   35 my $self = shift;
93 19         42 my ( $tag, @args ) = @_;
94 19         38 my $argnum = 0;
95 19         61 while ( my $item = shift( @args )) {
96 47 50       104 croak "not sure what to do with $item ($tag argument: $argnum)"
97             if ref $item;
98 47         55 $argnum++;
99              
100 47 100       210 if ( $item =~ m/^(!?)[:-](.*)$/ ) {
101 16         59 my ( $neg, $param ) = ( $1, $2 );
102 16 100       228 if ( $self->package->export_meta->arguments_has( $param )) {
103 2         47 $self->config->{$param} = shift( @args );
104 2         3 $argnum++;
105 2         6 next;
106             }
107             else {
108 14 100       509 $self->config->{$param} = ref( $args[0] ) ? $args[0] : !$neg;
109             }
110             }
111              
112 45 100       168 if ( $item =~ m/^!(.*)$/ ) {
    100          
113 2         5 $self->_exclude_item( $1 )
114             }
115             elsif ( my $type = ref( $args[0] )) {
116 4         6 my $arg = shift( @args );
117 4         6 $argnum++;
118 4 100       16 if ( $type eq 'ARRAY' ) {
    50          
119 1         3 $self->_include_item( $item, undef, $arg );
120             }
121             elsif ( $type eq 'HASH' ) {
122 3         8 $self->_include_item( $item, $arg, undef );
123             }
124             else {
125 0         0 croak "Not sure what to do with $item => $arg ($tag arguments: "
126             . ($argnum - 1) . " and $argnum)";
127             }
128             }
129             else {
130 39         95 $self->_include_item( $item )
131             }
132             }
133 19         45 delete $self->exports->{$_} for @{ $self->excludes };
  19         51  
134             }
135              
136 108 100   108   144 sub _item_name { my $in = shift; $in =~ m/^[\&\$\%\@]/ ? $in : "\&$in" }
  108         482  
137              
138             sub _exclude_item {
139 20     20   155 my $self = shift;
140 20         28 my ( $item ) = @_;
141              
142 20 100       54 if ( $item =~ m/^[:-](.*)$/ ) {
143             $self->_exclude_item( $_ )
144 3         8 for $self->_export_tags_get( $1 );
145 3         12 return;
146             }
147              
148 17         18 push @{ $self->excludes } => _item_name($item);
  17         28  
149             }
150              
151             sub _include_item {
152 100     100   4177 my $self = shift;
153 100         147 my ( $item, $conf, $args ) = @_;
154 100   100     293 $conf ||= {};
155 100   100     248 $args ||= [];
156              
157 5     5   70 use Carp qw/confess/;
  5         8  
  5         2860  
158 100 50       221 confess $item if $item =~ m/^&?aaa_/;
159              
160 100 100       896 push @$args => @{ delete $conf->{'-args'} }
  1         11  
161             if defined $conf->{'-args'};
162              
163 100         271 for my $key ( keys %$conf ) {
164 20 100       76 next if $key =~ m/^[:-]/;
165 3         13 push @$args => ( $key, delete $conf->{$key} );
166             }
167              
168 100 100       299 if ( $item =~ m/^[:-](.*)$/ ) {
169 14         31 my $name = $1;
170 14 50       35 return if $self->package->export_meta->options_has( $name );
171 14         414 for my $tagitem ( $self->_export_tags_get( $name ) ) {
172 52         535 my ( $negate, $name ) = ( $tagitem =~ m/^(!)?(.*)$/ );
173 52 50       98 if ( $negate ) {
174 0         0 $self->_exclude_item( $name );
175             }
176             else {
177 52         153 $self->_include_item( $tagitem, $conf, $args );
178             }
179             }
180 14         239 return;
181             }
182              
183 86         164 $item = _item_name($item);
184              
185 86         184 my $existing = $self->exports->{ $item };
186              
187 86 100       184 unless ( $existing ) {
188 79         160 $existing = [ $self->_get_item( $item ), {}, []];
189 79         1975 $self->exports->{ $item } = $existing;
190             }
191              
192 86         188 push @{ $existing->[2] } => @$args;
  86         163  
193 86         367 for my $param ( keys %$conf ) {
194 14         50 my ( $name ) = ( $param =~ m/^[-:](.*)$/ );
195 14         70 $existing->[1]->{$name} = $conf->{$param};
196             }
197             }
198              
199             sub _get_item {
200 80     80   102 my $self = shift;
201 80         115 my ( $name ) = @_;
202 80         161 $self->package->export_meta->exports_get( $name );
203             }
204              
205             sub _export_tags_get {
206 18     18   303 my $self = shift;
207 18         30 my ( $name ) = @_;
208 18         40 $self->package->export_meta->export_tags_get( $name );
209             }
210              
211             1;
212              
213             =head1 NAME
214              
215             Exporter::Declare::Specs - Import argument parser for Exporter::Declare
216              
217             =head1 DESCRIPTION
218              
219             Import arguments cna get complicated. All arguments are assumed to be exports
220             unless they have a - or : prefix. The prefix may denote a tag, a boolean
221             option, or an option that takes the next argument as a value. In addition
222             almost all these can be negated with the ! prefix.
223              
224             This class takes care of parsing the import arguments and generating data
225             structures that can be used to find what the exporter needs to know.
226              
227             =head1 METHODS
228              
229             =over 4
230              
231             =item $class->new( $package, @args )
232              
233             Create a new instance and parse @args.
234              
235             =item $specs->package()
236              
237             Get the name of the package that should do the exporting.
238              
239             =item $hashref = $specs->config()
240              
241             Get the configuration hash, All specified options and tags are the keys. The
242             value will be true/false/undef for tags/boolean options. For options that take
243             arguments the value will be that argument. When a config hash is provided to a
244             tag it will be the value.
245              
246             =item @names = $specs->arguments()
247              
248             =item @names = $specs->options()
249              
250             =item @names = $specs->tags()
251              
252             Get the argument, option, or tag names that were specified for the import.
253              
254             =item $hashref = $specs->argument_info()
255              
256             Get the arguments that were specified for the import. The key is the name of the
257             argument and the value is what the user supplied during import.
258              
259             =item $hashref = $specs->option_info()
260              
261             Get the options that were specified for the import. The key is the name of the user
262             supplied option and the value will evaluate to true.
263              
264             =item $hashref = $specs->tag_info()
265              
266             Get the values associated with the tags used during import. The key is the name of the tag
267             and the value is an array ref containing the values given to export_tag() for the associated
268             name.
269              
270             =item $hashref = $specs->exports()
271              
272             Get the exports hash. The keys are names of the exports. Values are an array
273             containing the export, item specific config hash, and arguments array. This is
274             generally not intended for direct consumption.
275              
276             =item $arrayref = $specs->excludes()
277              
278             Get the arrayref containing the names of all excluded exports.
279              
280             =item $specs->export( $package )
281              
282             Do the actual exporting. All exports will be injected into $package.
283              
284             =item $specs->add_export( $name, $value )
285              
286             =item $specs->add_export( $name, $value, \%config )
287              
288             Add an export. Name is required, including sigil. Value is required, if it is a
289             sub it will be blessed as a ::Sub, otherwise blessed as a ::Variable.
290              
291             $specs->add_export( '&foo' => sub { return 'foo' });
292              
293             =back
294              
295             =head1 AUTHORS
296              
297             Chad Granum L<exodist7@gmail.com>
298              
299             =head1 COPYRIGHT
300              
301             Copyright (C) 2010 Chad Granum
302              
303             Exporter-Declare is free software; Standard perl licence.
304              
305             Exporter-Declare is distributed in the hope that it will be useful, but
306             WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
307             FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.