File Coverage

blib/lib/Call/From.pm
Criterion Covered Total %
statement 37 38 97.3
branch 19 20 95.0
condition 19 27 70.3
subroutine 9 9 100.0
pod 2 2 100.0
total 86 96 89.5


line stmt bran cond sub pod time code
1 6     6   111914 use 5.006;
  6         28  
2 6     6   34 use strict;
  6         12  
  6         235  
3 6     6   44 use warnings;
  6         12  
  6         437  
4              
5             package Call::From;
6              
7             our $VERSION = '0.001000';
8             our $AUTHORITY = 'cpan:KENTNL';
9              
10 6     6   34 use Exporter qw();
  6         13  
  6         4951  
11             *import = \&Exporter::import;
12              
13             our @EXPORT_OK = qw( call_method_from call_function_from $_call_from );
14              
15             our $_call_from = sub {
16             $_[0]->${ \call_method_from( [ _to_caller( $_[1] ) ] ) }( @_[ 2 .. $#_ ] );
17             };
18              
19             sub _to_caller {
20 43     43   12295 my ( $ctx, $offset ) = @_;
21              
22             # +1 because this function is internal, and we dont
23             # want Call::From
24 43 100       118 $offset = 1 unless defined $offset;
25              
26             # Numeric special case first because caller is different
27 43 100 100     332 if ( defined $ctx and not ref $ctx and $ctx =~ /^-?\d+$/ ) {
      100        
28              
29 11         87 my (@call) = caller( $ctx + $offset );
30 11         86 return @call[ 0 .. 2 ];
31             }
32              
33 32         260 my (@call) = caller($offset);
34              
35             # _to_caller() returns the calling context of call_method_from
36 32 100       134 return @call[ 0 .. 2 ] if not defined $ctx;
37              
38             # _to_caller($name) as with (), but with replaced.
39 27 100       103 return ( $ctx, $call[1], $call[2] ) if not ref $ctx;
40              
41             # _to_caller([ pkg, (file,( line)) ]) fills the fields that are missing
42             return (
43 21   66     225 $ctx->[0] || $call[0], # pkg
      66        
      66        
44             $ctx->[1] || $call[1], # file
45             $ctx->[2] || $call[2], # line
46             );
47              
48             }
49              
50             sub _to_fun {
51 13 100   13   85 return $_[0] if 'CODE' eq ref $_[0];
52              
53 9 100 100     94 if ( defined $_[0]
54             and my ( $package, $function ) = $_[0] =~ /\A(.*?)::([^:]+)\z/ )
55             {
56             # q[::Foo]->can() is invalid before 5.18
57             # so map it to q[main::Foo]
58 6 100 33     28 $package = 'main' if not defined $package or not length $package;
59 6 100       65 if ( my $sub = "$package"->can($function) ) {
60 5         27 return $sub;
61             }
62 1         10 die "Can't resolve function <$function> in package <$package>";
63             }
64 3 100       12 my $arg = defined $_[0] ? qq["$_[0]"] : q[undef];
65 3         31 die "Can't automatically determine package and function from $arg";
66             }
67              
68             sub _gen_sub {
69 17     17   38 my ( $package, $file, $line, $code ) = @_;
70 17         62 my $sub_code =
71             qq[package $package;\n]
72             . qq[#line $line "$file"\n] . 'sub {'
73             . $code . '};';
74 17         27 local $@ = undef;
75 17         2278 my $sub = eval $sub_code;
76 17 50       370 $@ or return $sub;
77 0         0 die "Can't compile trampoline for $package: $@\n code => $sub_code";
78             }
79              
80             my $method_trampoline_cache = {};
81             my $function_trampoline_cache = {};
82              
83             sub call_method_from {
84 14     14 1 7019 my @caller = _to_caller( $_[0] );
85 14   66     101 return ( $method_trampoline_cache->{ join qq[\0], @caller } ||=
86             _gen_sub( @caller, q[ $_[0]->${\$_[1]}( @_[2..$#_ ] ) ] ) );
87             }
88              
89             sub call_function_from {
90 6     6 1 5254 my @caller = _to_caller( $_[0] );
91             return (
92 6   33     44 $function_trampoline_cache->{ join qq[\0], @caller } ||= _gen_sub(
93             @caller, __PACKAGE__ . q[::_to_fun($_[0])->( @_[1..$#_ ] ) ],
94             )
95             );
96             }
97              
98             1;
99              
100             __END__