File Coverage

blib/lib/Exporter/Declare/Meta.pm
Criterion Covered Total %
statement 76 86 88.3
branch 14 22 63.6
condition 4 5 80.0
subroutine 16 19 84.2
pod 8 8 100.0
total 118 140 84.2


line stmt bran cond sub pod time code
1             package Exporter::Declare::Meta;
2 7     7   84396 use strict;
  7         14  
  7         229  
3 7     7   34 use warnings;
  7         11  
  7         197  
4              
5 7     7   31 use Scalar::Util qw/blessed reftype/;
  7         14  
  7         471  
6 7     7   30 use Carp qw/croak/;
  7         7  
  7         255  
7 7     7   37 use aliased 'Exporter::Declare::Export::Sub';
  7         9  
  7         47  
8 7     7   543 use aliased 'Exporter::Declare::Export::Variable';
  7         12  
  7         21  
9 7     7   511 use aliased 'Exporter::Declare::Export::Alias';
  7         11  
  7         29  
10 7     7   3253 use Meta::Builder;
  7         23380  
  7         36  
11              
12             accessor 'export_meta';
13              
14             hash_metric exports => (
15             add => sub {
16             my $self = shift;
17             my ( $data, $metric, $action, $item, $ref ) = @_;
18             croak "Exports must be instances of 'Exporter::Declare::Export'"
19             unless blessed($ref) && $ref->isa('Exporter::Declare::Export');
20              
21             my ( $type, $name ) = ( $item =~ m/^([\&\%\@\$])?(.*)$/ );
22             $type ||= '&';
23             my $fullname = "$type$name";
24              
25             $self->default_hash_add( $data, $metric, $action, $fullname, $ref );
26              
27             push @{$self->export_tags->{all}} => $fullname;
28             },
29             get => sub {
30             my $self = shift;
31             my ( $data, $metric, $action, $item ) = @_;
32              
33             croak "exports_get() does not accept a tag as an argument"
34             if $item =~ m/^[:-]/;
35              
36             my ( $type, $name ) = ( $item =~ m/^([\&\%\@\$])?(.*)$/ );
37             $type ||= '&';
38             my $fullname = "$type$name";
39              
40             return $self->default_hash_get( $data, $metric, $action, $fullname )
41             || croak $self->package . " does not export '$fullname'";
42             },
43             merge => sub {
44             my $self = shift;
45             my ( $data, $metric, $action, $merge ) = @_;
46             my $newmerge = {};
47              
48             for my $item ( keys %$merge ) {
49             my $value = $merge->{$item};
50             next if $value->isa(Alias);
51             next if $data->{$item};
52             $newmerge->{$item} = $value;
53             }
54             $self->default_hash_merge( $data, $metric, $action, $newmerge );
55             },
56             list => sub {
57             my $self = shift;
58             my ($data) = @_;
59             return keys %$data;
60             },
61             );
62              
63             hash_metric options => (
64             add => sub {
65             my $self = shift;
66             my ( $data, $metric, $action, $item ) = @_;
67              
68             croak "'$item' is already a tag, you can't also make it an option."
69             if $self->export_tags_has($item);
70             croak "'$item' is already an argument, you can't also make it an option."
71             if $self->arguments_has($item);
72              
73             $self->default_hash_add( $data, $metric, $action, $item, 1 );
74             },
75             list => sub {
76             my $self = shift;
77             my ($data) = @_;
78             return keys %$data;
79             },
80             );
81              
82             hash_metric arguments => (
83             add => sub {
84             my $self = shift;
85             my ( $data, $metric, $action, $item ) = @_;
86              
87             croak "'$item' is already a tag, you can't also make it an argument."
88             if $self->export_tags_has($item);
89             croak "'$item' is already an option, you can't also make it an argument."
90             if $self->options_has($item);
91              
92             $self->default_hash_add( $data, $metric, $action, $item, 1 );
93             },
94             merge => sub {
95             my $self = shift;
96             my ( $data, $metric, $action, $merge ) = @_;
97             my $newmerge = {%$merge};
98             delete $newmerge->{suffix};
99             delete $newmerge->{prefix};
100             $self->default_hash_merge( $data, $metric, $action, $newmerge );
101             },
102             list => sub {
103             my $self = shift;
104             my ($data) = @_;
105             return keys %$data;
106             },
107             );
108              
109             lists_metric export_tags => (
110             push => sub {
111             my $self = shift;
112             my ( $data, $metric, $action, $item, @args ) = @_;
113              
114             croak "'$item' is a reserved tag, you cannot override it."
115             if $item eq 'all';
116             croak "'$item' is already an option, you can't also make it a tag."
117             if $self->options_has($item);
118             croak "'$item' is already an argument, you can't also make it a tag."
119             if $self->arguments_has($item);
120              
121             $self->default_list_push( $data, $metric, $action, $item, @args );
122             },
123             merge => sub {
124             my $self = shift;
125             my ( $data, $metric, $action, $merge ) = @_;
126             my $newmerge = {};
127             my %aliases = (
128             map {
129             my ($name) = (m/^&?(.*)$/);
130             ( $name => 1, "&$name" => 1 )
131             } @{$merge->{alias}}
132             );
133              
134             for my $item ( keys %$merge ) {
135             my $values = $merge->{$item};
136             $newmerge->{$item} = [grep { !$aliases{$_} } @$values];
137             }
138              
139             $self->default_list_merge( $data, $metric, $action, $newmerge );
140             },
141             list => sub {
142             my $self = shift;
143             my ($data) = @_;
144             return keys %$data;
145             },
146             );
147              
148             sub new {
149 19     19 1 6026 my $class = shift;
150 19         192 my $self = $class->SUPER::new(
151             @_,
152             export_tags => {all => [], default => [], alias => []},
153             arguments => {prefix => 1, suffix => 1},
154             );
155 19         975 $self->add_alias;
156 19         4150 return $self;
157             }
158              
159             sub new_from_exporter {
160 2     2 1 198 my $class = shift;
161 2         4 my ($exporter) = @_;
162 2         7 my $self = $class->new($exporter);
163 2         3 my %seen;
164 2         8 my ($exports) = $self->get_ref_from_package('@EXPORT');
165 2         6 my ($export_oks) = $self->get_ref_from_package('@EXPORT_OK');
166 2         12 my ($tags) = $self->get_ref_from_package('%EXPORT_TAGS');
167 2         6 $self->exports_add(@$_) for map {
  7         15  
168 7         15 my ( $ref, $name ) = $self->get_ref_from_package($_);
169              
170 7 100       21 if ( $name =~ m/^\&/ ) {
171 6         27 Sub->new( $ref, exported_by => $exporter );
172             }
173             else {
174 1         3 Variable->new( $ref, exported_by => $exporter );
175             }
176 7         20 [$name, $ref];
177             } grep { !$seen{$_}++ } @$exports, @$export_oks;
178 2 100       30 $self->export_tags_push( 'default', @$exports )
179             if @$exports;
180 2         17 $self->export_tags_push( $_, $tags->{$_} ) for keys %$tags;
181 2         9 return $self;
182             }
183              
184             sub add_alias {
185 19     19 1 23 my $self = shift;
186 19         61 my $package = $self->package;
187 19         148 my ($alias) = ( $package =~ m/([^:]+)$/ );
188 19     3   162 $self->exports_add( $alias, Alias->new( sub { $package }, exported_by => $package ) );
  3         2333  
189 19         203 $self->export_tags_push( 'alias', $alias );
190             }
191              
192             sub is_tag {
193 0     0 1 0 my $self = shift;
194 0         0 my ($name) = @_;
195 0 0       0 return exists $self->export_tags->{$name} ? 1 : 0;
196             }
197              
198             sub is_argument {
199 0     0 1 0 my $self = shift;
200 0         0 my ($name) = @_;
201 0 0       0 return exists $self->arguments->{$name} ? 1 : 0;
202             }
203              
204             sub is_option {
205 0     0 1 0 my $self = shift;
206 0         0 my ($name) = @_;
207 0 0       0 return exists $self->options->{$name} ? 1 : 0;
208             }
209              
210             sub get_ref_from_package {
211 78     78 1 68 my $self = shift;
212 78         76 my ($item) = @_;
213 7     7   9106 use Carp qw/confess/;
  7         11  
  7         816  
214 78 50       116 confess unless $item;
215 78         281 my ( $type, $name ) = ( $item =~ m/^([\&\@\%\$]?)(.*)$/ );
216 78   100     203 $type ||= '&';
217 78         85 my $fullname = "$type$name";
218 78         147 my $ref = $self->package . '::' . $name;
219              
220 7     7   33 no strict 'refs';
  7         9  
  7         1153  
221 78 100 66     423 return ( \&{$ref}, $fullname ) if !$type || $type eq '&';
  64         229  
222 14 100       38 return ( \${$ref}, $fullname ) if $type eq '$';
  6         28  
223 8 100       20 return ( \@{$ref}, $fullname ) if $type eq '@';
  5         30  
224 3 50       10 return ( \%{$ref}, $fullname ) if $type eq '%';
  3         24  
225 0         0 croak "'$item' cannot be exported";
226             }
227              
228             sub reexport {
229 2     2 1 7 my $self = shift;
230 2         1 my ($exporter) = @_;
231 2 100       20 my $meta =
232             $exporter->can('export_meta')
233             ? $exporter->export_meta()
234             : __PACKAGE__->new_from_exporter($exporter);
235 2         10 $self->merge($meta);
236             }
237              
238             1;
239              
240             =head1 NAME
241              
242             Exporter::Declare::Meta - The meta object which stores meta-data for all
243             exporters.
244              
245             =head1 DESCRIPTION
246              
247             All classes that use Exporter::Declare have an associated Meta object. Meta
248             objects track available exports, tags, and options.
249              
250             =head1 METHODS
251              
252             =over 4
253              
254             =item $class->new( $package )
255              
256             Created a meta object for the specified package. Also injects the export_meta()
257             sub into the package namespace that returns the generated meta object.
258              
259             =item $class->new_from_exporter( $package )
260              
261             Create a meta object for a package that already uses Exporter.pm. This will not
262             turn the class into an Exporter::Declare package, but it will create a meta
263             object and export_meta() method on it. This si primarily used for reexport
264             purposes.
265              
266             =item $package = $meta->package()
267              
268             Get the name of the package with which the meta object is associated.
269              
270             =item $meta->add_alias()
271              
272             Usually called at construction to add a package alias function to the exports.
273              
274             =item $meta->add_export( $name, $ref )
275              
276             Add an export, name should be the item name with sigil (assumed to be sub if
277             there is no sigil). $ref should be a ref blessed as an
278             L subclass.
279              
280             =item $meta->get_export( $name )
281              
282             Retrieve the L object by name. Name should be the
283             item name with sigil, assumed to be sub when sigil is missing.
284              
285             =item $meta->export_tags_push( $name, @items )
286              
287             Add @items to the specified tag. Tag will be created if it does not already
288             exist. $name should be the tag name B -/: prefix.
289              
290             =item @list = $meta->export_tags_get( $name )
291              
292             Get the list of items associated with the specified tag. $name should be the
293             tag name B -/: prefix.
294              
295             =item @list = $meta->export_tags_list()
296              
297             Get a list of all export tags.
298              
299             =item $bool = $meta->is_tag( $name )
300              
301             Check if a tag with the given name exists. $name should be the tag name
302             B -/: prefix.
303              
304             =item $meta->options_add( $name )
305              
306             Add import options by name. These will be boolean options that take no
307             arguments.
308              
309             =item my @list = $meta->options_list()
310              
311             =item $meta->arguments_add( $name )
312              
313             Add import options that slurp in the next argument as a value.
314              
315             =item $bool = $meta->is_option( $name )
316              
317             Check if the specified name is an option.
318              
319             =item $bool = $meta->is_argument( $name )
320              
321             Check if the specified name is an option that takes an argument.
322              
323             =item $meta->add_parser( $name, sub { ... })
324              
325             Add a parser sub that should be associated with exports via L
326              
327             =item $meta->get_parser( $name )
328              
329             Get a parser by name.
330              
331             =item $ref = $meta->get_ref_from_package( $item )
332              
333             Returns a reference to a specific package variable or sub.
334              
335             =item $meta->reexport( $package )
336              
337             Re-export the exports in the provided package. Package may be an
338             L based package or an L based package.
339              
340             =item $meta->merge( $meta2 )
341              
342             Merge-in the exports and tags of the second meta object.
343              
344             =back
345              
346             =head1 AUTHORS
347              
348             Chad Granum L
349              
350             =head1 COPYRIGHT
351              
352             Copyright (C) 2010 Chad Granum
353              
354             Exporter-Declare is free software; Standard perl licence.
355              
356             Exporter-Declare is distributed in the hope that it will be useful, but
357             WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
358             FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.