File Coverage

blib/lib/Perl/Stripper.pm
Criterion Covered Total %
statement 81 86 94.1
branch 34 48 70.8
condition 8 12 66.6
subroutine 10 10 100.0
pod 1 1 100.0
total 134 157 85.3


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