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 8     8   2518706 use v5.10;
  8         36  
2              
3             package SourceCode::LineCounter::Perl;
4 8     8   53 use strict;
  8         17  
  8         362  
5              
6 8     8   60 use warnings;
  8         22  
  8         591  
7 8     8   48 no warnings;
  8         20  
  8         570  
8              
9 8     8   84 use Carp qw(carp);
  8         18  
  8         13620  
10              
11             our $VERSION = '1.024';
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 12397 my( $class, %hash ) = @_;
77              
78 6         20 my $self = bless {}, $class;
79 6         27 $self->_init;
80              
81 6         22 $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 1447 $_[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       4 $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 11730 my( $self, $file ) = @_;
123              
124 2         4 my $fh;
125 2 100       86 unless( open $fh, "<", $file ) {
126 1         254 carp "Could not open file [$file]: $!";
127 1         69 return;
128             }
129              
130 1 50       6 $self->_clear_line_info unless $self->accumulate;
131              
132 1         53 LINE: while( <$fh> ) {
133 15         35 chomp;
134 15         46 $self->_set_current_line( \$_ );
135              
136 15         43 $self->_total( \$_ );
137 15 100       32 $self->add_to_blank if $self->_is_blank( \$_ );
138              
139 15         35 foreach my $type ( qw( _start_pod _end_pod _pod_line ) ) {
140 42 100 66     108 $self->$type( \$_ ) && $self->add_to_documentation && next LINE;
141             }
142              
143 5 100       14 $self->add_to_comment if $self->_is_comment( \$_ );
144 5 100       11 $self->add_to_code if $self->_is_code( \$_ );
145             }
146              
147 1         25 $self;
148             }
149              
150             sub _clear_line_info {
151 8     8   33 $_[0]->{line_info} = {};
152             }
153              
154             sub _set_current_line {
155 15     15   34 $_[0]->{line_info}{current_line} = \ $_[1];
156             }
157              
158             sub _init {
159 7     7   29 my @attrs = qw(total blank documentation code comment accumulate);
160 7 100       34 foreach ( @attrs ) { $_[0]->{$_} = 0 unless defined $_[0]->{$_} }
  42         170  
161 7         27 $_[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 1419 sub total { $_[0]->{total} }
171              
172 22     22   4205 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 12565 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 24 $_[0]->{line_info}{documentation}++;
191 11         19 $_[0]->{documentation}++;
192              
193 11         75 1;
194             }
195              
196             sub _start_pod {
197 20 100   20   55 return if $_[0]->_in_pod;
198 10 100       19 return unless ${$_[1]} =~ /^=\w+/;
  10         53  
199              
200 2         10 $_[0]->_mark_in_pod;
201              
202 2         10 1;
203             }
204              
205             sub _end_pod {
206 17 100   17   43 return unless $_[0]->_in_pod;
207 11 100       19 return unless ${$_[1]} =~ /^=cut$/;
  11         52  
208              
209 2         24 $_[0]->_clear_in_pod;
210              
211 2         9 1;
212             }
213              
214             sub _pod_line {
215 26 100   26   5553 return unless $_[0]->_in_pod;
216             }
217              
218 10     10   25376 sub _mark_in_pod { $_[0]->{line_info}{in_pod}++ }
219 117     117   5167 sub _in_pod { $_[0]->{line_info}{in_pod} }
220 9     9   17281 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 5045 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 7 $_[0]->{line_info}{code}++;
240 2         10 ++$_[0]->{code};
241             }
242              
243             sub _is_code {
244 12     12   3474 my( $self, $line_ref ) = @_;
245 12 100       28 return if grep { $self->$_() } qw(_is_blank _in_pod);
  24         67  
246              
247             # this will be false for things in strings!
248 10         63 ( my $copy = $$line_ref ) =~ s/\s*#.*//;
249              
250 10 100       48 return unless length $copy;
251              
252 5         22 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 6095 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 12 $_[0]->{line_info}{comment}++;
274 3         10 ++$_[0]->{comment};
275             }
276              
277             sub _is_comment {
278 20 100   20   17677 return if $_[0]->_in_pod;
279 16 100       27 return unless ${$_[1]} =~ m/#/;
  16         70  
280 9         43 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 5753 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 16 $_[0]->{line_info}{blank}++;
301 7         27 ++$_[0]->{blank};
302             }
303              
304             sub _is_blank {
305 36 100   36   10649 return unless defined $_[1];
306 24 100       39 return unless ${$_[1]} =~ m/^\s*$/;
  24         152  
307 11         43 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-2025, 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;