File Coverage

blib/lib/Filter/Indent/HereDoc.pm
Criterion Covered Total %
statement 35 52 67.3
branch 11 26 42.3
condition 0 3 0.0
subroutine 4 4 100.0
pod 0 1 0.0
total 50 86 58.1


line stmt bran cond sub pod time code
1             package Filter::Indent::HereDoc;
2              
3 1     1   79158 use strict;
  1         3  
  1         35  
4 1     1   7 use warnings;
  1         2  
  1         30  
5 1     1   13126 use Filter::Simple;
  1         60744  
  1         8  
6              
7             our $VERSION = '1.01';
8             our %options = ();
9             our @buffer; # Temporary storage of current here document
10             our @termstring; # FIFO list of here document terminating strings
11              
12             sub import {
13             %options = ();
14             $options{$_}++ foreach (@_);
15             }
16              
17             FILTER_ONLY
18             executable => sub {
19             my @code = split /\n/;
20             $_ = join '',(map &process_line($_),@code);
21             };
22              
23             sub process_line {
24 11     11 0 17 my $line = shift;
25 11 100       23 if (@termstring) {
26             # At this point we are in a here document, so all lines of code
27             # are buffered until the end of the heredoc is detected
28 2         7 push @buffer,$line;
29            
30             # 2 scenarios - terminator is a blank line, or terminator contains non-
31             # whitespace. If blank line, then look for same whitespace at start of
32             # each line in buffer. Otherwise take the whitespace that precedes the
33             # terminator and match this against each line in the buffer.
34             #
35             # By default, we accept terminator strings in the Perl6 RFC111 format,
36             # i.e. whitespace, ';', and comments following the terminator are
37             # allowed. The only exception is if the terminator is a blank line,
38             # in this case then only whitespace is allowed.
39            
40 2         3 my $termregex;
41 2 50       265 unless ($options{strict_terminators}) {
42 2 50       12 if ($termstring[0] =~ /\S/) {
43 2         40 $termregex = qr/^(\s*)($termstring[0])(\s*;{0,1}\s*(?:#.*){0,1})$/;
44             } else {
45 0         0 $termregex = qr/^\s*$/;
46             }
47             } else {
48 0 0       0 if ($termstring[0] =~ /\S/) {
49 0         0 $termregex = qr/^(\s*)($termstring[0])$/;
50             } else {
51 0         0 $termregex = qr/^$/;
52             }
53             }
54            
55 2         6 my ($whitespace,$terminator,$extras);
56 2 100       23 if ($line =~ $termregex) {
57 1         6 ($whitespace,$terminator,$extras) = ($1,$2,$3);
58 1 50       6 if ($termstring[0] =~ /\S/) {
59 1         4 foreach (@buffer) {
60 2 50       77 return unless (/^$whitespace/);
61             }
62             } else {
63             # Terminator string is a blank line
64 0         0 undef $whitespace;
65 0         0 foreach (@buffer) {
66 0 0       0 if (/^(\s+)\S/) {
67 0 0 0     0 $whitespace = $1 unless ($whitespace and /^$whitespace\s*/);
68             }
69             }
70             }
71             # End of heredoc - strip the required amount of whitespace
72 1         27 map s/^$whitespace//,@buffer;
73            
74             # If we found extra characters after the terminator (Perl6 RFC111
75             # style), move them onto a new line to be compatible with Perl5
76 1 50       7 if ($extras) {
77 0         0 pop @buffer;
78 0         0 push @buffer,$terminator;
79 0         0 push @buffer,$extras;
80             }
81            
82             # Return captured heredoc back to Perl and reset the buffer
83 1         4 $line = join "\n",@buffer;
84 1         3 @buffer = ();
85 1         2 shift @termstring;
86 1         12 return "$line\n";
87             }
88             } else {
89             # Perl6 RFC111 states that whitespace after the terminator
90             # should be ingored
91 9 50       22 unless ($options{strict_terminators}) {
92 9         19 $line =~ s/(?
93             }
94              
95             # Can we find the start of any here documents?
96 9         25 MATCH: while ($line =~ m/(?
97 1 50       9 if ($line =~ m/\G(\w+)/) {
98 1         4 push @termstring,$1;
99 1         3 next MATCH;
100             }
101              
102 0 0       0 if ($line =~ m/\G(?:\s*(['"`]))(.*?)(?
103 0         0 my ($quote,$string) = ($1,$2);
104 0         0 $string =~ s/\\$quote/$quote/g;
105 0         0 push @termstring,$string;
106 0         0 next MATCH;
107             }
108            
109             # Use of bare << to mean <<"" is depreciated
110             # ...but still works so the module needs to support it!
111 0         0 push @termstring,'';
112             }
113 9         100 return "$line\n";
114             }
115             }
116              
117             1;
118             __END__