File Coverage

blib/lib/Perl/Critic/Policy/CodeLayout/TabIndentSpaceAlign.pm
Criterion Covered Total %
statement 55 55 100.0
branch 21 24 87.5
condition 5 6 83.3
subroutine 16 16 100.0
pod 5 5 100.0
total 102 106 96.2


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::CodeLayout::TabIndentSpaceAlign;
2              
3 3     3   402332 use 5.006001;
  3         13  
  3         123  
4 3     3   16 use strict;
  3         7  
  3         100  
5 3     3   17 use warnings;
  3         11  
  3         103  
6              
7 3     3   25 use base 'Perl::Critic::Policy';
  3         6  
  3         3463  
8              
9 3     3   628658 use Carp;
  3         10  
  3         218  
10 3     3   20 use Perl::Critic::Utils;
  3         8  
  3         57  
11 3     3   3252 use Readonly;
  3         8  
  3         312  
12 3     3   3260 use Try::Tiny;
  3         5034  
  3         2398  
13              
14              
15             =head1 NAME
16              
17             Perl::Critic::Policy::CodeLayout::TabIndentSpaceAlign - Use tabs for indenting, spaces for aligning.
18              
19              
20             =head1 VERSION
21              
22             Version 1.0.5
23              
24             =cut
25              
26             our $VERSION = '1.0.5';
27              
28              
29             =head1 AFFILIATION
30              
31             This is a standalone policy not part of a larger PerlCritic Policies group.
32              
33              
34             =head1 DESCRIPTION
35              
36             Hard tabs are a perfectly fine way to indent code for accessibility and
37             usability purposes, allowing different users to tweak indentation settings to
38             suit their needs and habits. However, hard tabs should not be used for
39             formatting / aligning, as this makes the display dependent on the tab-to-space
40             ratio of the user.
41              
42             C<Perl/Critic/Policy/CodeLayout/ProhibitHardTabs> has a setting that allows
43             leading tabs, but this not not fully represent the paradigm where tabs are
44             reserved for indenting and spaces for formatting/aligning. In particular, it
45             does not prevent indenting with spaces, while this module detects and prevents
46             it.
47              
48             This Policy examines your source code, including POD, quotes, and HEREDOCs.
49             The contents of the C<__DATA__> section are not examined.
50              
51              
52             =head1 CONFIGURATION
53              
54             There is no configuration option available for this policy.
55              
56              
57             =head1 NOTES
58              
59             Beware that Perl::Critic may report the location of the string that contains the
60             tab, not the actual location of the tab, so you may need to do some hunting.
61              
62             =cut
63              
64             Readonly::Scalar my $DESCRIPTION => 'Non-leading tab.';
65             Readonly::Scalar my $EXPLANATION => 'Use tabs for indenting, spaces for formatting. Found a non-leading tab.';
66              
67              
68             =head1 FUNCTIONS
69              
70             =head2 supported_parameters()
71              
72             Return an array with information about the parameters supported.
73              
74             my @supported_parameters = $policy->supported_parameters();
75              
76             =cut
77              
78             sub supported_parameters
79             {
80 21     21 1 124759 return ();
81             }
82              
83              
84             =head2 default_severity()
85              
86             Return the default severify for this policy.
87              
88             my $default_severity = $policy->default_severity();
89              
90             =cut
91              
92             sub default_severity
93             {
94 14     14 1 190 return $Perl::Critic::Utils::SEVERITY_MEDIUM;
95             }
96              
97              
98             =head2 default_themes()
99              
100             Return the default themes this policy is included in.
101              
102             my $default_themes = $policy->default_themes();
103              
104             =cut
105              
106             sub default_themes
107             {
108 1     1 1 988 return qw( cosmetic );
109             }
110              
111              
112             =head2 applies_to()
113              
114             Return the class of elements this policy applies to.
115              
116             my $class = $policy->applies_to();
117              
118             =cut
119              
120             sub applies_to
121             {
122 21     21 1 169978 return 'PPI::Token';
123             }
124              
125              
126             =head2 violates()
127              
128             Check an element for violations against this policy.
129              
130             my $policy->violates(
131             $element,
132             $document,
133             );
134              
135             =cut
136              
137             sub violates
138             {
139 231     231 1 5763 my ( $self, $element, undef ) = @_;
140              
141             # The __DATA__ element is exempt.
142 231 50       1129 return if $element->parent->isa('PPI::Statement::Data');
143              
144             my $violations =
145             try
146             {
147             # Check comments and any kind of whitespace block.
148 231 100 100 231   9730 if ( $element->isa('PPI::Token::Comment') || $element->isa('PPI::Token::Whitespace') )
    100          
149             {
150             # Newlines can be included at the beginning / end of whitespace elements by
151             # PPI, ignore those.
152 134         441 my $content = $element->content();
153 134         1360 $content =~ s/^[\r\n]+//;
154 134         276 $content =~ s/[\r\n]+$//;
155              
156 134 100       406 if ( $element->column_number() == 1 )
157             {
158 67 100       3115 croak 'In comments and indentation, tabs are only allowed at the beginning of the string. Spaces are allowed but only after a non-space character.'
159             if $content !~ /\A\t*(?:|\S[^\t]*)\z/;
160             }
161             else
162             {
163             # If it's not at the beginning of a line, just make sure we don't have
164             # any tabs.
165 67 100       1566 croak 'Tabs are not allowed after non-whitespace on the line.'
166             if $content =~ /\t/;
167             }
168             }
169             # Check HereDoc separately, as the content for the object is accessed with
170             # a special method.
171             elsif ( $element->isa('PPI::Token::HereDoc') )
172             {
173 2         7 my $declaration = $element->content();
174 2 50       16 croak 'The HereDoc declaration should not have any tabs.'
175             if $declaration =~ /\t/;
176              
177             # The content of the HereDoc block should behave like a multiline string.
178 2         8 my @heredoc = $element->heredoc();
179 2 100       31 croak 'Tabs are not allowed after non-tab characters.' if _has_violations_in_multiline_string( join( "\n", @heredoc ) );
180              
181 1         4 my $terminator = $element->terminator();
182 1 50       10 croak 'The HereDoc terminator should not have any tabs.'
183             if $terminator =~ /\t/;
184             }
185             # Check everything else.
186             else
187             {
188 95         276 my $content = $element->content();
189 95 100       628 croak 'Tabs are not allowed after non-tab characters.' if _has_violations_in_multiline_string( $content );
190             }
191              
192 217         844 return;
193             }
194             catch
195             {
196 14     14   1078 return $_;
197 231         5288 };
198              
199 231 100 66     4636 return $self->violation(
200             $DESCRIPTION,
201             $EXPLANATION,
202             $element,
203             ) if defined( $violations ) && ( $violations ne '' );
204              
205 217         641 return;
206             }
207              
208              
209             =head2 _has_violations_in_multiline_string()
210              
211             Return a boolean indicating if a multiline string has violations against this
212             policy.
213              
214             my $string_has_violations = _has_violations_in_multiline_string( $string );
215              
216             =cut
217              
218             sub _has_violations_in_multiline_string
219             {
220 97     97   214 my ( $string ) = @_;
221              
222 97         512 foreach my $line ( split( /\r?\n/, $string ) )
223             {
224             # Don't allow tabs after non-tab characters on the same line.
225             # However, a tab followed by a space is legit, unlike the rest of the code.
226 134 100       487 next if $line !~ /[^\t]\t/;
227              
228 5         1369 return 1;
229             }
230              
231 92         379 return 0;
232             }
233              
234              
235             =head1 BUGS
236              
237             Please report any bugs or feature requests through the web interface at
238             L<https://github.com/guillaumeaubert/Perl-Critic-Policy-CodeLayout-TabIndentSpaceAlign/issues>.
239             I will be notified, and then you'll automatically be notified of progress on
240             your bug as I make changes.
241              
242              
243             =head1 SUPPORT
244              
245             You can find documentation for this module with the perldoc command.
246              
247             perldoc Perl::Critic::Policy::CodeLayout::TabIndentSpaceAlign
248              
249              
250             You can also look for information at:
251              
252             =over 4
253              
254             =item * GitHub (report bugs there)
255              
256             L<https://github.com/guillaumeaubert/Perl-Critic-Policy-CodeLayout-TabIndentSpaceAlign/issues>
257              
258             =item * AnnoCPAN: Annotated CPAN documentation
259              
260             L<http://annocpan.org/dist/Perl-Critic-Policy-CodeLayout-TabIndentSpaceAlign>
261              
262             =item * CPAN Ratings
263              
264             L<http://cpanratings.perl.org/d/Perl-Critic-Policy-CodeLayout-TabIndentSpaceAlign>
265              
266             =item * MetaCPAN
267              
268             L<https://metacpan.org/release/Perl-Critic-Policy-CodeLayout-TabIndentSpaceAlign>
269              
270             =back
271              
272              
273             =head1 AUTHOR
274              
275             L<Guillaume Aubert|https://metacpan.org/author/AUBERTG>,
276             C<< <aubertg at cpan.org> >>.
277              
278              
279             =head1 ACKNOWLEDGEMENTS
280              
281             I originally developed this project for ThinkGeek
282             (L<http://www.thinkgeek.com/>). Thanks for allowing me to open-source it!
283              
284              
285             =head1 COPYRIGHT & LICENSE
286              
287             Copyright 2012-2014 Guillaume Aubert.
288              
289             This program is free software: you can redistribute it and/or modify it under
290             the terms of the GNU General Public License version 3 as published by the Free
291             Software Foundation.
292              
293             This program is distributed in the hope that it will be useful, but WITHOUT ANY
294             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
295             PARTICULAR PURPOSE. See the GNU General Public License for more details.
296              
297             You should have received a copy of the GNU General Public License along with
298             this program. If not, see http://www.gnu.org/licenses/
299              
300             =cut
301              
302             1;