File Coverage

blib/lib/Sub/Install.pm
Criterion Covered Total %
statement 93 95 97.8
branch 27 30 90.0
condition 6 11 54.5
subroutine 24 24 100.0
pod 2 2 100.0
total 152 162 93.8


line stmt bran cond sub pod time code
1 8     8   3096 use v5.8.0;
  8         64  
2 8     8   34 use strict;
  8         13  
  8         190  
3 8     8   59 use warnings;
  8         12  
  8         478  
4             package Sub::Install;
5             # ABSTRACT: install subroutines into packages easily
6             $Sub::Install::VERSION = '0.929';
7 8     8   39 use Carp;
  8         13  
  8         686  
8 8     8   40 use Scalar::Util ();
  8         15  
  8         3716  
9              
10             #pod =head1 SYNOPSIS
11             #pod
12             #pod use Sub::Install;
13             #pod
14             #pod Sub::Install::install_sub({
15             #pod code => sub { ... },
16             #pod into => $package,
17             #pod as => $subname
18             #pod });
19             #pod
20             #pod =head1 DESCRIPTION
21             #pod
22             #pod This module makes it easy to install subroutines into packages without the
23             #pod unsightly mess of C or typeglobs lying about where just anyone can
24             #pod see them.
25             #pod
26             #pod =func install_sub
27             #pod
28             #pod Sub::Install::install_sub({
29             #pod code => \&subroutine,
30             #pod into => "Finance::Shady",
31             #pod as => 'launder',
32             #pod });
33             #pod
34             #pod This routine installs a given code reference into a package as a normal
35             #pod subroutine. The above is equivalent to:
36             #pod
37             #pod no strict 'refs';
38             #pod *{"Finance::Shady" . '::' . "launder"} = \&subroutine;
39             #pod
40             #pod If C is not given, the sub is installed into the calling package.
41             #pod
42             #pod If C is not a code reference, it is looked for as an existing sub in the
43             #pod package named in the C parameter. If C is not given, it will look
44             #pod in the calling package.
45             #pod
46             #pod If C is not given, and if C is a name, C will default to C.
47             #pod If C is not given, but if C is a code ref, Sub::Install will try to
48             #pod find the name of the given code ref and use that as C.
49             #pod
50             #pod That means that this code:
51             #pod
52             #pod Sub::Install::install_sub({
53             #pod code => 'twitch',
54             #pod from => 'Person::InPain',
55             #pod into => 'Person::Teenager',
56             #pod as => 'dance',
57             #pod });
58             #pod
59             #pod is the same as:
60             #pod
61             #pod package Person::Teenager;
62             #pod
63             #pod Sub::Install::install_sub({
64             #pod code => Person::InPain->can('twitch'),
65             #pod as => 'dance',
66             #pod });
67             #pod
68             #pod =func reinstall_sub
69             #pod
70             #pod This routine behaves exactly like C>, but does not emit a
71             #pod warning if warnings are on and the destination is already defined.
72             #pod
73             #pod =cut
74              
75             sub _name_of_code {
76 2     2   5 my ($code) = @_;
77 2         11 require B;
78 2         20 my $name = B::svref_2object($code)->GV->NAME;
79 2 100       12 return $name unless $name =~ /\A__ANON__/;
80 1         4 return;
81             }
82              
83             # See also Params::Util, to which this code was donated.
84             sub _CODELIKE {
85 33 0 33 33   194 (Scalar::Util::reftype($_[0])||'') eq 'CODE'
    100 100        
86             || Scalar::Util::blessed($_[0])
87             && (overload::Method($_[0],'&{}') ? $_[0] : undef);
88             }
89              
90             # do the heavy lifting
91             sub _build_public_installer {
92 17     17   1295 my ($installer) = @_;
93              
94             sub {
95 34     34   11133 my ($arg) = @_;
96 34         168 my ($calling_pkg) = caller(0);
97              
98             # I'd rather use ||= but I'm whoring for Devel::Cover.
99 34 100       79 for (qw(into from)) { $arg->{$_} = $calling_pkg unless $arg->{$_} }
  68         185  
100              
101             # This is the only absolutely required argument, in many cases.
102 34 100       225 Carp::croak "named argument 'code' is not optional" unless $arg->{code};
103              
104 33 100       72 if (_CODELIKE($arg->{code})) {
105 26   100     64 $arg->{as} ||= _name_of_code($arg->{code});
106             } else {
107             Carp::croak
108             "couldn't find subroutine named $arg->{code} in package $arg->{from}"
109 7 100       150 unless my $code = $arg->{from}->can($arg->{code});
110              
111 6 100       19 $arg->{as} = $arg->{code} unless $arg->{as};
112 6         12 $arg->{code} = $code;
113             }
114              
115             Carp::croak "couldn't determine name under which to install subroutine"
116 32 100       129 unless $arg->{as};
117              
118 31         75 $installer->(@$arg{qw(into as code) });
119             }
120 17         73 }
121              
122             # do the ugly work
123              
124             my $_misc_warn_re;
125             my $_redef_warn_re;
126             BEGIN {
127 8     8   47 $_misc_warn_re = qr/
128             Prototype\ mismatch:\ sub\ .+? |
129             Constant subroutine .+? redefined
130             /x;
131 8         221 $_redef_warn_re = qr/Subroutine\ .+?\ redefined/x;
132             }
133              
134             my $eow_re;
135 8     8   2461 BEGIN { $eow_re = qr/ at .+? line \d+\.\Z/ };
136              
137             sub _do_with_warn {
138 24     24   40 my ($arg) = @_;
139 24         48 my $code = delete $arg->{code};
140             my $wants_code = sub {
141 24     24   30 my $code = shift;
142             sub {
143 31 100   31   122 my $warn = $SIG{__WARN__} ? $SIG{__WARN__} : sub { warn @_ }; ## no critic
  0         0  
144             local $SIG{__WARN__} = sub {
145 9     9   319 my ($error) = @_;
146 9         12 for (@{ $arg->{suppress} }) {
  9         21  
147 4 100       43 return if $error =~ $_;
148             }
149 7         8 for (@{ $arg->{croak} }) {
  7         15  
150 1 50       23 if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
151 1         82 Carp::croak $base_error;
152             }
153             }
154 6         8 for (@{ $arg->{carp} }) {
  6         10  
155 8 100       278 if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
156 6         817 return $warn->(Carp::shortmess $base_error);
157             }
158             }
159 0   0     0 ($arg->{default} || $warn)->($error);
160 31         141 };
161 31         82 $code->(@_);
162 24         2517 };
163 24         64 };
164 24 100       75 return $wants_code->($code) if $code;
165 16         36 return $wants_code;
166             }
167              
168             sub _installer {
169             sub {
170 31     31   78 my ($pkg, $name, $code) = @_;
171 8     8   49 no strict 'refs'; ## no critic ProhibitNoStrict
  8         17  
  8         1165  
172 31         37 *{"$pkg\::$name"} = $code;
  31         168  
173 30         429 return $code;
174             }
175 24     24   86 }
176              
177             BEGIN {
178 8     8   50 *_ignore_warnings = _do_with_warn({
179             carp => [ $_misc_warn_re, $_redef_warn_re ]
180             });
181              
182 8         16 *install_sub = _build_public_installer(_ignore_warnings(_installer));
183              
184 8         36 *_carp_warnings = _do_with_warn({
185             carp => [ $_misc_warn_re ],
186             suppress => [ $_redef_warn_re ],
187             });
188              
189 8         15 *reinstall_sub = _build_public_installer(_carp_warnings(_installer));
190              
191 8         20 *_install_fatal = _do_with_warn({
192             code => _installer,
193             croak => [ $_redef_warn_re ],
194             });
195             }
196              
197             #pod =func install_installers
198             #pod
199             #pod This routine is provided to allow Sub::Install compatibility with
200             #pod Sub::Installer. It installs C and C methods into
201             #pod the package named by its argument.
202             #pod
203             #pod Sub::Install::install_installers('Code::Builder'); # just for us, please
204             #pod Code::Builder->install_sub({ name => $code_ref });
205             #pod
206             #pod Sub::Install::install_installers('UNIVERSAL'); # feeling lucky, punk?
207             #pod Anything::At::All->install_sub({ name => $code_ref });
208             #pod
209             #pod The installed installers are similar, but not identical, to those provided by
210             #pod Sub::Installer. They accept a single hash as an argument. The key/value pairs
211             #pod are used as the C and C parameters to the C routine
212             #pod detailed above. The package name on which the method is called is used as the
213             #pod C parameter.
214             #pod
215             #pod Unlike Sub::Installer's C will not eval strings into code, but
216             #pod will look for named code in the calling package.
217             #pod
218             #pod =cut
219              
220             sub install_installers {
221 2     2 1 161 my ($into) = @_;
222              
223 2         5 for my $method (qw(install_sub reinstall_sub)) {
224             my $code = sub {
225 6     6   4945 my ($package, $subs) = @_;
226 6         42 my ($caller) = caller(0);
227 6         10 my $return;
228 6         20 for (my ($name, $sub) = %$subs) {
229 12         68 $return = Sub::Install->can($method)->({
230             code => $sub,
231             from => $caller,
232             into => $package,
233             as => $name
234             });
235             }
236 6         13 return $return;
237 4         17 };
238 4         15 install_sub({ code => $code, into => $into, as => $method });
239             }
240             }
241              
242             #pod =head1 EXPORTS
243             #pod
244             #pod Sub::Install exports C and C only if they are
245             #pod requested.
246             #pod
247             #pod =head2 exporter
248             #pod
249             #pod Sub::Install has a never-exported subroutine called C, which is used
250             #pod to implement its C routine. It takes a hashref of named arguments,
251             #pod only one of which is currently recognize: C. This must be an arrayref
252             #pod of subroutines to offer for export.
253             #pod
254             #pod This routine is mainly for Sub::Install's own consumption. Instead, consider
255             #pod L.
256             #pod
257             #pod =cut
258              
259             sub exporter {
260 9     9 1 96 my ($arg) = @_;
261              
262 9         13 my %is_exported = map { $_ => undef } @{ $arg->{exports} };
  17         48  
  9         21  
263              
264             sub {
265 12     12   111083 my $class = shift;
266 12         24 my $target = caller;
267 12         192 for (@_) {
268 5 100       172 Carp::croak "'$_' is not exported by $class" if !exists $is_exported{$_};
269 4         21 install_sub({ code => $_, from => $class, into => $target });
270             }
271             }
272 9         376 }
273              
274 8     8   42 BEGIN { *import = exporter({ exports => [ qw(install_sub reinstall_sub) ] }); }
275              
276             #pod =head1 SEE ALSO
277             #pod
278             #pod =over
279             #pod
280             #pod =item L
281             #pod
282             #pod This module is (obviously) a reaction to Damian Conway's Sub::Installer, which
283             #pod does the same thing, but does it by getting its greasy fingers all over
284             #pod UNIVERSAL. I was really happy about the idea of making the installation of
285             #pod coderefs less ugly, but I couldn't bring myself to replace the ugliness of
286             #pod typeglobs and loosened strictures with the ugliness of UNIVERSAL methods.
287             #pod
288             #pod =item L
289             #pod
290             #pod This is a complete Exporter.pm replacement, built atop Sub::Install.
291             #pod
292             #pod =back
293             #pod
294             #pod =head1 EXTRA CREDITS
295             #pod
296             #pod Several of the tests are adapted from tests that shipped with Damian Conway's
297             #pod Sub-Installer distribution.
298             #pod
299             #pod =cut
300              
301             1;
302              
303             __END__