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