File Coverage

blib/lib/Perl/Critic/Policy/CodeLayout/RequireTrailingCommaAtNewline.pm
Criterion Covered Total %
statement 84 85 98.8
branch 33 38 86.8
condition 33 43 76.7
subroutine 15 15 100.0
pod 1 1 100.0
total 166 182 91.2


line stmt bran cond sub pod time code
1             # Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Kevin Ryde
2              
3             # Perl-Critic-Pulp is free software; you can redistribute it and/or modify
4             # it under the terms of the GNU General Public License as published by the
5             # Free Software Foundation; either version 3, or (at your option) any later
6             # version.
7             #
8             # Perl-Critic-Pulp is distributed in the hope that it will be useful, but
9             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11             # for more details.
12             #
13             # You should have received a copy of the GNU General Public License along
14             # with Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses/>.
15              
16              
17             package Perl::Critic::Policy::CodeLayout::RequireTrailingCommaAtNewline;
18 40     40   32483 use 5.006;
  40         143  
19 40     40   191 use strict;
  40         84  
  40         669  
20 40     40   163 use warnings;
  40         82  
  40         903  
21 40     40   204 use List::Util;
  40         87  
  40         2279  
22              
23 40     40   233 use base 'Perl::Critic::Policy';
  40         80  
  40         4406  
24 40     40   171383 use Perl::Critic::Utils qw(is_function_call is_method_call);
  40         80  
  40         1866  
25 40     40   689 use Perl::Critic::Pulp::Utils 'elem_is_comma_operator';
  40         75  
  40         2961  
26              
27             # uncomment this to run the ### lines
28             #use Smart::Comments;
29              
30             our $VERSION = 97;
31              
32 40         2367 use constant supported_parameters =>
33             ({ name => 'except_function_calls',
34             description => 'Don\'t demand a trailing comma in function call argument lists.',
35             behavior => 'boolean',
36             default_string => '0',
37 40     40   240 });
  40         75  
38 40     40   242 use constant default_severity => $Perl::Critic::Utils::SEVERITY_LOW;
  40         96  
  40         2338  
39 40     40   227 use constant default_themes => qw(pulp cosmetic);
  40         80  
  40         2022  
40 40         25371 use constant applies_to => qw(PPI::Structure::List
41 40     40   215 PPI::Structure::Constructor);
  40         77  
42              
43             sub violates {
44 44     44 1 771486 my ($self, $elem, $document) = @_;
45             ### elem: ref($elem)
46             ### content: "$elem"
47              
48 44 100       201 if ($self->{'_except_function_calls'}) {
49 4         8 my $prev;
50 4 50 66     14 if (($prev = $elem->sprevious_sibling)
      66        
      66        
51             && $prev->isa('PPI::Token::Word')
52             && (is_function_call($prev) || is_method_call($prev))) {
53             ### is_function_call: !! is_function_call($prev)
54             ### is_method_call: !! is_method_call($prev)
55 3         612 return;
56             }
57             }
58              
59 41         234 my @children = $elem->children;
60 41 100       240 @children = map {$_->isa('PPI::Statement') ? $_->children : $_} @children;
  103         738  
61             ### children: "@children"
62              
63 41 100       122 if (_is_list_single_expression($elem)) {
64             ### an expression not a list as such ...
65 9         34 return;
66             }
67              
68 32         82 my $newline = 0;
69 32         47 my $after;
70 32         183 foreach my $child (reverse @children) {
71 84 100 100     365 if ($child->isa('PPI::Token::Whitespace')
72             || $child->isa('PPI::Token::Comment')) {
73             ### HWS ...
74 56   100     162 $newline ||= ($child->content =~ /\n/);
75             ### $newline
76 56         314 $after = $child;
77             } else {
78 28 100 100     89 if ($newline && ! elem_is_comma_operator($child)) {
79 18         130 return $self->violation
80             ('Put a trailing comma at last of a list ending with a newline',
81             '',
82             $after);
83             }
84 10         43 last;
85             }
86             }
87              
88 14         39 return;
89             }
90              
91             # $elem is any PPI::Element
92             # Return true if it's a PPI::Structure::List which contains just a single
93             # expression. Any "," or "=>" in the list is multiple expressions, but also
94             # the various rules of the policy are applied as to what is list context
95             # (array assignments, function calls).
96             #
97             sub _is_list_single_expression {
98 41     41   70 my ($elem) = @_;
99 41 100       115 $elem->isa('PPI::Structure::List')
100             or return 0;
101              
102 35         351 my @children = $elem->schildren;
103             {
104             # eg. PPI::Structure::List
105             # PPI::Statement::Expression
106             # PPI::Token::Number '1'
107             # PPI::Token::Operator ','
108             # so descend through PPI::Statement::Expression
109             #
110 35 50       345 @children = map { $_->isa('PPI::Statement::Expression')
  35         65  
  30         97  
111             ? ($_->schildren) : ($_)} @children;
112 35 100   47   449 if (List::Util::first {elem_is_comma_operator($_)} @children) {
  47         144  
113             ### contains comma operator, so not an expression ...
114 13         104 return 0;
115             }
116             }
117              
118 22 50       156 if (my $prev = $elem->sprevious_sibling) {
119 22 100 33     847 if ($prev->isa('PPI::Token::Word')) {
    100 66        
120 9 100       29 if ($prev eq 'return') {
121             ### return statement without commas, is reckoned a single expression ...
122 2         36 return 1;
123             }
124 7 50 66     108 if (is_function_call($prev)
125             || is_method_call($prev)) {
126             ### function or method call ...
127 7 100 100     2157 if ($children[-1] && $children[-1]->isa('PPI::Token::HereDoc')) {
128 2         8 return 1;
129             }
130 5         17 return 0;
131             }
132              
133             } elsif ($prev->isa('PPI::Token::Operator')
134             && $prev eq '='
135             && _is_preceded_by_array($prev)) {
136             ### array assignment, not a single expression ...
137 10 100 100     130 if ($children[-1] && $children[-1]->isa('PPI::Token::HereDoc')) {
138 2         7 return 1;
139             }
140 8         28 return 0;
141             }
142             }
143              
144             ### no commas, not a call, so is an expression
145 3         32 return 1;
146             }
147              
148             sub _is_preceded_by_array {
149 13     13   240 my ($elem) = @_;
150             ### _is_preceded_by_array: "$elem"
151              
152 13   50     37 my $prev = $elem->sprevious_sibling || return 0;
153 13   100     393 while ($prev->isa('PPI::Structure::Subscript')
154             || $prev->isa('PPI::Structure::Block')) {
155             ### skip: ref $prev
156 5   50     20 $prev = $prev->sprevious_sibling || return 0;
157             }
158             ### prev: ref $prev
159 13 100       236 if ($prev->isa('PPI::Token::Symbol')) {
160 12         20 my $cast;
161 12 100 66     73 if (($cast = $prev->sprevious_sibling)
162             && $cast->isa('PPI::Token::Cast')) {
163 1         23 return ($cast->content eq '@');
164             }
165             ### raw_type: $prev->raw_type
166 11         206 return ($prev->raw_type eq '@');
167             }
168 1 50       5 if ($prev->isa('PPI::Token::Cast')) {
169 1         4 return ($prev->content eq '@');
170             }
171 0           return 0;
172             }
173              
174             1;
175             __END__
176              
177             =for stopwords paren parens Parens hashref boolean Ryde runtime subr
178              
179             =head1 NAME
180              
181             Perl::Critic::Policy::CodeLayout::RequireTrailingCommaAtNewline - comma at end of list at newline
182              
183             =head1 DESCRIPTION
184              
185             This policy is part of the L<C<Perl::Critic::Pulp>|Perl::Critic::Pulp>
186             add-on. It asks you to put a comma at the end of a list etc when it ends
187             with a newline,
188              
189             @array = ($one,
190             $two # bad
191             );
192              
193             @array = ($one,
194             $two, # ok
195             );
196              
197             This makes no difference to how the code runs, so the policy is low severity
198             and under the "cosmetic" theme (see L<Perl::Critic/POLICY THEMES>).
199              
200             The idea is to make it easier when editing the code since you don't have to
201             remember to add a comma to a preceding item when extending or re-arranging
202             lines.
203              
204             If the closing bracket is on the same line as the last element then no comma
205             is required. It can be be present if desired, but is not required.
206              
207             $hashref = { abc => 123,
208             def => 456 }; # ok
209              
210             Parens around an expression are not a list, so nothing is demanded in for
211             instance
212              
213             $foo = (
214             1
215             + 2 # ok, an expression not a list
216             );
217              
218             But a single element paren expression is a list when it's in an array
219             assignment or a function or method call.
220              
221             @foo = (
222             1
223             + 2 # bad, list of one value
224             );
225            
226              
227             @foo = (
228             1
229             + 2, # ok
230             );
231              
232             =head2 Return Statement
233              
234             A C<return> statement with a single value is considered an expression so a
235             trailing comma is not required.
236              
237             return ($x
238             + $y # ok
239             );
240              
241             Whether such code is a single-value expression or a list of only one value
242             depends on how the function is specified. There's nothing in the text (nor
243             even at runtime) which would say for sure.
244              
245             It's handy to included parens around a single-value expression to make it
246             clear some big arithmetic is all part of the return, especially if you can't
247             remember precedence levels. In such an expression a newline before the
248             final ")" can help keep a comment together with a term for a cut and paste,
249             or not lose a paren if commenting the last line, etc. So for now the policy
250             is lenient. Would an option be good though?
251              
252             =head2 Here Documents
253              
254             An exception is made for a single expression ending with a here-document.
255             This is slightly experimental, and might become an option, but the idea is
256             that a newline is necessary for a here-document within parens and so
257             shouldn't demand a comma.
258              
259             foo(<<HERE # ok
260             some text
261             HERE
262             );
263              
264             This style is a little unusual but some people like the whole here-document
265             at the place its string result will expand. If the code is all on one line
266             (see L<perlop/E<lt>E<lt>EOF>) then trailing comma considerations don't
267             apply. But both forms work and so are a matter of personal preference.
268              
269             foo(<<HERE);
270             some text
271             HERE
272              
273             Multiple values still require a final comma. Multiple values suggests a
274             list and full commas guards against forgetting to add a comma if extending
275             or rearranging.
276              
277             foo(<<HERE,
278             one
279             HERE
280             <<HERE # bad
281             two
282             HERE
283             );
284              
285             =head2 Disabling
286              
287             If you don't care about trailing commas like this you can as always disable
288             from F<.perlcriticrc> in the usual way (see L<Perl::Critic/CONFIGURATION>),
289              
290             [-CodeLayout::RequireTrailingCommaAtNewline]
291              
292             =head1 CONFIGURATION
293              
294             =over 4
295              
296             =item C<except_function_calls> (boolean, default false)
297              
298             If true then function calls and method calls are not checked, allowing for
299             instance
300              
301             foo (
302             1,
303             2 # ok under except_function_calls
304             );
305              
306             The idea is that if C<foo()> takes only two arguments then you don't want to
307             write a trailing comma as it might suggest something more could be added.
308              
309             Whether you write calls spread out this way is a matter of personal
310             preference. If you do then enable C<except_function_calls> with the
311             following in your F<.perlcriticrc> file,
312              
313             [CodeLayout::RequireTrailingCommaAtNewline]
314             except_function_calls=1
315              
316             =back
317              
318             =head1 SEE ALSO
319              
320             L<Perl::Critic::Pulp>,
321             L<Perl::Critic>,
322             L<Perl::Critic::Policy::CodeLayout::RequireTrailingCommas>
323              
324             =head2 Other Ways to Do It
325              
326             This policy is a variation of C<CodeLayout::RequireTrailingCommas>. That
327             policy doesn't apply to function calls or hashref constructors, and you may
328             find its requirement for a trailing comma in even one-line lists like
329             C<@x=(1,2,)> too much.
330              
331             =head1 HOME PAGE
332              
333             L<http://user42.tuxfamily.org/perl-critic-pulp/index.html>
334              
335             =head1 COPYRIGHT
336              
337             Copyright 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Kevin Ryde
338              
339             Perl-Critic-Pulp is free software; you can redistribute it and/or modify it
340             under the terms of the GNU General Public License as published by the Free
341             Software Foundation; either version 3, or (at your option) any later
342             version.
343              
344             Perl-Critic-Pulp is distributed in the hope that it will be useful, but
345             WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
346             or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
347             more details.
348              
349             You should have received a copy of the GNU General Public License along with
350             Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses>.
351              
352             =cut