File Coverage

blib/lib/Exporter/Attributes.pm
Criterion Covered Total %
statement 43 43 100.0
branch 3 4 75.0
condition 1 2 50.0
subroutine 9 9 100.0
pod 0 1 0.0
total 56 59 94.9


line stmt bran cond sub pod time code
1 4     4   98213 use strict;
  4         9  
  4         136  
2 4     4   21 use warnings FATAL => 'all';
  4         8  
  4         374  
3              
4             package Exporter::Attributes;
5              
6             # ABSTRACT: Export symbols by attributes
7              
8 4     4   23 use Exporter 5.72 ();
  4         104  
  4         154  
9 4         47 use Attribute::Universal 0.002 Exportable => 'ANY,BEGIN',
10 4     4   2786 Exported => 'ANY,BEGIN';
  4         26732  
11 4     4   2706 use Carp qw(croak);
  4         8  
  4         926  
12              
13             our $VERSION = '0.001'; # VERSION
14              
15             our @EXPORT_OK = qw(import);
16              
17             my $symbols = {};
18              
19             my %lists = (
20             Exportable => 'export_ok',
21             Exported => 'export',
22             );
23              
24             my %sigil = (
25             SCALAR => '$',
26             ARRAY => '@',
27             HASH => '%',
28             CODE => '&',
29             );
30              
31             sub add {
32             my ( $package, $list, $name, @tags ) = @_;
33             $symbols->{$package} //= {
34             export => [],
35             export_ok => [],
36             export_tags => {},
37             };
38             push @{ $symbols->{$package}->{$list} } => $name;
39             return unless @tags;
40             foreach my $tag (@tags) {
41             push @{ $symbols->{$package}->{export_tags}->{$tag} } => $name;
42             }
43             }
44              
45 4     4   3211 use namespace::clean;
  4         5180867  
  4         21  
46              
47             sub ATTRIBUTE {
48 32     32 0 14772 my $attr = Attribute::Universal::to_hash(@_);
49 32         626 my ( $package, $symbol, $referent, $attribute, $payload, $phase, $file,
50             $line )
51             = @_;
52             croak("lexical symbols are not exportable, in $file at line $line")
53 32 50       104 unless ref $attr->{symbol};
54 32         64 my $sigil = $sigil{ $attr->{type} };
55 32         58 my $list = $lists{ $attr->{attribute} };
56 32         44 my @tags = map { split /[\s,]+/ } @{ $attr->{payload} };
  32         166  
  32         81  
57 32         122 add( $attr->{package}, $list, $sigil . $attr->{label}, @tags );
58             }
59              
60             sub import {
61 8     8   608 my $class = $_[0];
62              
63             # export our own "import" method into the caller class
64             # so abort here if "import" is called by "use Exporter::Attributes"
65 8 100       375 goto &Exporter::import if $class eq __PACKAGE__;
66              
67             # get export symbols or just return
68 4   50     20 my $_symbols = $symbols->{$class} // return;
69              
70             # build :all export tag by concat @EXPORT and @EXPORT_OK
71             $_symbols->{export_tags}->{all} =
72 4         5 [ @{ $_symbols->{export} }, @{ $_symbols->{export_ok} }, ];
  4         12  
  4         20  
73              
74             # this is a quite easy way to say "our @Class::EXPORT", which is normally not possible
75             # we are rewriting the symbol table, dont let strict concern about it!
76 4     4   2074 no strict 'refs'; ## no critic
  4         11  
  4         594  
77 4         9 *{"${class}::EXPORT"} = $_symbols->{export};
  4         1109  
78 4         2289 *{"${class}::EXPORT_OK"} = $_symbols->{export_ok};
  4         21  
79 4         9 *{"${class}::EXPORT_TAGS"} = $_symbols->{export_tags};
  4         16  
80              
81             # and finally let import the symbol into the caller namespace.
82 4         3208 goto &Exporter::import;
83             }
84              
85             1;
86              
87             __END__