File Coverage

blib/lib/Perl/Critic/Policy/Variables/RequireLocalizedPunctuationVars.pm
Criterion Covered Total %
statement 45 45 100.0
branch 22 24 91.6
condition 12 12 100.0
subroutine 13 13 100.0
pod 4 5 80.0
total 96 99 96.9


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Variables::RequireLocalizedPunctuationVars;
2              
3 40     40   27325 use 5.010001;
  40         183  
4 40     40   278 use strict;
  40         128  
  40         946  
5 40     40   280 use warnings;
  40         127  
  40         967  
6 40     40   245 use Readonly;
  40         136  
  40         2182  
7              
8 40     40   275 use Perl::Critic::Utils qw{ :severities :classification $EMPTY hashify};
  40         127  
  40         2033  
9 40     40   13921 use parent 'Perl::Critic::Policy';
  40         132  
  40         296  
10              
11             our $VERSION = '1.146';
12              
13             #-----------------------------------------------------------------------------
14              
15             Readonly::Scalar my $PACKAGE_RX => qr/::/xms;
16             Readonly::Hash my %EXCEPTIONS => hashify(qw(
17             $_
18             $ARG
19             @_
20             ));
21             Readonly::Scalar my $DESC => q{Magic variable "%s" should be assigned as "local"};
22             Readonly::Scalar my $EXPL => [ 81, 82 ];
23              
24             #-----------------------------------------------------------------------------
25              
26             sub supported_parameters {
27             return (
28             {
29 105     105 0 2411 name => 'allow',
30             description =>
31             q<Global variables to exclude from this policy.>,
32             default_string => $EMPTY,
33             behavior => 'string list',
34             list_always_present_values => [ qw< $_ $ARG @_ > ],
35             },
36             );
37             }
38              
39 590     590 1 2210 sub default_severity { return $SEVERITY_HIGH }
40 92     92 1 458 sub default_themes { return qw(core pbp bugs certrec ) }
41 47     47 1 214 sub applies_to { return 'PPI::Token::Operator' }
42              
43             #-----------------------------------------------------------------------------
44              
45             sub violates {
46 1774     1774 1 4180 my ( $self, $elem, undef ) = @_;
47              
48 1774 100       4620 return if $elem->content() ne q{=};
49              
50 1743         10925 my $destination = $elem->sprevious_sibling;
51 1743 50       51360 return if !$destination; # huh? assignment in void context??
52 1743         6748 while ($destination->isa('PPI::Structure::Subscript')) {
53 46 50       143 $destination = $destination->sprevious_sibling()
54             or return;
55             }
56              
57 1743 100       10812 if (my $var = $self->_is_non_local_magic_dest($destination)) {
58 516         2335 return $self->violation( sprintf( $DESC, $var ), $EXPL, $elem );
59             }
60 1227         9384 return; # OK
61             }
62              
63             sub _is_non_local_magic_dest {
64 3281     3281   6850 my ($self, $elem) = @_;
65              
66             # Quick exit if in good form
67 3281         8305 my $modifier = $elem->sprevious_sibling;
68             return
69             if
70 3281 100 100     69891 $modifier
      100        
      100        
71             && $modifier->isa('PPI::Token::Word')
72             && ($modifier->content() eq 'local'
73             || $modifier->content() eq 'my');
74              
75             # Implementation note: Can't rely on PPI::Token::Magic,
76             # unfortunately, because we need English too
77              
78 2573 100 100     11927 if ($elem->isa('PPI::Token::Symbol')) {
    100          
79 1035 100       2736 return $self->_is_magic_var($elem) ? $elem : undef;
80             }
81             elsif (
82             $elem->isa('PPI::Structure::List')
83             or $elem->isa('PPI::Statement::Expression')
84             ) {
85 1228         10217 for my $child ($elem->schildren) {
86 1538         13544 my $var = $self->_is_non_local_magic_dest($child);
87 1538 100       6256 return $var if $var;
88             }
89             }
90              
91 930         2123 return;
92             }
93              
94             #-----------------------------------------------------------------------------
95              
96             sub _is_magic_var {
97 1035     1035   2132 my ($self, $elem) = @_;
98              
99 1035         2936 my $variable_name = $elem->symbol();
100 1035 100       46148 return if $self->{_allow}{$variable_name};
101 880 100       3874 return 1 if $elem->isa('PPI::Token::Magic'); # optimization(?), and
102             # helps with PPI 1.118 carat
103             # bug. This bug is gone as of
104             # 1.208, which is required for
105             # P::C 1.113. RT 65514
106 624 100       2031 return if not is_perl_global( $elem );
107              
108 260         3091 return 1;
109             }
110              
111             1;
112              
113             __END__
114              
115             #-----------------------------------------------------------------------------
116              
117             =pod
118              
119             =head1 NAME
120              
121             Perl::Critic::Policy::Variables::RequireLocalizedPunctuationVars - Magic variables should be assigned as "local".
122              
123              
124             =head1 AFFILIATION
125              
126             This Policy is part of the core L<Perl::Critic|Perl::Critic>
127             distribution.
128              
129              
130             =head1 DESCRIPTION
131              
132             Punctuation variables (and their English.pm equivalents) are global
133             variables. Messing with globals is dangerous in a complex program as
134             it can lead to very subtle and hard to fix bugs. If you must change a
135             magic variable in a non-trivial program, do it in a local scope.
136              
137             For example, to slurp a filehandle into a scalar, it's common to set
138             the record separator to undef instead of a newline. If you choose to
139             do this (instead of using L<Path::Tiny|Path::Tiny>!) then be sure to
140             localize the global and change it for as short a time as possible.
141              
142             # BAD:
143             $/ = undef;
144             my $content = <$fh>;
145              
146             # BETTER:
147             my $content;
148             {
149             local $/ = undef;
150             $content = <$fh>;
151             }
152              
153             # A popular idiom:
154             my $content = do { local $/ = undef; <$fh> };
155              
156             This policy also allows the use of C<my>. Perl prevents using C<my>
157             with "proper" punctuation variables, but allows C<$a>, C<@ARGV>, the
158             names declared by L<English|English>, etc. This is not a good coding
159             practice, however it is not the concern of this specific policy to
160             complain about that.
161              
162             There are exemptions for C<$_> and C<@_>, and the English equivalent
163             C<$ARG>.
164              
165              
166             =head1 CONFIGURATION
167              
168             You can configure your own exemptions using the C<allow> option:
169              
170             [Variables::RequireLocalizedPunctuationVars]
171             allow = @ARGV $ARGV
172              
173             These are added to the default exemptions.
174              
175              
176             =head1 CREDITS
177              
178             Initial development of this policy was supported by a grant from the
179             Perl Foundation.
180              
181              
182             =head1 AUTHOR
183              
184             Chris Dolan <cdolan@cpan.org>
185              
186              
187             =head1 COPYRIGHT
188              
189             Copyright (c) 2007-2011 Chris Dolan. Many rights reserved.
190              
191             This program is free software; you can redistribute it and/or modify
192             it under the same terms as Perl itself. The full text of this license
193             can be found in the LICENSE file included with this module.
194              
195             =cut
196              
197             # Local Variables:
198             # mode: cperl
199             # cperl-indent-level: 4
200             # fill-column: 78
201             # indent-tabs-mode: nil
202             # c-indentation-style: bsd
203             # End:
204             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :