File Coverage

blib/lib/methods/import.pm
Criterion Covered Total %
statement 89 101 88.1
branch 25 34 73.5
condition 13 19 68.4
subroutine 16 18 88.8
pod 0 6 0.0
total 143 178 80.3


line stmt bran cond sub pod time code
1 5     5   354571 use 5.008006;
  5         74  
2 5     5   26 use strict;
  5         5  
  5         119  
3 5     5   36 use warnings;
  5         15  
  5         386  
4              
5             package methods::import;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.001';
9              
10 5     5   2119 use namespace::clean qw();
  5         67835  
  5         101  
11 5     5   33 use Sub::Util qw();
  5         8  
  5         3982  
12              
13             sub import {
14 6     6   387 my $caller = caller;
15 6         11 my $class = shift;
16 6         18 return $class->import_into($caller, @_);
17             }
18              
19             sub method_list {
20 0     0 0 0 require Carp;
21 0         0 Carp::croak("No methods listed to import");
22             }
23              
24             {
25             my %bools = (-keep => 1);
26             sub _get_opt {
27 26     26   32 my $class = shift;
28 26         41 my ($list) = @_;
29 26 50       73 my $opts =
    100          
30             ref($list->[0]) eq 'HASH' ? shift @$list :
31             ref($list->[0]) eq 'ARRAY' ? $class->_hashify(shift @$list) :
32             {};
33 26   66     136 while (@$list and !ref($list->[0]) and exists($bools{$list->[0]})) {
      100        
34 1         3 my $thing = shift @$list;
35 1         5 $opts->{$thing} = $bools{$thing};
36             }
37 26         42 return $opts;
38             }
39             sub _hashify {
40 0     0   0 shift;
41 0         0 @_ = @{+shift};
  0         0  
42 0         0 my %r;
43 0         0 while (@_) {
44 0         0 my $thing = shift;
45 0 0       0 $r{$thing} = exists($bools{$thing}) ? 1 : shift;
46             }
47 0         0 \%r;
48             }
49             }
50              
51             sub import_into {
52 6     6 0 13 my $class = shift;
53 6         11 my $caller = shift;
54 6         7 my $using;
55            
56 6 50       19 @_ = $class->method_list unless @_;
57 6         16 my $default_opts = $class->_get_opt(\@_);
58            
59 6 50 66     55 push @_, 'using' unless grep !ref && /^using$/, @_;
60            
61 6         14 while (@_) {
62 20         397 my $method = shift;
63 20         42 my $opts = $class->_get_opt(\@_);
64 20 100       50 if ($method =~ /=/) {
65 6         32 ($method, $opts->{-as}, $opts->{-prototype}) = split /=/, $method;
66             }
67 20         70 $opts = { %$default_opts, %$opts };
68 20   50     80 $opts->{'-using'} ||= \$using;
69 20         37 $class->import_method($caller, $method, $opts);
70             }
71 6         2085 return;
72             }
73              
74             sub import_method {
75 20     20 0 26 my $class = shift;
76 20         40 my ($caller, $method, $opts) = @_;
77 20         33 my $coderef = $class->make_coderef($method, $opts);
78 20         43 $class->install_coderef($caller, $coderef, $method, $opts);
79             }
80              
81             sub make_coderef {
82 20     20 0 25 my $class = shift;
83 20         30 my ($method, $opts) = @_;
84 20   100     71 my $curry = $opts->{'-curry'} || [];
85 20         28 my $coderef;
86 20 100       40 if ($method eq 'using') {
87             $coderef = sub {
88 5 100   5   577 return ${$opts->{'-using'}} unless @_;
  2     3   8  
89 3         8 my ($object, $coderef) = @_;
90 3         6 my $old = ${$opts->{'-using'}};
  3         9  
91 3         5 ${$opts->{'-using'}} = $object;
  3         7  
92 3 100       8 return $old unless $coderef;
93 1         2 my @r;
94 1 50       3 if (wantarray) {
    50          
95 0         0 @r = $coderef->();
96             }
97             elsif (defined wantarray) {
98 0         0 $r[0] = $coderef->();
99             }
100             else {
101 1         4 $coderef->(); 1;
  1         417  
102             }
103 1         3 ${$opts->{'-using'}} = $old;
  1         2  
104 1 50       5 wantarray ? @r : $r[0];
105 6         41 };
106             }
107             else {
108             $coderef = sub {
109 14 100   14   15507 defined(my $object = defined(${$opts->{'-using'}}) ? ${$opts->{'-using'}} : $_)
  14 100       68  
  6         23  
110             or $class->croak_undefined($method, $opts);
111 13         60 $object->$method(@$curry, @_);
112 14         62 };
113             }
114 20 100       103 if (defined $opts->{-prototype}) {
115 1         11 $coderef = Sub::Util::set_prototype($opts->{-prototype}, $coderef);
116             }
117 20         36 return $coderef;
118             }
119              
120             sub install_coderef {
121 20     23 0 29 my $class = shift;
122 20         45 my ($caller, $coderef, $method, $opts) = @_;
123 20   66     64 my $as = $opts->{'-as'} || $method;
124 20 50       42 return if $as eq '-';
125 20         115 $coderef = Sub::Util::set_subname("$caller\::$as", $coderef);
126 20         34 do {
127 5     5   37 no strict 'refs';
  5         10  
  5         711  
128 20         49 *{"$caller\::$as"} = $coderef;
  20         111  
129             };
130             'namespace::clean'->import(-cleanee => $caller, $as)
131 20 100       134 unless $opts->{'-keep'};
132             }
133              
134             sub croak_undefined {
135 1     4 0 2 my $class = shift;
136 1         2 my ($method, $opts) = @_;
137 1   33     4 my $as = $opts->{'-as'} || $method;
138 1         6 require Carp;
139 1         138 Carp::croak("Can't call method \"$method\" (via imported sub \"$as\") because \$_ is not defined");
140             }
141              
142             1;
143              
144             __END__