File Coverage

blib/lib/Exporter/Renaming.pm
Criterion Covered Total %
statement 89 89 100.0
branch 34 40 85.0
condition 18 28 64.2
subroutine 14 14 100.0
pod 0 3 0.0
total 155 174 89.0


line stmt bran cond sub pod time code
1             package Exporter::Renaming;
2              
3 1     1   2937 use 5.008;
  1         3  
  1         56  
4 1     1   224 use strict;
  1         3  
  1         40  
5 1     1   24 use warnings;
  1         1  
  1         33  
6 1     1   6 use Carp;
  1         2  
  1         165  
7              
8             our $VERSION = 1.19;
9              
10             my $renaming_on; # are we active?
11             my $exporter_import; # holds coderef to original Exporter behavior, if defined
12             my $exporter_to_level; # same for Export::Heavy::heavy_export_to_level
13              
14             # switch on renaming behavior of Exporter
15             sub import {
16 4 100   4   2421 return if $renaming_on; # never do this twice
17 2         12 require Exporter;
18 2         10 require Exporter::Heavy;
19 2         5 $exporter_import = \ &Exporter::import; # alias for original
20 2         4 $exporter_to_level = \ &Exporter::Heavy::heavy_export_to_level;
21 1     1   6 no warnings 'redefine';
  1         1  
  1         166  
22 2         78 *Exporter::import = \ &renaming_import; # renaming behavior
23 2         10 *Exporter::Heavy::heavy_export_to_level = \ &renaming_to_level;
24 2         15 $renaming_on = 1;
25             }
26              
27             # restore Exporter's original behavior
28             sub unimport {
29 1 50   1   254 return unless $renaming_on;
30 1     1   5 no warnings 'redefine';
  1         2  
  1         2142  
31 1         26 *Exporter::import = $exporter_import; # normal behavior
32 1         4 *Exporter::Heavy::heavy_export_to_level = $exporter_to_level;
33 1         3 $renaming_on = 0; # allow import again
34             }
35              
36             # This is the import routine we supplant into Exporter. It interprets
37             # a renaming package, if any, then resumes normal import through
38             # "goto &$exporter_import". This is this sub's way of returning
39             sub renaming_import {
40             # be as inconspicious as possible
41 16 50   16 0 18108 goto $exporter_import unless $renaming_on;
42 16         34 my ($from_module, $key, $renamings, @normal) = @_;
43             # check if we are needed at all
44 16 100 66     425 goto $exporter_import unless
      66        
45             $key and $key eq 'Renaming' and ref $renamings eq 'ARRAY';
46              
47 15         30 my $to_module = caller;
48 15         32 process_renaming($from_module, $to_module, $renamings);
49              
50             # do any remaining straight imports
51 8 100       27 return unless @normal;
52 1         3 @_ = ($from_module, @normal);
53 1         24 goto $exporter_import;
54             }
55              
56             # replacement for Exporter::Heavy::heavy_export_to_level
57             sub renaming_to_level {
58 1 50   1 0 2087 goto $exporter_to_level unless $renaming_on;
59 1         4 my $pkg = shift;
60 1         2 my $level = shift;
61 1         3 (undef) = shift; # XXX redundant arg
62 1         7 my $callpkg = caller($level);
63 1         3 my ($key, $renamings, @normal) = @_;
64 1 50 33     15 return $pkg->export($callpkg, @_) unless
      33        
65             $key and $key eq 'Renaming' and ref $renamings eq 'ARRAY';
66 1         5 process_renaming($pkg, $callpkg, $renamings);
67 1 50       52 $pkg->export($callpkg, @normal) if @normal;
68             }
69              
70             sub process_renaming {
71 16     16 0 31 my ($from, $to, $renamings) = @_;
72 16         29 my %table;
73             # build renaming table, basically as %table = reverse @$renamings,
74             # but do error checking and type (sigil) propagation
75 16 100       162 croak( "Odd number of renaming elements") if @$renamings % 2;
76 15         39 while ( @$renamings ) {
77 21         44 my ( $old_sym, $new_sym) = ( shift @$renamings, shift @$renamings);
78 21   66     55 $new_sym ||= $old_sym; # default to straight import
79 21         36 my ( $old_type, $old_name) = _get_type( $old_sym);
80 21         39 my ( $new_type, $new_name) = _get_type( $new_sym);
81             # check type and name
82 21 100       179 croak( "Invalid type character in '$old_sym'") unless
83             defined $old_type;
84 20 100       170 croak( "Invalid type character in '$new_sym'") unless
85             defined $new_type;
86             # Check if $new_name is valid ($old_name will be checked by
87             # standard Exporter)
88 19 100       280 croak( "Invalid name in '$new_sym'") unless
89             $new_name =~ /^[A-Za-z_]\w*$/;
90             # type propagation
91 18   100     89 my $type = $old_type || $new_type || '&';
92 18   66     54 $old_type ||= $type;
93 18   66     44 $new_type ||= $type;
94 18 100       175 croak( "Different types: old '$old_sym', new '$new_sym'") if
95             $old_type ne $new_type;
96 17         20 $new_sym = "$type$new_name";
97 17         23 $old_sym = "$type$old_name";
98             # Check table for multiple entries
99 17 100       335 croak( "Multiple renamings to '$new_sym'") if exists $table{ $new_sym};
100 16         72 $table{ $new_sym} = $old_sym;
101             }
102              
103             # Jump through Exporter's hoops for all original symbols
104             {
105 10         16 package Exporter::Renaming::Inter; # name space for importing
106              
107             # We want Exporter's messages passed on to our user
108 10         24 our @CARP_NOT = qw(Exporter Exporter::Renaming);
109             # "values %table" may list some symbols more than once, but Exporter
110             # sorts that out.
111 10         1380 $exporter_import->($from, values %table); # original names
112             }
113              
114             # If we are here, all imports are ok (under the original names)
115             # now alias symbols into user space according to table
116 9         39 while ( my ( $new, $old) = each %table ) {
117 14         24 ( my( $type), $new) = _get_type( $new);
118 14         27 ( undef, $old) = _get_type( $old);
119 14         68 _sym_alias( $type, "${from}::$old", "${to}::$new");
120             }
121             }
122              
123             # split off type character
124             sub _get_type {
125 70     70   111 local $_ = shift;
126 70         852 my ( $type, $name) = /(\W?)(.*)/;
127 70 100 100     275 return if $type and $type !~ /[\$@%&*]/; # reject invalid type chars
128 68         177 ( $type, $name);
129             }
130              
131             # create alias of any type (the only substantial copy of code from Exporter)
132             sub _sym_alias {
133 14     14   23 my ( $type, $old, $new) = @_;
134 14   50     92 $type ||= '&';
135 1     1   9 no strict 'refs';
  1         9  
  1         178  
136 14         94 *{$new} =
  4         11  
137 1         4 $type eq '$' ? \ ${ $old} :
138 1         3 $type eq '@' ? \ @{ $old} :
139 7         19 $type eq '%' ? \ %{ $old} :
140 1         4 $type eq '&' ? \ &{ $old} :
141 14 50       57 $type eq '*' ? \ *{ $old} :
    100          
    100          
    100          
    100          
142             undef;
143             ;
144             }
145              
146             1;
147             __END__