File Coverage

inc/Sub/Install.pm
Criterion Covered Total %
statement 63 93 67.7
branch 11 30 36.6
condition 2 11 18.1
subroutine 19 23 82.6
pod 2 2 100.0
total 97 159 61.0


line stmt bran cond sub pod time code
1             #line 1
2             package Sub::Install;
3 3     3   20  
  3         7  
  3         107  
4 3     3   17 use warnings;
  3         6  
  3         99  
5             use strict;
6 3     3   19  
  3         8  
  3         238  
7 3     3   20 use Carp;
  3         6  
  3         1636  
8             use Scalar::Util ();
9              
10             #line 17
11              
12             our $VERSION = '0.925';
13              
14             #line 86
15              
16             sub _name_of_code {
17             my ($code) = @_;
18             require B;
19             my $name = B::svref_2object($code)->GV->NAME;
20             return $name unless $name =~ /\A__ANON__/;
21             return;
22             }
23              
24             # See also Params::Util, to which this code was donated.
25             sub _CODELIKE {
26             (Scalar::Util::reftype($_[0])||'') eq 'CODE'
27             || Scalar::Util::blessed($_[0])
28             && (overload::Method($_[0],'&{}') ? $_[0] : undef);
29             }
30              
31             # do the heavy lifting
32             sub _build_public_installer {
33             my ($installer) = @_;
34              
35             sub {
36             my ($arg) = @_;
37             my ($calling_pkg) = caller(0);
38              
39             # I'd rather use ||= but I'm whoring for Devel::Cover.
40             for (qw(into from)) { $arg->{$_} = $calling_pkg unless $arg->{$_} }
41              
42             # This is the only absolutely required argument, in many cases.
43             Carp::croak "named argument 'code' is not optional" unless $arg->{code};
44              
45             if (_CODELIKE($arg->{code})) {
46             $arg->{as} ||= _name_of_code($arg->{code});
47             } else {
48             Carp::croak
49             "couldn't find subroutine named $arg->{code} in package $arg->{from}"
50             unless my $code = $arg->{from}->can($arg->{code});
51              
52             $arg->{as} = $arg->{code} unless $arg->{as};
53             $arg->{code} = $code;
54             }
55              
56             Carp::croak "couldn't determine name under which to install subroutine"
57             unless $arg->{as};
58              
59             $installer->(@$arg{qw(into as code) });
60             }
61             }
62              
63             # do the ugly work
64              
65             my $_misc_warn_re;
66             my $_redef_warn_re;
67             BEGIN {
68             $_misc_warn_re = qr/
69             Prototype\ mismatch:\ sub\ .+? |
70             Constant subroutine \S+ redefined
71             /x;
72             $_redef_warn_re = qr/Subroutine\ \S+\ redefined/x;
73             }
74              
75             my $eow_re;
76             BEGIN { $eow_re = qr/ at .+? line \d+\.\Z/ };
77              
78             sub _do_with_warn {
79             my ($arg) = @_;
80             my $code = delete $arg->{code};
81             my $wants_code = sub {
82             my $code = shift;
83             sub {
84             my $warn = $SIG{__WARN__} ? $SIG{__WARN__} : sub { warn @_ }; ## no critic
85             local $SIG{__WARN__} = sub {
86             my ($error) = @_;
87             for (@{ $arg->{suppress} }) {
88 0     0   0 return if $error =~ $_;
89 0         0 }
90 0         0 for (@{ $arg->{croak} }) {
91 0 0       0 if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
92 0         0 Carp::croak $base_error;
93             }
94             }
95             for (@{ $arg->{carp} }) {
96             if (my ($base_error) = $error =~ /\A($_) $eow_re/x) {
97 3 0 33 3   147 return $warn->(Carp::shortmess $base_error);
    50 50        
98             }
99             }
100             ($arg->{default} || $warn)->($error);
101             };
102             $code->(@_);
103             };
104 6     6   11 };
105             return $wants_code->($code) if $code;
106             return $wants_code;
107 3     3   7 }
108 3         26  
109             sub _installer {
110             sub {
111 3 50       13 my ($pkg, $name, $code) = @_;
  6         24  
112             no strict 'refs'; ## no critic ProhibitNoStrict
113             *{"$pkg\::$name"} = $code;
114 3 50       19 return $code;
115             }
116 3 50       13 }
117 0   0     0  
118             BEGIN {
119 3 50       49 *_ignore_warnings = _do_with_warn({
120             carp => [ $_misc_warn_re, $_redef_warn_re ]
121             });
122              
123 3 50       22 *install_sub = _build_public_installer(_ignore_warnings(_installer));
124 3         7  
125             *_carp_warnings = _do_with_warn({
126             carp => [ $_misc_warn_re ],
127 3 50       11 suppress => [ $_redef_warn_re ],
128             });
129              
130 3         17 *reinstall_sub = _build_public_installer(_carp_warnings(_installer));
131              
132 6         27 *_install_fatal = _do_with_warn({
133             code => _installer,
134             croak => [ $_redef_warn_re ],
135             });
136             }
137              
138             #line 231
139 3     3   18  
140             sub install_installers {
141             my ($into) = @_;
142              
143 3         109 for my $method (qw(install_sub reinstall_sub)) {
144             my $code = sub {
145             my ($package, $subs) = @_;
146             my ($caller) = caller(0);
147 3     3   1101 my $return;
148             for (my ($name, $sub) = %$subs) {
149             $return = Sub::Install->can($method)->({
150 9     9   15 code => $sub,
151 9         19 from => $caller,
152             into => $package,
153 9     9   15 as => $name
154             });
155 3 50   3   21 }
  0         0  
156             return $return;
157 0     0   0 };
158 0         0 install_sub({ code => $code, into => $into, as => $method });
  0         0  
159 0 0       0 }
160             }
161 0         0  
  0         0  
162 0 0       0 #line 270
163 0         0  
164             sub exporter {
165             my ($arg) = @_;
166 0         0
  0         0  
167 0 0       0 my %is_exported = map { $_ => undef } @{ $arg->{exports} };
168 0         0  
169             sub {
170             my $class = shift;
171 0   0     0 my $target = caller;
172 3         40 for (@_) {
173 3         12 Carp::croak "'$_' is not exported by $class" if !exists $is_exported{$_};
174 9         1157 install_sub({ code => $_, from => $class, into => $target });
175 9         31 }
176 9 100       38 }
177 6         15 }
178              
179             BEGIN { *import = exporter({ exports => [ qw(install_sub reinstall_sub) ] }); }
180              
181             #line 327
182 3     3   9  
183 3     3   21 1;
  3         6  
  3         599