File Coverage

lib/Perlmazing/Engine/Exporter.pm
Criterion Covered Total %
statement 85 125 68.0
branch 19 54 35.1
condition 1 3 33.3
subroutine 10 10 100.0
pod 0 1 0.0
total 115 193 59.5


line stmt bran cond sub pod time code
1             package Perlmazing::Engine::Exporter;
2 34     34   352 use strict;
  34         72  
  34         1526  
3 34     34   171 use warnings;
  34         2078  
  34         2553  
4 34     34   192 use Carp;
  34         83  
  34         5249  
5             our $VERSION = '1.2810';
6             my $package = __PACKAGE__;
7             my $imports;
8             my $exports;
9              
10             sub import {
11 1546     1546   2909 my $self = shift;
12 1546         19317 my @call = caller 0;
13 1546         3266 my $pack = $call[0];
14 34     34   212 no strict 'refs';
  34         53  
  34         12826  
15 1546 100       4051 if ($self eq $package) {
16 34         58 my $in_isa = grep { /^\Q$package\E$/ } @{"${pack}::ISA"};
  0         0  
  34         227  
17 34 50       180 unshift (@{"${pack}::ISA"}, __PACKAGE__) unless $in_isa;
  34         2010  
18             } else {
19 1512 50       13112 if (my @call = caller 1) {
20 1512 50       4468 $pack = $call[0] if $call[3] eq "${self}::import";
21             }
22 1512 50       5730 return if $imports->{$pack}->{$self};
23 1512         2257 my @export = (@_, @{"${self}::EXPORT"});
  1512         8294  
24 1512         4437 @export = $self->_expand_names(@export);
25 1512         3429 my $no = {map {$_ => 1} grep {$_ =~ /^!/} @export};
  14         22  
  16849         28121  
26 1512         2625 my @yes = grep {!$no->{"!$_"}} grep {$_ !~ /^!/} @export;
  16835         30998  
  16849         25442  
27 1512         2804 for my $i (@yes) {
28 16822         35150 $package->export($self, $i, $pack);
29             }
30 1512         278984 $imports->{$pack}->{$self}++;
31             }
32             }
33              
34             sub _expand_names {
35 1517     1517   2276 my $self = shift;
36 1517         2080 my @expanded;
37 34     34   278 no strict 'refs';
  34         59  
  34         24947  
38 1517         2876 for my $i (@_) {
39 16854         23336 my $no = $i =~ s/^!//;
40 16854 100       34182 my $neg = $no ? '!' : '';
41 16854 100       24231 if ($i =~ /^:(\w+)$/) {
42 5         8 my $name = $1;
43 5 50       6 croak "Package $self doesn't define tag '$name' in \%EXPORT_TAGS" unless exists ${"${self}::EXPORT_TAGS"}{$name};
  5         16  
44 5 0       8 push @expanded, map {($_ =~ s/^!//) ? ($no ? $_ : "$neg$_") : "$neg$_"} $self->_expand_names(@{${"${self}::EXPORT_TAGS"}{$name}});
  82 50       137  
  5         5  
  5         19  
45             } else {
46 16849         32529 push @expanded, "$neg$i";
47             }
48             }
49 1517         2539 my $seen;
50             my @final;
51 1517         2286 for my $i (@expanded) {
52 16931         26224 push @final, $i;
53 16931         31801 $seen->{$i}++;
54             }
55 1517         2239 my $found_symbols = {map {$_ => 1} @{"${self}::found_symbols"}};
  182040         302228  
  1517         6958  
56 1517         16502 for my $i (@final) {
57 16931         24452 (my $name = $i) =~ s/^!//;
58 16931 0 33     18729 croak "Unknown symbol '$name' from package '$self'" unless defined(&{"${self}::$name"}) or exists $found_symbols->{$name};
  16931         46325  
59             }
60 1517         30241 @final;
61             }
62              
63             sub export {
64 16822     16822 0 21025 my $self = shift;
65 16822         28838 my ($from, $symbol, $to) = (shift, shift, shift);
66 16822         20527 my $sigil = '&';
67 16822         28801 $symbol =~ s/^(:|\&|\$|\%|\@|\*)/$sigil = $1; ''/e;
  0         0  
  0         0  
68 16822 50       34024 croak "Unknown symbol type for expression '$symbol' in EXPORT" if $symbol =~ /^\W/;
69 34     34   263 no strict 'refs';
  34         88  
  34         1318  
70 34     34   160 no warnings 'once';
  34         58  
  34         19839  
71 16822 50       32963 if ($sigil eq ':') {
    50          
    0          
    0          
    0          
    0          
72 0         0 my $tags = \%{"${from}::EXPORT_TAGS"};
  0         0  
73 0 0       0 if (not exists $tags->{$symbol}) {
74 0         0 croak "Export tag '$symbol' is not defined in package $from";
75             }
76 0 0       0 unless (ref($tags->{$symbol}) eq 'ARRAY') {
77 0         0 croak "Export tags should contain array refs";
78             }
79 0         0 for my $i (@{$tags->{$symbol}}) {
  0         0  
80 0         0 $self->export($from, $i, $to);
81             }
82             } elsif ($sigil eq '&') {
83 16822 50       18461 if (not defined *{"${from}::$symbol"}{CODE}) {
  16822         45876  
84 0         0 eval "sub ${from}::$symbol"; ## no critic
85 0 0       0 croak "Cannot create symbol for sub ${from}::$symbol: $@" if $@;
86             }
87 16822 100       35300 if (not $exports->{$to}->{$symbol}) {
88 16754 50       18828 if (defined *{"${to}::$symbol"}{CODE}) {
  16754         69899  
89 0         0 croak "Cannot define symbol &${to}::$symbol: symbol is already defined under the same namespace and name";
90             } else {
91 16754         19760 *{"${to}::$symbol"} = *{"${from}::$symbol"}{CODE};
  16754         38122  
  16754         29562  
92 16754         41679 $exports->{$to}->{$symbol}++;
93             }
94             }
95             } elsif ($sigil eq '$') {
96 0 0         if (not defined *{"${from}::$symbol"}{SCALAR}) {
  0            
97 0           ${"${from}::$symbol"} = undef;
  0            
98             }
99 0           *{"${to}::$symbol"} = *{"${from}::$symbol"}{SCALAR};
  0            
  0            
100             } elsif ($sigil eq '@') {
101 0 0         if (not defined *{"${from}::$symbol"}{ARRAY}) {
  0            
102 0           @{"${from}::$symbol"} = ();
  0            
103             }
104 0           *{"${to}::$symbol"} = *{"${from}::$symbol"}{ARRAY};
  0            
  0            
105             } elsif ($sigil eq '%') {
106 0 0         if (not defined *{"${from}::$symbol"}{HASH}) {
  0            
107 0           %{"${from}::$symbol"} = ();
  0            
108             }
109 0           *{"${to}::$symbol"} = *{"${from}::$symbol"}{HASH};
  0            
  0            
110             } elsif ($sigil eq '*') {
111 0           *{"${to}::$symbol"} = *{"${from}::$symbol"};
  0            
  0            
112             } else {
113 0           croak "I don't know how to handle '$symbol' in EXPORT";
114             }
115             }
116              
117             1;