File Coverage

blib/lib/Perl/Stripper.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Perl::Stripper;
2              
3             our $DATE = '2015-01-03'; # DATE
4             our $VERSION = '0.08'; # VERSION
5              
6 1     1   13456 use 5.010001;
  1         2  
  1         35  
7 1     1   436 use Log::Any qw($log);
  1         1388  
  1         4  
8              
9 1     1   982 use PPI;
  0            
  0            
10             use Moo;
11             use experimental 'smartmatch';
12              
13             has maintain_linum => (is => 'rw', default => sub { 1 });
14             has strip_comment => (is => 'rw', default => sub { 1 });
15             has strip_pod => (is => 'rw', default => sub { 1 });
16             has strip_ws => (is => 'rw', default => sub { 1 });
17             has strip_log => (is => 'rw', default => sub { 0 });
18             has stripped_log_levels => (is => 'rw', default => sub { [qw/debug trace/] });
19              
20             sub _strip_el_content {
21             my ($self, $el) = @_;
22              
23             my $ct;
24             if ($self->maintain_linum) {
25             $ct = $el->content;
26             my $num_nl = () = $ct =~ /\R/g;
27             $ct = "\n" x $num_nl;
28             } else {
29             $ct = "";
30             }
31             $el->set_content($ct);
32             }
33              
34             sub _strip_node_content {
35             my ($self, $node) = @_;
36              
37             my $ct;
38             if ($self->maintain_linum) {
39             $ct = $node->content;
40             my $num_nl = () = $ct =~ /\R/g;
41             $ct = "\n" x $num_nl;
42             } else {
43             $ct = "";
44             }
45             $node->prune(sub{1});
46             $node->add_element(PPI::Token::Whitespace->new($ct)) if $ct;
47             }
48              
49             sub strip {
50             my ($self, $perl) = @_;
51              
52             my @ll = @{ $self->stripped_log_levels };
53             my @llf = map {$_."f"} @ll;
54             my @isll = map {"is_$_"} @ll;
55              
56             my $doc = PPI::Document->new(\$perl);
57             my $res = $doc->find(
58             sub {
59             my ($top, $el) = @_;
60              
61             if ($self->strip_comment && $el->isa('PPI::Token::Comment')) {
62             # don't strip shebang line
63             if ($el->content =~ /^#!/) {
64             my $loc = $el->location;
65             return if $loc->[0] == 1 && $loc->[1] == 1;
66             }
67             if (ref($self->strip_comment) eq 'CODE') {
68             $self->strip_comment->($el);
69             } else {
70             $self->_strip_el_content($el);
71             }
72             }
73              
74             if ($self->strip_pod && $el->isa('PPI::Token::Pod')) {
75             if (ref($self->strip_pod) eq 'CODE') {
76             $self->strip_pod->($el);
77             } else {
78             $self->_strip_el_content($el);
79             }
80             }
81              
82             if ($self->strip_log) {
83             my $match;
84             if ($el->isa('PPI::Statement')) {
85             # matching '$log->trace(...);'
86             my $c0 = $el->child(0);
87             if ($c0->content eq '$log') {
88             my $c1 = $c0->snext_sibling;
89             if ($c1->content eq '->') {
90             my $c2 = $c1->snext_sibling;
91             my $c2c = $c2->content;
92             if ($c2c ~~ @ll || $c2c ~~ @llf) {
93             $match++;
94             }
95             }
96             }
97             }
98             if ($el->isa('PPI::Statement::Compound')) {
99             # matching 'if ($log->is_trace) { ... }'
100             my $c0 = $el->child(0);
101             if ($c0->content eq 'if') {
102             my $cond = $c0->snext_sibling;
103             if ($cond->isa('PPI::Structure::Condition')) {
104             my $expr = $cond->child(0);
105             if ($expr->isa('PPI::Statement::Expression')) {
106             my $c0 = $expr->child(0);
107             if ($c0->content eq '$log') {
108             my $c1 = $c0->snext_sibling;
109             if ($c1->content eq '->') {
110             my $c2 = $c1->snext_sibling;
111             my $c2c = $c2->content;
112             if ($c2c ~~ @isll) {
113             $match++;
114             }
115             }
116             }
117             }
118             }
119             }
120             }
121              
122             if ($match) {
123             if (ref($self->strip_log) eq 'CODE') {
124             $self->strip_log->($el);
125             } else {
126             $self->_strip_node_content($el);
127             }
128             }
129             }
130              
131             0;
132             }
133             );
134             die "BUG: find() dies: $@!" unless defined($res);
135              
136             $doc->serialize;
137             }
138              
139             1;
140             # ABSTRACT: Yet another PPI-based Perl source code stripper
141              
142             __END__