File Coverage

blib/lib/Sub/Import.pm
Criterion Covered Total %
statement 78 88 88.6
branch 6 10 60.0
condition 1 3 33.3
subroutine 18 22 81.8
pod n/a
total 103 123 83.7


line stmt bran cond sub pod time code
1 2     2   136506 use strict;
  2         24  
  2         62  
2 2     2   9 use warnings;
  2         4  
  2         127  
3              
4             package Sub::Import 1.002;
5             # ABSTRACT: import routines from most anything using Sub::Exporter
6              
7 2     2   14 use B qw(svref_2object);
  2         3  
  2         93  
8 2     2   11 use Carp ();
  2         5  
  2         24  
9 2     2   8 use Exporter ();
  2         3  
  2         33  
10 2     2   998 use Params::Util qw(_CLASS _CLASSISA);
  2         12730  
  2         133  
11 2     2   1283 use Sub::Exporter ();
  2         14170  
  2         855  
12              
13             #pod =head1 SYNOPSIS
14             #pod
15             #pod use Sub::Import 'Some::Library' => (
16             #pod some_routine => { -as => 'some_other_name' },
17             #pod other_routine => undef,
18             #pod );
19             #pod
20             #pod Some more examples:
21             #pod
22             #pod # import a function with a custom name
23             #pod use Sub::Import 'Digest::MD5', md5_hex => {-as => 'md5sum'};
24             #pod
25             #pod # import multiple functions, each with its own name
26             #pod use Sub::Import 'MIME::Base64',
27             #pod encode_base64 => {-as => 'e64'},
28             #pod decode_base64 => {-as => 'd64'};
29             #pod
30             #pod # Import most functions with the "trig_" prefix, e.g. "trig_log",
31             #pod # "trig_sin", "trig_cos", etc.
32             #pod use Sub::Import 'Math::Trig', -all => {-prefix => 'trig_'};
33             #pod
34             #pod # Import PI-related functions with the "_the_great" suffix, e.g.
35             #pod # "pi_the_great", "pi2_the_great", etc.
36             #pod use Sub::Import 'Math::Trig', -pi => {-suffix => '_the_great'};
37             #pod
38             #pod =head1 DESCRIPTION
39             #pod
40             #pod Sub::Import is the companion to Sub::Exporter. You can use Sub::Import to get
41             #pod Sub::Exporter-like import semantics, even if the library you're importing from
42             #pod used Exporter.pm.
43             #pod
44             #pod The synopsis above should say it all. Where you would usually say:
45             #pod
46             #pod use Some::Library qw(foo bar baz);
47             #pod
48             #pod ...to get Exporter.pm semantics, you can now get Sub::Exporter semantics with:
49             #pod
50             #pod use Sub::Import 'Some::Library' => qw(foo bar baz);
51             #pod
52             #pod =head1 WARNINGS AND LIMITATIONS
53             #pod
54             #pod While you can rename imports, there is no way to customize them, because they
55             #pod are not being built by generators. At present, extra arguments for each import
56             #pod will be thrown away. In the future, they may become a fatal error.
57             #pod
58             #pod Non-subroutine imports will not be importable via this mechanism.
59             #pod
60             #pod The regex-like import features of Exporter.pm will be unavailable. (Will
61             #pod anyone miss them?)
62             #pod
63             #pod =cut
64              
65             sub import {
66 2     2   32 my ($self, $target, @args) = @_;
67              
68 2         6 my $import = $self->_get_import($target);
69              
70 2         10 @_ = ($target, @args);
71 2         12 goto &$import;
72             }
73              
74             sub unimport {
75 0     0   0 my ($self, $target, @args) = @_;
76              
77 0         0 my $unimport = $self->_get_unimport($target);
78              
79 0         0 @_ = ($target, @args);
80 0         0 goto &$unimport;
81             }
82              
83             sub _get_unimport {
84 0     0   0 my ($self, $target) = @_;
85              
86 0         0 $self->_get_methods($target)->{unimport};
87             }
88              
89             sub _get_import {
90 2     2   4 my ($self, $target) = @_;
91              
92 2         7 $self->_get_methods($target)->{import};
93             }
94              
95             my %GENERATED_METHODS;
96             sub _get_methods {
97 2     2   4 my ($self, $target) = @_;
98              
99 2   33     18 $GENERATED_METHODS{$target} ||= $self->_create_methods($target);
100             }
101              
102             sub _require_class {
103 2     2   4 my ($self, $class) = @_;
104              
105 2 50       8 Carp::croak("invalid package name: $class") unless _CLASS($class);
106              
107 2         33 local $@;
108 2 50       112 eval "require $class; 1" or die;
109              
110 2         8 return;
111             }
112              
113             sub _is_sexy {
114 2     2   4 my ($self, $class) = @_;
115              
116 2         4 local $@;
117 2         4 my $isa;
118 2         4 my $ok = eval {
119 2         30 my $obj = svref_2object( $class->can('import') );
120 2         45 my $importer_pkg = $obj->START->stashpv;
121 2         50 $isa = _CLASSISA($importer_pkg, 'Sub::Exporter');
122 2         41 1;
123             };
124              
125 2         10 return $isa;
126             }
127              
128             my $EXPORTER_IMPORT;
129 2     2   634 BEGIN { $EXPORTER_IMPORT = Exporter->can('import'); }
130             sub _is_exporterrific {
131 1     1   3 my ($self, $class) = @_;
132              
133 1         2 my $class_import = do {
134 1         1 local $@;
135 1         3 eval { $class->can('import') };
  1         4  
136             };
137              
138 1 50       3 return unless $class_import;
139 1         4 return $class_import == $EXPORTER_IMPORT;
140             }
141              
142             sub _create_methods {
143 2     2   5 my ($self, $target) = @_;
144              
145 2         7 $self->_require_class($target);
146              
147 2 100       12 if ($self->_is_sexy($target)) {
    50          
148             return {
149 1         13 import => $target->can("import"),
150             unimport => $target->can("unimport"),
151             };
152             } elsif ($self->_is_exporterrific($target)) {
153 1         3 return $self->_create_methods_exporter($target);
154             } else {
155 0         0 return $self->_create_methods_fallback($target);
156             }
157             }
158              
159             sub __filter_subs {
160 2     2   5 my ($self, $exports) = @_;
161              
162 2         4 @$exports = map { s/\A&//; $_ } grep { /\A[&_a-z]/ } @$exports;
  1         4  
  1         4  
  1         5  
163             }
164              
165             sub _create_methods_exporter {
166 1     1   2 my ($self, $target) = @_;
167              
168 2     2   19 no strict 'refs';
  2         10  
  2         500  
169              
170 1         1 my @ok = @{ $target . "::EXPORT_OK" };
  1         6  
171 1         9 my @default = @{ $target . "::EXPORT" };
  1         5  
172 1         6 my %groups = %{ $target . "::EXPORT_TAGS" };
  1         5  
173              
174 1         4 $self->__filter_subs($_) for (\@ok, \@default, values %groups);
175              
176 1         2 my @all = do {
177 1         1 my %seen;
178 1         2 grep { ! $seen{$_}++ } @ok, @default;
  1         5  
179             };
180              
181 1         6 my $import = Sub::Exporter::build_exporter({
182             exports => \@all,
183             groups => {
184             %groups,
185             default => \@default,
186             }
187             });
188              
189             return {
190             import => $import,
191 0     0     unimport => sub { die "unimport not handled for Exporter via Sub::Import" },
192 1         219 };
193             }
194              
195             sub _create_methods_fallback {
196 0     0     my ($self, @target) = @_;
197              
198 0           Carp::confess(
199             "Sub::Import only handles Sub::Exporter and Exporter-based import methods"
200             );
201             }
202              
203             1;
204              
205             __END__