File Coverage

blib/lib/Pod/MinimumVersion.pm
Criterion Covered Total %
statement 77 81 95.0
branch 34 44 77.2
condition 19 19 100.0
subroutine 20 20 100.0
pod 4 6 66.6
total 154 170 90.5


line stmt bran cond sub pod time code
1             # Copyright 2009, 2010, 2011 Kevin Ryde
2              
3             # This file is part of Pod-MinimumVersion.
4              
5             # Pod-MinimumVersion 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             # Pod-MinimumVersion 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 Pod-MinimumVersion. If not, see .
17              
18              
19             package Pod::MinimumVersion;
20 2     2   2224 use 5.004;
  2         7  
  2         89  
21 2     2   11 use strict;
  2         3  
  2         75  
22 2     2   12 use List::Util;
  2         8  
  2         160  
23 2     2   1984 use version;
  2         5758  
  2         20  
24 2     2   241 use vars qw($VERSION @CHECKS);
  2         4  
  2         4549  
25              
26             # uncomment this to run the ### lines
27             #use Smart::Comments;
28              
29             $VERSION = 50;
30              
31             sub new {
32 50     50 1 12778 my ($class, %self) = @_;
33 50   100     251 $self{'want_reports'} ||= 'one_per_version';
34 50         163 return bless \%self, $class;
35             }
36              
37             sub minimum_version {
38 45     45 1 1232654 my ($self) = @_;
39 45   100     126 my $report = $self->minimum_report || return undef;
40 24         103 return $report->{'version'};
41             }
42             sub minimum_report {
43 45     45 1 309 my ($self) = @_;
44 45 50       133 if (! exists $self->{'minimum_report'}) {
45 5 100   5   46 $self->{'minimum_report'}
46             = List::Util::reduce {$a->{'version'} > $b->{'version'} ? $a : $b}
47 45         235 $self->reports;
48             }
49 45         848 return $self->{'minimum_report'};
50             }
51             sub reports {
52 91     91 1 231 my ($self) = @_;
53 91         195 $self->analyze;
54 91 100       712 return @{$self->{'reports'} || []};
  91         644  
55             }
56              
57             sub analyze {
58 94     94 0 138 my ($self) = @_;
59 94 100       249 return if $self->{'analyzed'};
60 49         76 $self->{'analyzed'} = 1;
61              
62             ### Pod-MinVer analyze()
63              
64 49         57 my %checks;
65 49         85 foreach my $elem (@CHECKS) {
66 392         667 my ($func, $command, $version) = @$elem;
67 392 100 100     2240 next if ($self->{'above_version'} && $version <= $self->{'above_version'});
68 320         450 push @{$checks{$command}}, $func;
  320         861  
69             }
70 49 100       259 return if (! %checks);
71              
72 48         1818 require Pod::MinimumVersion::Parser;
73 48         508 my $parser = Pod::MinimumVersion::Parser->new (pmv => $self,
74             checks => \%checks);
75 48 50       129 if (exists $self->{'string'}) {
    0          
    0          
76 48         189 $parser->parse_from_string ("$self->{'string'}");
77             } elsif (exists $self->{'filehandle'}) {
78 0         0 $parser->parse_from_filehandle ($self->{'filehandle'});
79             } elsif (exists $self->{'filename'}) {
80             # stringize to parse_from_file() taking an overloaded object to be a handle
81             # ENHANCE-ME: perhaps opening here and parse_from_filehandle() would be
82             # a better way to avoid
83 0         0 $parser->parse_from_file ("$self->{'filename'}");
84             }
85             }
86              
87             #------------------------------------------------------------------------------
88             # 5.004
89             #
90             # E<> newly documented in 5.004, but is in pod2man right back to 5.002, so
91             # don't report that
92              
93             {
94             my $v5004 = version->new('5.004');
95              
96             # =for, =begin, =end new in 5.004
97             #
98             push @CHECKS, [ \&_check_for_begin_end, 'command', $v5004 ];
99             my %for_begin_end = (for => 1, begin => 1, end => 1);
100             sub _check_for_begin_end {
101 33     33   65 my ($self, $command, $text, $para_obj) = @_;
102 33 100       127 if ($for_begin_end{$command}) {
103 9         31 $self->report ('for_begin_end', $v5004, $para_obj, "=$command command");
104             }
105             }
106             }
107              
108             #------------------------------------------------------------------------------
109             # 5.005
110              
111             {
112             my $v5005 = version->new('5.005');
113              
114             # L display alternative new in 5.005
115             #
116             push @CHECKS, [ \&_check_link_display_text, 'interior_sequence', $v5005 ];
117             sub _check_link_display_text {
118 27     27   47 my ($self, $command, $arg, $seq_obj) = @_;
119 27 100 100     1379 if ($command eq 'L' && $arg =~ /\|/) {
120 4         15 $self->report ('link_display_text', $v5005, $seq_obj,
121             'Display text L link');
122             }
123             }
124             }
125              
126             #------------------------------------------------------------------------------
127             # 5.006
128              
129             {
130             my $v5006 = version->new('5.006');
131              
132             push @CHECKS, [ \&_check_double_angles, 'interior_sequence', $v5006 ];
133             sub _check_double_angles {
134 28     28   54 my ($self, $command, $arg, $seq_obj) = @_;
135              
136 28 100       199 if ($seq_obj->left_delimiter =~ /^<
137 8         22 $self->report ('double_angles', $v5006, $seq_obj,
138             'Double angle brackets C<< foo >>');
139             }
140             }
141             }
142              
143             #------------------------------------------------------------------------------
144             # 5.008
145              
146             {
147             my $v5008 = version->new('5.008');
148              
149             # =head3 and =head4 new in 5.8.0
150             push @CHECKS, [ \&_check_head34, 'command', $v5008 ];
151             my %head34 = (head3 => 1, head4 => 1);
152             sub _check_head34 {
153 38     38   64 my ($self, $command, $text, $para_obj) = @_;
154 38 100       150 if ($head34{$command}) {
155 2         9 $self->report ('head34', $v5008, $para_obj, "=$command command");
156             }
157             }
158              
159             # E and E documented in 5.6.0, but Pod::Man only has them in
160             # 5.8.0, so rate them as a 5008 feature
161             #
162             # E is in Pod::Man of 5.8.0, though not documented explicitly
163             #
164             push @CHECKS, [ \&_check_E_5008, 'interior_sequence', $v5008 ];
165             my %E_5008 = (apos => 1, sol => 1, verbar => 1);
166             sub _check_E_5008 {
167 29     29   55 my ($self, $command, $arg, $seq_obj) = @_;
168              
169 29 100 100     246 if ($command eq 'E' && $E_5008{$arg}) {
170 3         13 $self->report ('E_5008', $v5008, $seq_obj, "E<$arg> escape");
171             }
172             }
173              
174             # L urls new in 5.8.0
175             #
176             # In 5.6 and earlier the "/" is interpreted as a section, so from
177             # L you get something bad like
178             #
179             # the section on "/foo.com/index.html" in the http: manpage
180             #
181             # Crib note: a "|" display text part is not allowed with a url, according
182             # to perlpodspec of perl 5.10.0 under the "Authors wanting to link to a
183             # particular (absolute) URL" bullet point. So no need to watch for that
184             # in applying this test.
185             #
186             push @CHECKS, [ \&_check_link_url, 'interior_sequence', $v5008 ];
187             sub _check_link_url {
188 29     29   62 my ($self, $command, $arg, $seq_obj) = @_;
189             # this regexp as recommended by perlpodspec of perl 5.10.0
190 29 100 100     153 if ($command eq 'L' && $arg =~ m/\A\w+:[^:\s]\S*\z/) {
191 2         7 $self->report ('link_url', $v5008, $seq_obj,
192             'L<> link to URL');
193             }
194             }
195             }
196              
197             #------------------------------------------------------------------------------
198             # 5.010
199              
200             {
201             my $v5010 = version->new('5.010');
202              
203             # =encoding documented in 5.8.0, but Pod::Man doesn't recognise it until
204             # 5.10.0, so rate it as a 5010 feature
205             #
206             push @CHECKS, [ \&_check_encoding, 'command', $v5010 ];
207             sub _check_encoding {
208 45     45   83 my ($self, $command, $text, $para_obj) = @_;
209 45 100       193 if ($command eq 'encoding') {
210 2         6 $self->report ('encoding', $v5010, $para_obj, '=encoding command');
211             }
212             }
213             }
214              
215             #------------------------------------------------------------------------------
216             # 5.012
217              
218             {
219             my $v5012 = version->new('5.012');
220              
221             # L documented in 5.12.0 where previously explicitly prohibited,
222             # rate it as a 5012 feature
223             #
224             push @CHECKS, [ \&_check_link_url_with_text, 'interior_sequence', $v5012 ];
225             sub _check_link_url_with_text {
226 34     34   61 my ($self, $command, $arg, $seq_obj) = @_;
227             # this regexp adapted from recommendation of perlpodspec from perl 5.10.0
228 34 100 100     226 if ($command eq 'L' && $arg =~ m/\A.*\|\w+:[^:\s]\S*\z/) {
229 2         7 $self->report ('link_url_with_text', $v5012, $seq_obj,
230             'L<> link with URL and text');
231             }
232             }
233             }
234              
235             #------------------------------------------------------------------------------
236              
237             sub report {
238 32     32 0 56 my ($self, $name, $version, $pod_obj, $why) = @_;
239              
240 32 50       82 if ($self->{'want_reports'} eq 'one_per_check') {
241 0 0       0 return if ($self->{'seen'}->{$name}++);
242             }
243 32 100       79 if ($self->{'want_reports'} eq 'one_per_version') {
244 29 100       1086 return if ($self->{'seen'}->{$version}++);
245             }
246              
247 31         199 my ($filename, $linenum) = $pod_obj->file_line;
248 31 50       79 if (defined $self->{'filename'}) {
249 0         0 $filename = $self->{'filename'};
250             }
251 31         917 require Pod::MinimumVersion::Report;
252 31         48 push @{$self->{'reports'}},
  31         234  
253             Pod::MinimumVersion::Report->new (filename => $filename,
254             name => $name,
255             linenum => $linenum,
256             version => $version,
257             why => $why);
258             }
259              
260             1;
261             __END__