File Coverage

blib/lib/Perl/Stripper.pm
Criterion Covered Total %
statement 88 93 94.6
branch 40 54 74.0
condition 8 12 66.6
subroutine 10 10 100.0
pod 1 1 100.0
total 147 170 86.4


line stmt bran cond sub pod time code
1             package Perl::Stripper;
2              
3             our $DATE = '2017-07-11'; # DATE
4             our $VERSION = '0.10'; # VERSION
5              
6 1     1   18778 use 5.010001;
  1         6  
7 1     1   4722 use Log::ger;
  1         128  
  1         9  
8              
9 1     1   2432 use PPI;
  1         164965  
  1         54  
10 1     1   846 use Moo;
  1         16519  
  1         8  
11 1     1   2517 use experimental 'smartmatch';
  1         4458  
  1         7  
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 12     12   28 my ($self, $el) = @_;
22              
23 12         24 my $ct;
24 12 50       36 if ($self->maintain_linum) {
25 12         39 $ct = $el->content;
26 12         106 my $num_nl = () = $ct =~ /\R/g;
27 12         41 $ct = "\n" x $num_nl;
28             } else {
29 0         0 $ct = "";
30             }
31 12         53 $el->set_content($ct);
32             }
33              
34             sub _strip_node_content {
35 5     5   14 my ($self, $node) = @_;
36              
37 5         14 my $ct;
38 5 50       18 if ($self->maintain_linum) {
39 5         18 $ct = $node->content;
40 5         635 my $num_nl = () = $ct =~ /\R/g;
41 5         19 $ct = "\n" x $num_nl;
42             } else {
43 0         0 $ct = "";
44             }
45 5     25   41 $node->prune(sub{1});
  25         1950  
46 5 100       797 $node->add_element(PPI::Token::Whitespace->new($ct)) if $ct;
47             }
48              
49             sub strip {
50 2     2 1 268 my ($self, $perl) = @_;
51              
52 2         6 my @ll = @{ $self->stripped_log_levels };
  2         14  
53 2         9 my @llf = map {$_."f"} @ll;
  4         17  
54 2         8 my @isll = map {"is_$_"} @ll;
  4         13  
55              
56 2         24 my $doc = PPI::Document->new(\$perl);
57             my $res = $doc->find(
58             sub {
59 393     393   5406 my ($top, $el) = @_;
60              
61 393 100 66     2415 if ($self->strip_comment && $el->isa('PPI::Token::Comment')) {
62             # don't strip shebang line
63 12 100       42 if ($el->content =~ /^#!/) {
64 2         35 my $loc = $el->location;
65 2 50 33     16882 return if $loc->[0] == 1 && $loc->[1] == 1;
66             }
67 10 50       80 if (ref($self->strip_comment) eq 'CODE') {
68 0         0 $self->strip_comment->($el);
69             } else {
70 10         30 $self->_strip_el_content($el);
71             }
72             }
73              
74 391 100 66     2335 if ($self->strip_pod && $el->isa('PPI::Token::Pod')) {
75 2 50       10 if (ref($self->strip_pod) eq 'CODE') {
76 0         0 $self->strip_pod->($el);
77             } else {
78 2         8 $self->_strip_el_content($el);
79             }
80             }
81              
82 391 100       1165 if ($self->strip_log) {
83 148         267 my $match;
84 148 100       545 if ($el->isa('PPI::Statement')) {
85             # matching '$log->trace(...);'
86 20         88 my $c0 = $el->child(0);
87 20 100       192 if ($c0->content eq '$log') {
88 3         51 my $c1 = $c0->snext_sibling;
89 3 50       210 if ($c1->content eq '->') {
90 3         33 my $c2 = $c1->snext_sibling;
91 3         132 my $c2c = $c2->content;
92 3 100 100     39 if ($c2c ~~ @ll || $c2c ~~ @llf) {
93 2         6 $match++;
94             }
95             }
96             }
97             }
98 148 100       630 if ($el->isa('PPI::Statement')) {
99             # matching 'log_trace(...);'
100 20         62 my $c0 = $el->child(0);
101 20 100       160 if (grep { $c0->content eq "log_$_" } @ll) {
  40         177  
102 1         10 $match++;
103             }
104             }
105 148 100       652 if ($el->isa('PPI::Statement::Compound')) {
106             # matching 'if ($log->is_trace) { ... }' or 'if (log_is_trace()) { ... }'
107 2         7 my $c0 = $el->child(0);
108 2 50       19 if ($c0->content eq 'if') {
109 2         20 my $cond = $c0->snext_sibling;
110 2 50       87 if ($cond->isa('PPI::Structure::Condition')) {
111 2         11 my $expr = $cond->child(0);
112 2 50       32 if ($expr->isa('PPI::Statement::Expression')) {
113 2         8 my $c0 = $expr->child(0);
114 2 100       18 if ($c0->content eq '$log') {
    50          
115 1         10 my $c1 = $c0->snext_sibling;
116 1 50       35 if ($c1->content eq '->') {
117 1         9 my $c2 = $c1->snext_sibling;
118 1         41 my $c2c = $c2->content;
119 1 50       10 if ($c2c ~~ @isll) {
120 1         3 $match++;
121             }
122             }
123 2         16 } elsif (grep {$c0->content eq "log_is_$_"} @ll) {
124 1         10 $match++;
125             }
126             }
127             }
128             }
129             }
130              
131 148 100       411 if ($match) {
132 5 50       23 if (ref($self->strip_log) eq 'CODE') {
133 0         0 $self->strip_log->($el);
134             } else {
135 5         17 $self->_strip_node_content($el);
136             }
137             }
138             }
139              
140 391         1062 0;
141             }
142 2         77278 );
143 2 50       79 die "BUG: find() dies: $@!" unless defined($res);
144              
145 2         33 $doc->serialize;
146             }
147              
148             1;
149             # ABSTRACT: Yet another PPI-based Perl source code stripper
150              
151             __END__