File Coverage

blib/lib/SourceCode/LineCounter/Perl.pm
Criterion Covered Total %
statement 87 87 100.0
branch 36 38 94.7
condition 2 3 66.6
subroutine 31 31 100.0
pod 13 13 100.0
total 169 172 98.2


line stmt bran cond sub pod time code
1 7     7   5022 use v5.10;
  7         23  
2              
3             package SourceCode::LineCounter::Perl;
4 7     7   35 use strict;
  7         13  
  7         143  
5              
6 7     7   32 use warnings;
  7         11  
  7         211  
7 7     7   36 no warnings;
  7         18  
  7         295  
8              
9 7     7   42 use Carp qw(carp);
  7         11  
  7         8127  
10              
11             our $VERSION = '1.022';
12              
13             =encoding utf8
14              
15             =head1 NAME
16              
17             SourceCode::LineCounter::Perl - Count lines in Perl source code
18              
19             =head1 SYNOPSIS
20              
21             use SourceCode::LineCounter::Perl;
22              
23             my $counter = SourceCode::LineCounter::Perl->new;
24              
25             $counter->count( $file );
26              
27             my $total_lines = $counter->total;
28              
29             my $pod_lines = $counter->documentation;
30              
31             my $code_lines = $counter->code;
32              
33             my $comment_lines = $counter->comment;
34              
35             my $comment_lines = $counter->blank;
36              
37              
38             =head1 DESCRIPTION
39              
40             This module counts the lines in Perl source code and tries to classify
41             them as code lines, documentation lines, and blank lines.
42              
43             Read a line
44              
45             If it's a blank line, record it and move on to the next line
46              
47             If it is the start of pod, mark that we are in pod, and count
48             it as a pod line and move on
49              
50             If we are in pod and the line is blank, record it as a blank line
51             and a pod line, and move on.
52              
53             If we are ending pod (with C<=cut>, record it as a pod line and
54             move on.
55              
56             If we are in pod and it is not blank, record it as a pod line and
57             move on.
58              
59             If we are not in pod, guess if the line has a comment. If the
60             line has a comment, record it.
61              
62             Removing comments, see if there is anything left. If there is,
63             record it as a code line.
64              
65             Move on to the next line.
66              
67             =cut
68              
69             =over 4
70              
71             =item new
72              
73             =cut
74              
75             sub new {
76 6     6 1 5336 my( $class, %hash ) = @_;
77              
78 6         17 my $self = bless {}, $class;
79 6         19 $self->_init;
80              
81 6         14 $self;
82             }
83              
84             =item reset
85              
86             Reset everything the object counted so you can use the same object
87             with another file.
88              
89             =cut
90              
91             sub reset {
92 1     1 1 873 $_[0]->_init;
93             }
94              
95             =item accumulate( [ BOOLEAN ] )
96              
97             With no argument, returns the current setting as true or false.
98              
99             With one argument, sets the value for accumulation. If that's true,
100             the counter will add to the count from previous calls to C.
101             If false, C starts fresh each time.
102              
103             =cut
104              
105             sub accumulate {
106 1     1 1 3 my( $self ) = @_;
107              
108 1 50       11 $self->{accumulate} = !! $_[1] if @_ > 1;
109              
110 1         6 return $self->{accumulate};
111             }
112              
113             =item count( FILE )
114              
115             Counts the lines in FILE. The optional second argument, if true,
116             adds those counts to the counts from the last run. By default,
117             previous results are cleared.
118              
119             =cut
120              
121             sub count {
122 2     2 1 3331 my( $self, $file ) = @_;
123              
124 2         5 my $fh;
125 2 100       108 unless( open $fh, "<", $file ) {
126 1         181 carp "Could not open file [$file]: $!";
127 1         134 return;
128             }
129              
130 1 50       6 $self->_clear_line_info unless $self->accumulate;
131              
132 1         24 LINE: while( <$fh> ) {
133 15         23 chomp;
134 15         33 $self->_set_current_line( \$_ );
135              
136 15         27 $self->_total( \$_ );
137 15 100       24 $self->add_to_blank if $self->_is_blank( \$_ );
138              
139 15         30 foreach my $type ( qw( _start_pod _end_pod _pod_line ) ) {
140 42 100 66     73 $self->$type( \$_ ) && $self->add_to_documentation && next LINE;
141             }
142              
143 5 100       13 $self->add_to_comment if $self->_is_comment( \$_ );
144 5 100       9 $self->add_to_code if $self->_is_code( \$_ );
145             }
146              
147 1         23 $self;
148             }
149              
150             sub _clear_line_info {
151 8     8   22 $_[0]->{line_info} = {};
152             }
153              
154             sub _set_current_line {
155 15     15   26 $_[0]->{line_info}{current_line} = \ $_[1];
156             }
157              
158             sub _init {
159 7     7   21 my @attrs = qw(total blank documentation code comment accumulate);
160 7 100       16 foreach ( @attrs ) { $_[0]->{$_} = 0 unless defined $_[0]->{$_} }
  42         122  
161 7         23 $_[0]->_clear_line_info;
162             };
163              
164             =item total
165              
166             Returns the total number of lines in the file
167              
168             =cut
169              
170 4     4 1 885 sub total { $_[0]->{total} }
171              
172 22     22   1527 sub _total { ++ $_[0]->{total} }
173              
174             =item documentation
175              
176             Returns the total number of Pod lines in the file, including
177             and blank lines in Pod.
178              
179             =cut
180              
181 10     10 1 5902 sub documentation { $_[0]->{documentation} }
182              
183             =item add_to_documentation
184              
185             Add to the documentation line counter if the line is documentation.
186              
187             =cut
188              
189             sub add_to_documentation {
190 11     11 1 18 $_[0]->{line_info}{documentation}++;
191 11         13 $_[0]->{documentation}++;
192              
193 11         50 1;
194             }
195              
196             sub _start_pod {
197 20 100   20   35 return if $_[0]->_in_pod;
198 10 100       41 return unless ${$_[1]} =~ /^=\w+/;
  10         37  
199              
200 2         7 $_[0]->_mark_in_pod;
201              
202 2         7 1;
203             }
204              
205             sub _end_pod {
206 17 100   17   33 return unless $_[0]->_in_pod;
207 11 100       15 return unless ${$_[1]} =~ /^=cut$/;
  11         37  
208              
209 2         8 $_[0]->_clear_in_pod;
210              
211 2         5 1;
212             }
213              
214             sub _pod_line {
215 26 100   26   2988 return unless $_[0]->_in_pod;
216             }
217              
218 10     10   12086 sub _mark_in_pod { $_[0]->{line_info}{in_pod}++ }
219 117     117   1975 sub _in_pod { $_[0]->{line_info}{in_pod} }
220 9     9   6315 sub _clear_in_pod { $_[0]->{line_info}{in_pod} = 0 }
221              
222              
223             =item code
224              
225             Returns the number of non-blank lines, whether documentation
226             or code.
227              
228             =cut
229              
230 4     4 1 3104 sub code { $_[0]->{code} }
231              
232             =item add_to_code( LINE )
233              
234             Add to the code line counter if the line is a code line.
235              
236             =cut
237              
238             sub add_to_code {
239 2     2 1 6 $_[0]->{line_info}{code}++;
240 2         7 ++$_[0]->{code};
241             }
242              
243             sub _is_code {
244 12     12   2073 my( $self, $line_ref ) = @_;
245 12 100       23 return if grep { $self->$_() } qw(_is_blank _in_pod);
  24         66  
246              
247             # this will be false for things in strings!
248 10         54 ( my $copy = $$line_ref ) =~ s/\s*#.*//;
249              
250 10 100       35 return unless length $copy;
251              
252 5         18 1;
253             }
254              
255             =item comment
256              
257             The number of lines with comments. These are the things
258             that start with #. That might be lines that are all comments
259             or code lines that have comments.
260              
261             =cut
262              
263 5     5 1 2751 sub comment { $_[0]->{comment} }
264              
265             =item add_to_comment
266              
267             Add to the comment line counter if the line has a comment. A line
268             might be counted as both code and comments.
269              
270             =cut
271              
272             sub add_to_comment {
273 3     3 1 8 $_[0]->{line_info}{comment}++;
274 3         17 ++$_[0]->{comment};
275             }
276              
277             sub _is_comment {
278 20 100   20   10497 return if $_[0]->_in_pod;
279 16 100       24 return unless ${$_[1]} =~ m/#/;
  16         54  
280 9         57 1;
281             }
282              
283             =item blank
284              
285             The number of blank lines. By default, these are lines that
286             match the regex qr/^\s*$/. You can change this in C
287             by specifying the C parameter.
288              
289             =cut
290              
291 4     4 1 2640 sub blank { $_[0]->{blank} }
292              
293             =item add_to_blank
294              
295             Add to the blank line counter if the line is blank.
296              
297             =cut
298              
299             sub add_to_blank {
300 7     7 1 11 $_[0]->{line_info}{blank}++;
301 7         13 ++$_[0]->{blank};
302             }
303              
304             sub _is_blank {
305 36 100   36   5560 return unless defined $_[1];
306 24 100       29 return unless ${$_[1]} =~ m/^\s*$/;
  24         94  
307 11         29 1;
308             }
309              
310             =back
311              
312             =head1 TO DO
313              
314             =over 4
315              
316             =item * Generalized LineCounter that can dispatch to language
317             delegates.
318              
319             =back
320              
321             =head1 SEE ALSO
322              
323              
324             =head1 SOURCE AVAILABILITY
325              
326             This source is in Github
327              
328             https://github.com/briandfoy/sourcecode-linecounter-perl
329              
330             =head1 AUTHOR
331              
332             brian d foy, C<< >>
333              
334             =head1 COPYRIGHT AND LICENSE
335              
336             Copyright © 2008-2021, brian d foy . All rights reserved.
337              
338             You may redistribute this under the terms of the Artistic License 2.0.
339              
340             =cut
341              
342             1;