File Coverage

blib/lib/Importer/Zim/Base.pm
Criterion Covered Total %
statement 89 104 85.5
branch 51 72 70.8
condition 15 25 60.0
subroutine 13 14 92.8
pod 0 1 0.0
total 168 216 77.7


line stmt bran cond sub pod time code
1              
2             package Importer::Zim::Base;
3             $Importer::Zim::Base::VERSION = '0.12.1';
4             # ABSTRACT: Base module for Importer::Zim backends
5              
6 5     5   263970 use 5.010001;
  5         57  
7              
8 5     5   2161 use Module::Runtime ();
  5         7415  
  5         121  
9              
10 5     5   1666 use Importer::Zim::Utils qw(DEBUG carp croak);
  5         12  
  5         28  
11              
12             sub import_into {
13 0     0 0 0 my $class = shift;
14              
15 0         0 carp "$class->import(@_)" if DEBUG;
16 0         0 my @exports = _prepare_args( $class, @_ );
17              
18 0 0       0 if ( $class eq 'Importer::Zim::Lexical' ) { # +Lexical backend
19              
20             # require Sub::Inject;
21 0         0 @_ = map { @{$_}{qw(export code)} } @exports;
  0         0  
  0         0  
22 0         0 goto &Sub::Inject::sub_inject;
23             }
24              
25 0         0 my $caller = caller;
26             return $class->can('_export_to')->( #
27 0         0 map { ; "${caller}::$_->{export}" => $_->{code} } @exports
  0         0  
28             );
29              
30             ## Non-optimized code
31             #my $caller = caller;
32             #@_ = $caller, map { @{$_}{qw(export code)} } @exports;
33             #goto &{ $class->can('export_to') };
34             }
35              
36             sub _prepare_args {
37 16     16   54582 my $class = shift;
38 16 50       42 my $package = shift
39             or croak qq{Usage: use $class MODULE => [\%OPTS =>] EXPORTS...\n};
40              
41 16 100       59 my $opts = _module_opts( ref $_[0] eq 'HASH' ? shift : {} );
42 16 50       51 my @version = exists $opts->{-version} ? ( $opts->{-version} ) : ();
43 16         52 &Module::Runtime::use_module( $package, @version );
44              
45 16         10935 my $can_export = _can_export($package);
46              
47 16         26 my ( @exports, %seen );
48 16 100 66     40 @_ = @{"${package}::EXPORT"} unless @_ || !${"${package}::"}{'EXPORT'};
  4         22  
  4         20  
49 16         44 while (@_) {
50 166         340 my @symbols = _expand_symbol( $package, shift );
51 166 100       354 my $opts = _import_opts( ref $_[0] eq 'HASH' ? shift : {}, $opts );
52             exists $opts->{-filter}
53 166 100       345 and @symbols = grep &{ $opts->{-filter} }, @symbols;
  144         220  
54 166         506 for my $symbol (@symbols) {
55             croak qq{"$symbol" is not exported by "$package"}
56 89 50 66     259 if $opts->{-strict} && !$can_export->{$symbol};
57 89 50       164 croak qq{Can't handle "$symbol"}
58             if $symbol =~ /^[\$\@\%\*]/;
59 89         98 my $sub = *{"${package}::${symbol}"}{CODE};
  89         216  
60 89         108 my $export = do {
61 89   66     198 local $_ = $opts->{-as} // $symbol;
62 89 100       164 exists $opts->{-map} ? $opts->{-map}->() : $_;
63             };
64 89 50       137 croak qq{Can't find "$symbol" in "$package"}
65             unless $sub;
66 89         242 my $seen = $seen{$export}{$sub}++;
67             croak qq{Can't import as "$export" twice}
68 89 50       104 if keys %{ $seen{$export} } > 1;
  89         187  
69 89 100       151 unless ($seen) {
70 87         87 warn(qq{ Importing "${package}::${symbol}" as "$export"\n})
71             if DEBUG;
72 87         342 push @exports, { export => $export, code => $sub };
73             }
74             }
75             }
76 16         106 return @exports;
77             }
78              
79             sub _module_opts {
80             state $IS_MODULE_OPTION
81 16     16   31 = { map { ; "-$_" => 1 } qw(how filter map prefix strict version) };
  24         57  
82              
83 16         41 my %opts = ( -strict => !!1 );
84 16         21 my $o = $_[0];
85 16 100       37 $opts{-strict} = !!$o->{-strict} if exists $o->{-strict};
86 16 100       36 exists $o->{-filter} and $opts{-filter} = $o->{-filter};
87             exists $o->{-map} and $opts{-map} = $o->{-map}
88 16 50 100 7   115 or exists $o->{-prefix} and $opts{-map} = sub { $o->{-prefix} . $_ };
  7   33     15  
89 16 50       34 exists $o->{-version} and $opts{-version} = $o->{-version};
90              
91 16 50       46 if ( my @bad = grep { !$IS_MODULE_OPTION->{$_} } keys %$o ) {
  8         31  
92 0         0 carp qq{Ignoring unknown module options (@bad)\n};
93             }
94 16         36 return \%opts;
95             }
96              
97             # $opts = _import_opts($opts1, $m_opts);
98             sub _import_opts {
99             state $IS_IMPORT_OPTION
100 166     166   195 = { map { ; "-$_" => 1 } qw(as filter map prefix strict) };
  20         46  
101              
102 166         286 my %opts = ( -strict => !!1 );
103             exists $_[1]{-filter}
104 166 100       317 and $opts{-filter} = _expand_filter( $_[1]{-filter} );
105 166 100       274 exists $_[1]{-map} and $opts{-map} = $_[1]{-map};
106 166 50       279 exists $_[1]{-strict} and $opts{-strict} = $_[1]{-strict};
107 166         181 my $o = $_[0];
108 166 100       242 $opts{-as} = $o->{-as} if exists $o->{-as};
109 166 50       230 exists $o->{-filter} and $opts{-filter} = _expand_filter( $o->{-filter} );
110             exists $o->{-map} and $opts{-map} = $o->{-map}
111 166 50 100 1   349 or exists $o->{-prefix} and $opts{-map} = sub { $o->{-prefix} . $_ };
  1   33     2  
112 166 100       221 $opts{-strict} = !!$o->{-strict} if exists $o->{-strict};
113              
114 166 50       335 if ( my @bad = grep { !$IS_IMPORT_OPTION->{$_} } keys %$o ) {
  8         23  
115 0         0 carp qq{Ignoring unknown symbol options (@bad)\n};
116             }
117 166         233 return \%opts;
118             }
119              
120             sub _expand_filter {
121 144     144   160 my $filter = shift;
122 144 100   72   324 ref $filter eq 'Regexp' ? sub {/$filter/} : $filter;
  72         281  
123             }
124              
125             sub _expand_symbol {
126 166 100 66 166   675 return $_[1] unless ref $_[1] || $_[1] =~ /^[:&]/;
127              
128 5 0       14 return map { /^&/ ? substr( $_, 1 ) : $_ } @{ $_[1] } if ref $_[1];
  0 50       0  
  0         0  
129              
130 5 100       16 return substr( $_[1], 1 ) if $_[1] =~ /^&/;
131              
132 3         9 my ( $package, $tag ) = ( $_[0], substr( $_[1], 1 ) );
133             my $symbols
134 3 50 33     4 = ${"${package}::"}{'EXPORT_TAGS'} && ${"${package}::EXPORT_TAGS"}{$tag}
135             or return $_[1];
136 3 50       6 return map { /^&/ ? substr( $_, 1 ) : $_ } @$symbols;
  6         17  
137             }
138              
139             sub _can_export {
140 16     16   25 my $package = shift;
141 16         21 my %exports;
142 16 100       22 for (
    50          
143 16         54 ( ${"${package}::"}{'EXPORT'} ? @{"${package}::EXPORT"} : () ),
  4         13  
144 16         41 ( ${"${package}::"}{'EXPORT_OK'} ? @{"${package}::EXPORT_OK"} : () )
  16         44  
145             )
146             {
147 360 100       506 my $x = /^&/ ? substr( $_, 1 ) : $_;
148 360         594 $exports{$x}++;
149             }
150 16         29 return \%exports;
151             }
152              
153 5     5   39 no Importer::Zim::Utils qw(DEBUG carp croak);
  5         17  
  5         35  
154              
155             1;
156              
157             #pod =encoding utf8
158             #pod
159             #pod =head1 DESCRIPTION
160             #pod
161             #pod "The Earth is safe once more, GIR! Now let's go destroy it!"
162             #pod – Zim
163             #pod
164             #pod No public interface.
165             #pod
166             #pod =head1 DEBUGGING
167             #pod
168             #pod You can set the C environment variable
169             #pod for get some diagnostics information printed to C.
170             #pod
171             #pod IMPORTER_ZIM_DEBUG=1
172             #pod
173             #pod =head1 SEE ALSO
174             #pod
175             #pod L
176             #pod
177             #pod =cut
178              
179             __END__