File Coverage

blib/lib/Perl/Critic/Pulp/PodParser.pm
Criterion Covered Total %
statement 66 67 98.5
branch 12 14 85.7
condition 6 11 54.5
subroutine 16 16 100.0
pod 0 9 0.0
total 100 117 85.4


line stmt bran cond sub pod time code
1             # Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019 Kevin Ryde
2              
3             # This file is part of Perl-Critic-Pulp.
4              
5             # Perl-Critic-Pulp is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Perl-Critic-Pulp is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses/>.
17              
18             package Perl::Critic::Pulp::PodParser;
19 40     40   847 use 5.006;
  40         197  
20 40     40   219 use strict;
  40         71  
  40         891  
21 40     40   211 use warnings;
  40         81  
  40         1169  
22 40     40   6480 use Perl::Critic::Pulp::Utils;
  40         99  
  40         1686  
23 40     40   284 use base 'Pod::Parser';
  40         104  
  40         22115  
24              
25             our $VERSION = 98;
26              
27             # uncomment this to run the ### lines
28             # use Smart::Comments;
29              
30              
31             # sub new {
32             # my $class = shift;
33             # ### Pulp-PodParser new()
34             # my $self = $class->SUPER::new (@_);
35             # return $self;
36             # }
37             sub initialize {
38 322     322 0 816 my ($self) = @_;
39             ### initialize() ...
40              
41             # empty violations for violations() to return before a parse
42 322         831 $self->{'violations'} = [];
43 322         706 $self->{'in_begin'} = '';
44 322         2182 $self->errorsub ('error_handler'); # method name
45              
46             # Note: The violations list is never cleared. Might like to do so at the
47             # start of a new a pod document, though this parser is only ever used on a
48             # single document and then discarded. begin_input() and begin_pod() are
49             # no good as they're invoked for each chunk fed in by parse_from_elem().
50             }
51              
52             sub error_handler {
53 3     3 0 13 my ($self, $errmsg) = @_;
54             ### error_handler() ...
55 3         59 return 1; # error handled
56              
57             # Don't think it's the place of this policy to report pod parse errors.
58             # Maybe within sections a policy is operating on, on the basis that could
59             # affect the goodness of its checks, but better leave it all to podchecker
60             # or other perlcritic policies.
61             #
62             # my $policy = $self->{'policy'};
63             # my $elem = $self->{'elem'};
64             # push @{$self->{'violations'}},
65             # $policy->violation ("Pod::Parser $errmsg", '', $elem);
66             }
67              
68             sub parse_from_elem {
69 322     322 0 668 my ($self, $elem) = @_;
70             ### Pulp-PodParser parse_from_elem(): ref($elem)
71              
72 322   100     1772 my $elems = ($elem->can('find')
73             ? $elem->find ('PPI::Token::Pod')
74             : [ $elem ])
75             || return; # find() returns false if nothing found
76 319         4408 foreach my $pod (@$elems) {
77             ### pod chunk at linenum: $pod->line_number
78 325         1193 $self->{'elem'} = $pod;
79 325         1047 $self->parse_from_string ($pod->content);
80             }
81             }
82              
83             # this is generic except for holding onto $str ready for violation override
84             sub parse_from_string {
85 325     325 0 1775 my ($self, $str) = @_;
86 325         656 $self->{'str'} = $str;
87 325         2083 require IO::String;
88 325         1920 my $fh = IO::String->new ($str);
89 325         29144 $self->parse_from_filehandle ($fh);
90             }
91              
92             sub command {
93 323     323 0 848 my ($self, $command, $text, $linenum) = @_;
94 323 100       1466 if ($command eq 'begin') {
    100          
95 31         64 push @{$self->{'in_begin_stack'}}, $self->{'in_begin'};
  31         216  
96 31 100       187 if ($text =~ /^:/) {
    100          
97             # "=begin :foo" is ordinary POD
98 6         27 $self->{'in_begin'} = '';
99             } elsif ($text =~ /(\w+)/) {
100 24         101 $self->{'in_begin'} = $1; # first word only
101             } else {
102             # "=begin" with no word chars ...
103 1         5 $self->{'in_begin'} = '';
104             }
105             ### in_begin: $self->{'in_begin'}
106              
107             } elsif ($command eq 'end') {
108 21         41 $self->{'in_begin'} = pop @{$self->{'in_begin_stack'}};
  21         67  
109 21 50       88 if (! defined $self->{'in_begin'}) {
110 0         0 $self->{'in_begin'} = '';
111             }
112             ### pop to in_begin: $self->{'in_begin'}
113             }
114             }
115 40     40   344 use constant verbatim => '';
  40         117  
  40         2671  
116 40     40   269 use constant textblock => '';
  40         91  
  40         16161  
117              
118             sub violation_at_linenum {
119 182     182 0 466 my ($self, $message, $linenum) = @_;
120             ### violation on elem: ref($self->{'elem'})
121              
122 182         376 my $policy = $self->{'policy'};
123             ### policy: ref($policy)
124 182         1014 my $violation = $policy->violation ($message, '', $self->{'elem'});
125              
126             # fix dodgy Perl::Critic::Policy 1.108 violation() ending up with caller
127             # package not given $policy
128 182 50 33     39241 if ($violation->policy eq __PACKAGE__
      33        
129             && defined $violation->{'_policy'}
130             && $violation->{'_policy'} eq __PACKAGE__) {
131 182         2136 $violation->{'_policy'} = ref($policy);
132             }
133              
134             Perl::Critic::Pulp::Utils::_violation_override_linenum
135 182         847 ($violation, $self->{'str'}, $linenum);
136             ### $violation
137 182         307 push @{$self->{'violations'}}, $violation;
  182         1789  
138             }
139              
140             sub violation_at_linenum_and_textpos {
141 136     136 0 411 my ($self, $message, $linenum, $text, $pos) = @_;
142             ### violation_at_linenum_and_textpos()
143             ### $message
144             ### $linenum
145             ### $pos
146              
147 136         356 my $part = substr($text,0,$pos);
148 136         327 $linenum += ($part =~ tr/\n//);
149 136         485 $self->violation_at_linenum ($message, $linenum);
150             }
151              
152             # return list of violation objects (possibly empty)
153             sub violations {
154 322     322 0 726 my ($self) = @_;
155 322         542 return @{$self->{'violations'}};
  322         2593  
156             }
157              
158             #------------------------------------------------------------------------------
159             # This not documented yet. Might prefer to split it out for separate use too.
160             #
161             # Not sure about padding to make the column right. Usually good, but
162             # perhaps not always. Maybe should offset a column by examining
163             # $paraobj->cmd_prefix() and $paraobj->cmd_name().
164              
165             {
166             my %command_non_text = (for => 1,
167             begin => 1,
168             end => 1,
169             cut => 1);
170              
171             # The parameters are as per the command() method of Pod::Parser.
172             # If $command contains text style markup then call $self->textblock() on
173             # its text.
174             # All commands except =for, =begin, =end and =cut have marked-up text.
175             # Eg. =head2 C<blah blah>
176             #
177             sub command_as_textblock {
178 203     203 0 510 my ($self, $command, $text, $linenum, $paraobj) = @_;
179             ### command: $command
180             ### $text
181              
182             # $text can be undef if =foo with no newline at end-of-file
183 203 100 66     1113 if (defined $text && ! $command_non_text{$command}) {
184             # padded to make the column number right, the leading spaces do no harm
185             # for this policy
186 179         840 $self->textblock ((' ' x (length($command)+1)) . $text,
187             $linenum,
188             $paraobj);
189             }
190 203         1914 return '';
191             }
192             }
193              
194             1;
195             __END__
196              
197             =for stopwords perlcritic Ryde
198              
199             =head1 NAME
200              
201             Perl::Critic::Pulp::PodParser - shared POD parsing code for the Pulp perlcritic add-on
202              
203             =head1 SYNOPSIS
204              
205             use base 'Perl::Critic::Pulp::PodParser';
206              
207             =head1 DESCRIPTION
208              
209             This is only meant for internal use yet.
210              
211             It's some shared parse-from-element, error suppression, no output, violation
212             accumulation and violation line number things for POD parsing in policies.
213              
214             =head1 SEE ALSO
215              
216             L<Perl::Critic::Pulp>
217              
218             =head1 HOME PAGE
219              
220             L<http://user42.tuxfamily.org/perl-critic-pulp/index.html>
221              
222             =head1 COPYRIGHT
223              
224             Copyright 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019 Kevin Ryde
225              
226             Perl-Critic-Pulp is free software; you can redistribute it and/or modify it
227             under the terms of the GNU General Public License as published by the Free
228             Software Foundation; either version 3, or (at your option) any later
229             version.
230              
231             Perl-Critic-Pulp is distributed in the hope that it will be useful, but
232             WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
233             or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
234             more details.
235              
236             You should have received a copy of the GNU General Public License along with
237             Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses/>.
238              
239             =cut