File Coverage

blib/lib/Importer/Zim/Base.pm
Criterion Covered Total %
statement 88 103 85.4
branch 50 70 71.4
condition 15 25 60.0
subroutine 13 14 92.8
pod 0 1 0.0
total 166 213 77.9


line stmt bran cond sub pod time code
1              
2             package Importer::Zim::Base;
3             $Importer::Zim::Base::VERSION = '0.12.0';
4             # ABSTRACT: Base module for Importer::Zim backends
5              
6 5     5   195004 use 5.010001;
  5         58  
7              
8 5     5   1533 use Module::Runtime ();
  5         7044  
  5         142  
9              
10 5     5   1299 use Importer::Zim::Utils qw(DEBUG carp croak);
  5         14  
  5         26  
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   50483 my $class = shift;
38 16 50       48 my $package = shift
39             or croak qq{Usage: use $class MODULE => [\%OPTS =>] EXPORTS...\n};
40              
41 16 100       64 my $opts = _module_opts( ref $_[0] eq 'HASH' ? shift : {} );
42 16 50       42 my @version = exists $opts->{-version} ? ( $opts->{-version} ) : ();
43 16         56 &Module::Runtime::use_module( $package, @version );
44              
45 16         8964 my $can_export = _can_export($package);
46              
47 16         28 my ( @exports, %seen );
48 16 100 66     43 @_ = @{"${package}::EXPORT"} unless @_ || !${"${package}::"}{'EXPORT'};
  4         23  
  4         19  
49 16         36 while (@_) {
50 166         282 my @symbols = _expand_symbol( $package, shift );
51 166 100       396 my $opts = _import_opts( ref $_[0] eq 'HASH' ? shift : {}, $opts );
52             exists $opts->{-filter}
53 166 100       344 and @symbols = grep &{ $opts->{-filter} }, @symbols;
  144         226  
54 166         518 for my $symbol (@symbols) {
55             croak qq{"$symbol" is not exported by "$package"}
56 89 50 66     264 if $opts->{-strict} && !$can_export->{$symbol};
57 89 50       174 croak qq{Can't handle "$symbol"}
58             if $symbol =~ /^[\$\@\%\*]/;
59 89         99 my $sub = *{"${package}::${symbol}"}{CODE};
  89         211  
60 89         116 my $export = do {
61 89   66     214 local $_ = $opts->{-as} // $symbol;
62 89 100       169 exists $opts->{-map} ? $opts->{-map}->() : $_;
63             };
64 89 50       143 croak qq{Can't find "$symbol" in "$package"}
65             unless $sub;
66 89         237 my $seen = $seen{$export}{$sub}++;
67             croak qq{Can't import as "$export" twice}
68 89 50       103 if keys %{ $seen{$export} } > 1;
  89         207  
69 89 100       147 unless ($seen) {
70 87         100 warn(qq{ Importing "${package}::${symbol}" as "$export"\n})
71             if DEBUG;
72 87         341 push @exports, { export => $export, code => $sub };
73             }
74             }
75             }
76 16         110 return @exports;
77             }
78              
79             sub _module_opts {
80             state $IS_MODULE_OPTION
81 16     16   29 = { map { ; "-$_" => 1 } qw(how filter map prefix strict version) };
  24         60  
82              
83 16         47 my %opts = ( -strict => !!1 );
84 16         26 my $o = $_[0];
85 16 100       42 $opts{-strict} = !!$o->{-strict} if exists $o->{-strict};
86 16 100       35 exists $o->{-filter} and $opts{-filter} = $o->{-filter};
87             exists $o->{-map} and $opts{-map} = $o->{-map}
88 16 50 100 7   71 or exists $o->{-prefix} and $opts{-map} = sub { $o->{-prefix} . $_ };
  7   33     17  
89              
90 16 50       52 if ( my @bad = grep { !$IS_MODULE_OPTION->{$_} } keys %$o ) {
  8         38  
91 0         0 carp qq{Ignoring unknown module options (@bad)\n};
92             }
93 16         34 return \%opts;
94             }
95              
96             # $opts = _import_opts($opts1, $m_opts);
97             sub _import_opts {
98             state $IS_IMPORT_OPTION
99 166     166   190 = { map { ; "-$_" => 1 } qw(as filter map prefix strict) };
  20         51  
100              
101 166         292 my %opts = ( -strict => !!1 );
102             exists $_[1]{-filter}
103 166 100       325 and $opts{-filter} = _expand_filter( $_[1]{-filter} );
104 166 100       284 exists $_[1]{-map} and $opts{-map} = $_[1]{-map};
105 166 50       292 exists $_[1]{-strict} and $opts{-strict} = $_[1]{-strict};
106 166         189 my $o = $_[0];
107 166 100       256 $opts{-as} = $o->{-as} if exists $o->{-as};
108 166 50       239 exists $o->{-filter} and $opts{-filter} = _expand_filter( $o->{-filter} );
109             exists $o->{-map} and $opts{-map} = $o->{-map}
110 166 50 100 1   340 or exists $o->{-prefix} and $opts{-map} = sub { $o->{-prefix} . $_ };
  1   33     3  
111 166 100       226 $opts{-strict} = !!$o->{-strict} if exists $o->{-strict};
112              
113 166 50       346 if ( my @bad = grep { !$IS_IMPORT_OPTION->{$_} } keys %$o ) {
  8         22  
114 0         0 carp qq{Ignoring unknown symbol options (@bad)\n};
115             }
116 166         246 return \%opts;
117             }
118              
119             sub _expand_filter {
120 144     144   173 my $filter = shift;
121 144 100   72   367 ref $filter eq 'Regexp' ? sub {/$filter/} : $filter;
  72         244  
122             }
123              
124             sub _expand_symbol {
125 166 100 66 166   632 return $_[1] unless ref $_[1] || $_[1] =~ /^[:&]/;
126              
127 5 0       28 return map { /^&/ ? substr( $_, 1 ) : $_ } @{ $_[1] } if ref $_[1];
  0 50       0  
  0         0  
128              
129 5 100       18 return substr( $_[1], 1 ) if $_[1] =~ /^&/;
130              
131 3         11 my ( $package, $tag ) = ( $_[0], substr( $_[1], 1 ) );
132             my $symbols
133 3 50 33     3 = ${"${package}::"}{'EXPORT_TAGS'} && ${"${package}::EXPORT_TAGS"}{$tag}
134             or return $_[1];
135 3 50       7 return map { /^&/ ? substr( $_, 1 ) : $_ } @$symbols;
  6         20  
136             }
137              
138             sub _can_export {
139 16     16   25 my $package = shift;
140 16         23 my %exports;
141 16 100       22 for (
    50          
142 16         57 ( ${"${package}::"}{'EXPORT'} ? @{"${package}::EXPORT"} : () ),
  4         11  
143 16         40 ( ${"${package}::"}{'EXPORT_OK'} ? @{"${package}::EXPORT_OK"} : () )
  16         43  
144             )
145             {
146 360 100       511 my $x = /^&/ ? substr( $_, 1 ) : $_;
147 360         649 $exports{$x}++;
148             }
149 16         27 return \%exports;
150             }
151              
152 5     5   41 no Importer::Zim::Utils qw(DEBUG carp croak);
  5         12  
  5         34  
153              
154             1;
155              
156             #pod =encoding utf8
157             #pod
158             #pod =head1 DESCRIPTION
159             #pod
160             #pod "The Earth is safe once more, GIR! Now let's go destroy it!"
161             #pod – Zim
162             #pod
163             #pod No public interface.
164             #pod
165             #pod =head1 DEBUGGING
166             #pod
167             #pod You can set the C environment variable
168             #pod for get some diagnostics information printed to C.
169             #pod
170             #pod IMPORTER_ZIM_DEBUG=1
171             #pod
172             #pod =head1 SEE ALSO
173             #pod
174             #pod L
175             #pod
176             #pod =cut
177              
178             __END__