File Coverage

blib/lib/Import/Into/As.pm
Criterion Covered Total %
statement 60 62 96.7
branch 25 30 83.3
condition 6 9 66.6
subroutine 8 8 100.0
pod n/a
total 99 109 90.8


line stmt bran cond sub pod time code
1             package Import::Into::As;
2 1     1   2562443 use strict;
  1         2  
  1         64  
3 1     1   5 use warnings;
  1         2  
  1         46  
4              
5             our $VERSION = '0.000001';
6              
7 1     1   863 use Import::Into;
  1         3674  
  1         32  
8 1     1   6 use Carp qw/croak/;
  1         2  
  1         268  
9              
10             sub import::into::as {
11 4     4   839 my $class = shift;
12 4         9 my ($target, $rename, @args) = @_;
13              
14             # need to bump level by 2, 1 for the call to _get_imported_syms,
15             # another for the call to import::into
16 4         4 my $bump_level = 2;
17              
18 4         5 my ($dest, $level);
19              
20 4 100       20 if (ref $target) {
    100          
21 2 100       7 $dest = $target->{package} if exists $target->{package};
22 2 100       5 if (exists $target->{level}) {
23 1         2 $level = $target->{level};
24 1   33     5 $dest ||= caller($level);
25 1         2 $target->{level} += $bump_level;
26             }
27             }
28             elsif ($target =~ m/^\d+$/) {
29 1         2 $level = $target;
30 1         2 $dest = caller($level);
31 1         3 $target += $bump_level;
32             }
33             else {
34 1         2 $dest = $target;
35             }
36              
37 4 50       11 croak "unable to find destination package!"
38             unless $dest;
39              
40             # Get all the symbols that should be imported. This is a hashref of symbol
41             # names where value is an arrayref of glob entries.
42 4         9 my %syms = _get_imported_syms($class, $target, \@args, $dest);
43              
44             # Load each import symbol into the destination namespace
45 4         17 for my $sym (keys %syms) {
46 17 100       43 next if $sym eq '__ANON__';
47              
48             # Coderefs can be renamed.
49 13   66     44 my $subname = $rename->{$sym} || $sym;
50              
51 1     1   5 no strict 'refs';
  1         2  
  1         229  
52              
53             # Only support the big 4 types in the glob.
54 13 100       42 *{"$dest\::$subname"} = $syms{$sym}{CODE} if $syms{$sym}{CODE};
  10         43  
55 13 100       33 *{"$dest\::$sym"} = $syms{$sym}{SCALAR} if $syms{$sym}{SCALAR};
  4         19  
56 13 50       26 *{"$dest\::$sym"} = $syms{$sym}{HASH} if $syms{$sym}{HASH};
  0         0  
57 13 50       1868 *{"$dest\::$sym"} = $syms{$sym}{ARRAY} if $syms{$sym}{ARRAY};
  0         0  
58             }
59             }
60              
61             # This will import the symbols into the desired namespace, but will localize
62             # the namespace to ensure no changes are actually made. It will then return all
63             # the symbols that were imported into the namespace and restore the
64             # namespace to its previous state.
65             sub _get_imported_syms {
66 4     4   8 my ($module, $target, $args, $dest) = @_;
67              
68             # This block does some crazy things, we need to turn off strict refs
69 1     1   6 no strict 'refs';
  1         5  
  1         285  
70              
71             # Localize the entire destination namespace so that we don't actually do
72             # anything to it. This also means we do not need to turn off redefine
73             # warnings.
74 4         4 local *{"$dest\::"};
  4         12  
75              
76             # Import into the namespace we just protected with local.
77 4         14 $module->import::into($target, @$args);
78              
79             # Generate a (sym => { CODE => ..., SCALAR => ..., ... }, ...) hash.
80             return map {
81 17         19 my $code = *{"$dest\::$_"}{CODE};
  17         37  
82 17         17 my $array = *{"$dest\::$_"}{ARRAY};
  17         39  
83 17         17 my $hash = *{"$dest\::$_"}{HASH};
  17         28  
84 17         18 my $scalar = *{"$dest\::$_"}{SCALAR};
  17         32  
85              
86             # Scalars in globs are crazy... this is "good enough", though it will
87             # fail for anonymous scalar exports that are set to undef.
88 17 100 100     45 $scalar = undef unless defined($$scalar) || $scalar == \${"$module\::$_"};
  15         72  
89              
90 17 100       150 $_ => {
    50          
    50          
    100          
91             $code ? (CODE => $code) : (),
92             $array ? (ARRAY => $array) : (),
93             $hash ? (HASH => $hash) : (),
94             $scalar ? (SCALAR => $scalar) : (),
95             }
96 4         951 } keys %{"$dest\::"};
  4         14  
97             }
98              
99             1;
100              
101             __END__