line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
15
|
|
|
15
|
|
2259992
|
use strict; |
|
15
|
|
|
|
|
38
|
|
|
15
|
|
|
|
|
667
|
|
2
|
15
|
|
|
15
|
|
93
|
use warnings; |
|
15
|
|
|
|
|
32
|
|
|
15
|
|
|
|
|
2434
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
my $pkg2file = sub { |
5
|
|
|
|
|
|
|
my ($pkg) = shift; |
6
|
|
|
|
|
|
|
$pkg =~ s@::@/@g; |
7
|
|
|
|
|
|
|
$pkg .= '.pm'; |
8
|
|
|
|
|
|
|
return $pkg; |
9
|
|
|
|
|
|
|
}; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
package filtered; # for Pod::Weaver |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# ABSTRACT: Apply source filter on external module |
14
|
|
|
|
|
|
|
our $VERSION = 'v0.0.7'; # VERSION |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
package filtered::hook; ## no critic (RequireFilenameMatchesPackage) |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our $VERSION = 'v0.0.7'; # VERSION |
19
|
|
|
|
|
|
|
|
20
|
15
|
|
|
15
|
|
90
|
use File::Path; |
|
15
|
|
|
|
|
41
|
|
|
15
|
|
|
|
|
1126
|
|
21
|
15
|
|
|
15
|
|
94
|
use File::Basename; |
|
15
|
|
|
|
|
35
|
|
|
15
|
|
|
|
|
20029
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my %MYINC; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub new |
26
|
|
|
|
|
|
|
{ |
27
|
51
|
|
|
51
|
|
173
|
my ($self, %arg) = @_; |
28
|
51
|
|
33
|
|
|
516
|
my $class = ref($self) || $self; |
29
|
51
|
|
|
|
|
439
|
return bless { |
30
|
|
|
|
|
|
|
_FILTER => $arg{FILTER}, |
31
|
|
|
|
|
|
|
}, $class; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# NOTE: To store data in object is probably not good idea because this prohibits re-entrance. |
35
|
|
|
|
|
|
|
sub init |
36
|
|
|
|
|
|
|
{ |
37
|
114
|
|
|
114
|
|
291
|
my ($self, $target, $as, $with, $ppi, $prev) = @_; |
38
|
|
|
|
|
|
|
|
39
|
114
|
|
|
|
|
433
|
$self->{_TARGET} = $target; |
40
|
114
|
|
|
|
|
221
|
$self->{_AS} = $as; |
41
|
114
|
|
|
|
|
219
|
$self->{_WITH} = $with; |
42
|
114
|
|
|
|
|
329
|
$self->{_PPI} = $ppi; |
43
|
114
|
|
|
|
|
359
|
$self->{_PREV} = $prev; |
44
|
114
|
|
|
|
|
442
|
return $self; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub _filter_by_ppi |
48
|
|
|
|
|
|
|
{ |
49
|
38
|
|
|
38
|
|
78
|
my ($self, $ref) = @_; |
50
|
|
|
|
|
|
|
|
51
|
38
|
|
|
|
|
7030
|
require PPI::Transform::PackageName; |
52
|
|
|
|
|
|
|
my $trans = PPI::Transform::PackageName->new( |
53
|
740
|
|
|
740
|
|
4840
|
-all => sub { s/^$self->{_TARGET}\b/$self->{_AS}/ } |
54
|
38
|
|
|
|
|
656
|
); |
55
|
38
|
|
|
|
|
464
|
$trans->apply($ref); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub filtered::hook::INC |
59
|
|
|
|
|
|
|
{ |
60
|
114
|
|
|
114
|
|
302
|
my ($self, $filename) = @_; |
61
|
114
|
50
|
|
|
|
360
|
if($pkg2file->($self->{_TARGET}) ne $filename) { |
62
|
0
|
|
|
|
|
0
|
warn "Unexpected loading of $filename against $self->{_TARGET}"; |
63
|
0
|
|
|
|
|
0
|
return; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
114
|
|
|
|
|
371
|
$self->{_FILENAME} = $filename; |
67
|
114
|
|
|
|
|
171
|
shift @INC; # TODO: Gain robustness # NOTE: Just one time application |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
#print "SELF: $self / FILTER: $self->{_FILTER} / AS: $self->{_AS} / FILENAME: $filename\n"; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# NOTE: The following part is based on perldoc -f require |
72
|
114
|
100
|
|
|
|
545
|
if (exists $MYINC{$self}{$filename}) { |
73
|
|
|
|
|
|
|
# return 1 in original require |
74
|
|
|
|
|
|
|
return (sub { |
75
|
48
|
100
|
|
48
|
|
138
|
if($_[1]) { |
76
|
24
|
|
|
|
|
58
|
delete $INC{$filename}; |
77
|
24
|
100
|
|
|
|
120
|
$INC{$filename} = $self->{_PREV}[1] if($self->{_PREV}[0]); |
78
|
24
|
|
|
|
|
43
|
$_ = "1;\n"; |
79
|
24
|
|
|
|
|
45
|
$_[1] = 0; |
80
|
24
|
|
|
|
|
179
|
return 1; |
81
|
|
|
|
|
|
|
} else { |
82
|
24
|
|
|
|
|
434
|
return 0; |
83
|
|
|
|
|
|
|
} |
84
|
24
|
50
|
|
|
|
1495
|
}, 1) if $MYINC{$self}{$filename}; |
85
|
0
|
|
|
|
|
0
|
die "Compilation failed in require"; |
86
|
|
|
|
|
|
|
} |
87
|
90
|
|
|
|
|
131
|
my ($realfilename,$result); |
88
|
|
|
|
|
|
|
ITER: { |
89
|
90
|
|
|
|
|
117
|
foreach my $prefix (@INC) { |
|
90
|
|
|
|
|
205
|
|
90
|
171
|
|
|
|
|
477
|
$realfilename = "$prefix/$filename"; |
91
|
171
|
100
|
|
|
|
5796
|
if (-f $realfilename) { |
92
|
81
|
|
|
|
|
322
|
$MYINC{$self}{$filename} = $realfilename; |
93
|
81
|
|
|
|
|
222
|
last ITER; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
} |
96
|
9
|
|
|
|
|
162
|
die "Can't find $filename in \@INC"; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
81
|
|
|
|
|
122
|
my ($qr1, $qr2); |
100
|
81
|
|
|
|
|
4055
|
open my $fh, '<', $realfilename; |
101
|
81
|
100
|
|
|
|
324
|
if(defined $self->{_AS}) { |
102
|
57
|
100
|
|
|
|
190
|
if($self->{_PPI}) { |
103
|
38
|
|
|
|
|
178
|
local $/; |
104
|
38
|
|
|
|
|
1083
|
my $content = <$fh>; |
105
|
38
|
|
|
|
|
486
|
close $fh; |
106
|
38
|
|
|
|
|
150
|
undef $fh; |
107
|
38
|
|
|
|
|
239
|
$self->_filter_by_ppi(\$content); |
108
|
10
|
|
|
10
|
|
121
|
open $fh, '<', \$content; |
|
10
|
|
|
|
|
23
|
|
|
10
|
|
|
|
|
98
|
|
|
38
|
|
|
|
|
87876
|
|
109
|
|
|
|
|
|
|
} else { |
110
|
19
|
|
|
|
|
355
|
$qr1 = qr/\b(package\s+)$self->{_TARGET}\b/; |
111
|
19
|
|
|
|
|
195
|
$qr2 = qr/\b$self->{_TARGET}::\b/; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
return (sub { |
115
|
1686
|
|
|
1686
|
|
570397
|
my ($sub, $state) = @_; |
116
|
1686
|
100
|
100
|
|
|
10420
|
if($state == 1) { # Inject filter at the beginning |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
117
|
81
|
|
|
|
|
205
|
delete $INC{$filename}; |
118
|
81
|
100
|
|
|
|
472
|
$INC{$filename} = $self->{_PREV}[1] if($self->{_PREV}[0]); |
119
|
81
|
|
|
|
|
311
|
$_ = 'use '.$self->{_FILTER}; |
120
|
81
|
100
|
|
|
|
285
|
if(defined $self->{_WITH}) { |
121
|
12
|
|
|
|
|
206
|
$_ .= ' '.$self->{_WITH}; |
122
|
|
|
|
|
|
|
} |
123
|
81
|
100
|
|
|
|
459
|
if(exists $ENV{FILTERED_ROOT}) { |
124
|
15
|
50
|
|
|
|
27
|
if(eval { require Filter::tee; }) { |
|
15
|
|
|
|
|
149
|
|
125
|
15
|
|
|
|
|
27
|
my $asfile; |
126
|
15
|
100
|
|
|
|
49
|
if(defined($self->{_AS})) { |
127
|
12
|
|
|
|
|
27
|
$asfile = $self->{_AS}; |
128
|
12
|
|
|
|
|
34
|
$asfile =~ s@::@/@g; |
129
|
12
|
|
|
|
|
28
|
$asfile .= '.pm'; |
130
|
|
|
|
|
|
|
} else { |
131
|
3
|
|
|
|
|
8
|
$asfile = $filename; |
132
|
|
|
|
|
|
|
} |
133
|
15
|
|
|
|
|
897
|
my $dir = dirname($ENV{FILTERED_ROOT}.'/'.$asfile); |
134
|
15
|
100
|
|
|
|
1498
|
File::Path::make_path($dir) if ! -d $dir; |
135
|
15
|
|
|
|
|
93
|
$_ .= "; use Filter::tee '".$ENV{FILTERED_ROOT}.'/'.$asfile."'"; |
136
|
|
|
|
|
|
|
} else { |
137
|
0
|
|
|
|
|
0
|
warn 'Ignore environment variable FILTERED_ROOT because Filter::tee is not available'; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
} |
140
|
81
|
|
|
|
|
197
|
$_ .= ";\n"; |
141
|
81
|
|
|
|
|
156
|
$_[1] = 0; |
142
|
|
|
|
|
|
|
} elsif(eof($fh)) { |
143
|
72
|
|
|
|
|
559
|
close $fh; |
144
|
72
|
|
|
|
|
1420
|
return 0; |
145
|
|
|
|
|
|
|
} elsif(defined $self->{_AS} && ! $self->{_PPI}) { |
146
|
441
|
|
|
|
|
868
|
$_ = <$fh>; |
147
|
441
|
|
|
|
|
1555
|
s {$qr1} {${1}$self->{_AS}}; |
148
|
441
|
|
|
|
|
1415
|
s {$qr2} {$self->{_AS}::}; |
149
|
|
|
|
|
|
|
} else { |
150
|
1092
|
|
|
|
|
2045
|
$_ = <$fh>; |
151
|
|
|
|
|
|
|
} |
152
|
1614
|
|
|
|
|
23842
|
return 1; |
153
|
81
|
|
|
|
|
34663
|
}, 1); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
package filtered; |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
|
159
|
15
|
|
|
15
|
|
185
|
use Carp; |
|
15
|
|
|
|
|
34
|
|
|
15
|
|
|
|
|
1482
|
|
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
my %hook; |
162
|
|
|
|
|
|
|
my $USE_PPI; |
163
|
15
|
|
|
15
|
|
48
|
BEGIN { $USE_PPI = eval { require PPI; }; } |
|
15
|
|
|
|
|
6238
|
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub import |
166
|
|
|
|
|
|
|
{ |
167
|
114
|
|
|
114
|
|
152287
|
my ($class, @args) = @_; |
168
|
114
|
|
|
|
|
206
|
my ($filter, $target, $as, $with); |
169
|
114
|
|
|
|
|
238
|
my $ppi = $USE_PPI; |
170
|
114
|
|
|
|
|
167
|
while(1) { |
171
|
466
|
100
|
|
|
|
1166
|
last unless @args; |
172
|
409
|
100
|
|
|
|
1712
|
if($args[0] eq 'by') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
173
|
114
|
|
|
|
|
189
|
shift @args; |
174
|
114
|
|
|
|
|
230
|
$filter = shift @args; |
175
|
|
|
|
|
|
|
} elsif($args[0] eq 'as') { |
176
|
81
|
|
|
|
|
121
|
shift @args; |
177
|
81
|
|
|
|
|
160
|
$as = shift @args; |
178
|
|
|
|
|
|
|
} elsif($args[0] eq 'with') { |
179
|
12
|
|
|
|
|
30
|
shift @args; |
180
|
12
|
|
|
|
|
184
|
$with = shift @args; |
181
|
|
|
|
|
|
|
} elsif($args[0] eq 'use_ppi') { |
182
|
76
|
|
|
|
|
108
|
shift @args; |
183
|
76
|
|
|
|
|
149
|
$ppi = shift @args; |
184
|
|
|
|
|
|
|
} elsif($args[0] eq 'on') { |
185
|
69
|
|
|
|
|
94
|
shift @args; |
186
|
69
|
|
|
|
|
125
|
$target = shift @args; |
187
|
|
|
|
|
|
|
} else { |
188
|
57
|
100
|
|
|
|
198
|
$target = shift @args unless defined $target; |
189
|
57
|
|
|
|
|
108
|
last; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
114
|
50
|
|
|
|
321
|
croak '`by\' must be specified' if ! defined($filter); |
194
|
114
|
50
|
|
|
|
327
|
croak '`on\' or target name must be specified' if ! defined($target); |
195
|
114
|
100
|
|
|
|
641
|
$hook{$filter} = filtered::hook->new(FILTER => $filter) if ! exists $hook{$filter}; |
196
|
114
|
100
|
|
|
|
363
|
my $prev = [exists($INC{$pkg2file->($target)}), (exists($INC{$pkg2file->($target)}) ? $INC{$pkg2file->($target)} : '')]; |
197
|
114
|
|
|
|
|
1262
|
unshift @INC, $hook{$filter}->init($target, $as, $with, $ppi, $prev); |
198
|
114
|
|
|
|
|
382
|
delete $INC{$pkg2file->($target)}; |
199
|
114
|
100
|
|
|
|
26799
|
if(!defined eval "require $target") { |
200
|
18
|
|
|
|
|
4391
|
delete $INC{$hook{$filter}{_FILENAME}}; # For error in internal require; |
201
|
18
|
100
|
|
|
|
80
|
$INC{$hook{$filter}{_FILENAME}} = $prev->[1] if $prev->[0]; |
202
|
18
|
|
|
|
|
487
|
croak "Can't load $target by $@"; |
203
|
|
|
|
|
|
|
} |
204
|
96
|
100
|
|
|
|
18703
|
if(defined $as) { |
205
|
81
|
|
|
|
|
333
|
@_ = ($as, @args); |
206
|
|
|
|
|
|
|
} else { |
207
|
15
|
|
|
|
|
59
|
@_ = ($target, @args); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
{ |
210
|
15
|
|
|
15
|
|
78
|
no strict 'refs'; ## no critic (ProhibitNoStrict) |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
612
|
|
|
96
|
|
|
|
|
221
|
|
211
|
15
|
|
|
15
|
|
91
|
no warnings 'once'; |
|
15
|
|
|
|
|
25
|
|
|
15
|
|
|
|
|
4342
|
|
212
|
96
|
|
|
|
|
1287
|
my $import = $_[0]->can('import'); |
213
|
96
|
50
|
|
|
|
286
|
if(defined $import) { |
|
|
0
|
|
|
|
|
|
214
|
96
|
|
|
|
|
4645
|
goto &$import; |
215
|
|
|
|
|
|
|
} elsif ($_[0]->isa('Exporter')) { |
216
|
0
|
|
|
|
|
|
$_[0]->export_to_level(1, @_); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
1; |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
__END__ |