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