File Coverage

blib/lib/Perl/Critic/Policy/Variables/ProhibitTopicIterator.pm
Criterion Covered Total %
statement 63 74 85.1
branch 32 44 72.7
condition 4 9 44.4
subroutine 13 13 100.0
pod 4 5 80.0
total 116 145 80.0


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Variables::ProhibitTopicIterator;
2              
3 5     5   954775 use 5.010001;
  5         19  
4 5     5   25 use strict;
  5         9  
  5         97  
5 5     5   18 use warnings;
  5         8  
  5         250  
6 5     5   24 use Readonly;
  5         9  
  5         318  
7              
8 5     5   36 use Perl::Critic::Utils qw/:severities :classification/;
  5         6  
  5         408  
9 5     5   1953 use base 'Perl::Critic::Policy';
  5         10  
  5         2875  
10              
11             our $VERSION = '0.0.7';
12              
13             Readonly::Scalar my $DESC => q{Always use named loop control variables};
14             Readonly::Scalar my $EXPL => undef; # [ ];
15              
16             #-----------------------------------------------------------------------------
17              
18 28     28 1 245547 sub applies_to { return 'PPI::Statement::Compound' }
19 8     8 1 119 sub default_severity { return $SEVERITY_LOW }
20 2     2 1 6361 sub default_themes { return qw/maintenance complexity/ }
21 2     2 0 1798330 sub supported_parameters { return }
22              
23             #-----------------------------------------------------------------------------
24              
25             sub violates {
26 24     24 1 780 my ($self,$elem,undef)=@_;
27 24 50       192 if(!$elem->isa('PPI::Statement::Compound')) { return }
  0         0  
28 24         115 my $node=$elem->first_element();
29 24 50       181 if(!$node->isa('PPI::Token::Word')) { return }
  0         0  
30 24         138 my $type=$node->content();
31 24         181 my $next=$node->snext_sibling();
32 24 50       932 if(!$next) { return } # invalid syntax?
  0         0  
33             #
34 24 100 33     201 if($type=~/^for(?:each)?$/) {
    50          
35 18 100       95 if($next->isa('PPI::Structure::List')) { return $self->violation($DESC,$EXPL,$elem) }
  2         25  
36 16 100 66     149 if($next->isa('PPI::Token::Magic')&&($next->content() eq '$_')) { return $self->violation($DESC,$EXPL,$elem) }
  2         22  
37 14 100       100 if($next->isa('PPI::Structure::For')) {
38 6 100       86 if($next->find_first(sub {
39 36     36   572 my (undef,$e)=@_;
40 36 100       174 if(!$e->isa('PPI::Token::Magic')) { return 0 }
  34         79  
41 2 50       10 if($e->content() ne '$_') { return 0 }
  0         0  
42 2         23 my $ne=$e->snext_sibling();
43 2 50       89 if(!$ne) { return 0 }
  0         0  
44 2 50       11 if(!$ne->isa('PPI::Token::Operator')) { return 0 }
  0         0  
45 2 50       8 if($ne->content() ne '=') { return 0 }
  0         0  
46 2         13 return 1;
47 2         84 })) { return $self->violation($DESC,$EXPL,$elem) }
48 4         98 return;
49             }
50 8 100       47 if($next->isa('PPI::Token::Symbol')) { return }
  4         17  
51 4 50 33     30 if($next->isa('PPI::Token::Word')&&($next->content() eq 'my')) { return }
  4         42  
52             }
53             elsif(($type=~/^(?:if|while)$/)&&$next->isa('PPI::Structure::Condition')) {
54 6 100       65 if($next->find_first(sub {
55 32     32   524 my (undef,$e)=@_;
56 32 100       142 if(!$e->isa('PPI::Token::Magic')) { return 0 }
  29         81  
57 3 50       13 if($e->content() ne '$_') { return 0 }
  0         0  
58 3         26 my $ne=$e->snext_sibling();
59 3 50       101 if(!$ne) { return 0 }
  0         0  
60 3 50       14 if(!$ne->isa('PPI::Token::Operator')) { return 0 }
  0         0  
61 3 100       11 if($ne->content() ne '=') { return 0 }
  1         15  
62 2         13 return 1;
63 2         37 })) { return $self->violation($DESC,$EXPL,$elem) }
64 4         93 return;
65             }
66 0           return;
67             }
68              
69             #-----------------------------------------------------------------------------
70              
71             1;
72              
73             __END__
74              
75             =pod
76              
77             =head1 NAME
78              
79             Perl::Critic::Policy::Variables::ProhibitTopicIterator - Use named loop control variables.
80              
81             =head1 DESCRIPTION
82              
83             Loops with no named variable become a maintenance concern as the loop complexity grows. Larger, multi-line, and nested loops can lead to programmer confusion about the true meaning of C<$_>. To ensure long-term maintainability of code, named variables are recommended for all loops.
84              
85             This policy considers any loop control without a named variable to be a violation.
86              
87             Moreover, if/while statements that assign directly to C<$_> are considered a violation.
88              
89             foreach my $i (1..3) { ... } # ok
90             for(my $i=1;$i<=3;$i++) { ... } # ok
91             for my $i (1..3) { ... } # ok
92             if(my $i=shift(@A)) { ... } # ok
93             while(my $i=shift(@A)) { ... } # ok
94              
95             foreach (1..3) { ... } # not ok
96             for($_=1;$_<=3;$_++) { ... } # not ok
97             for (1..3) { ... } # not ok
98             if($_=shift(@A)) { ... } # not ok
99             while($_=shift(@A)) { ... } # not ok
100              
101             =head1 CONFIGURATION
102              
103             None at this time, but future configuration may make the policy I<less> aggressive about certain constructions.
104              
105             =head1 NOTES
106              
107             Post-conditionals can be enforced with L<Perl::Critic::Policy::ControlStructures::ProhibitPostfixControls>.
108              
109             =cut