File Coverage

blib/lib/Perl/Critic/Policy/Variables/ProhibitPackageVars.pm
Criterion Covered Total %
statement 55 55 100.0
branch 24 24 100.0
condition 6 6 100.0
subroutine 18 18 100.0
pod 5 6 83.3
total 108 109 99.0


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Variables::ProhibitPackageVars;
2              
3 40     40   27671 use 5.010001;
  40         159  
4 40     40   264 use strict;
  40         115  
  40         864  
5 40     40   214 use warnings;
  40         110  
  40         988  
6              
7 40     40   236 use Readonly;
  40         104  
  40         2147  
8              
9 40     40   281 use List::SomeUtils qw(all);
  40         131  
  40         1990  
10              
11 40         1999 use Perl::Critic::Utils qw{
12             :booleans :characters :severities :data_conversion
13 40     40   271 };
  40         123  
14 40     40   13976 use parent 'Perl::Critic::Policy';
  40         163  
  40         259  
15              
16             our $VERSION = '1.148';
17              
18             #-----------------------------------------------------------------------------
19              
20             Readonly::Scalar my $DESC => q{Package variable declared or used};
21             Readonly::Scalar my $EXPL => [ 73, 75 ];
22              
23             #-----------------------------------------------------------------------------
24              
25             sub supported_parameters {
26             return (
27             {
28 100     100 0 2427 name => 'packages',
29             description => 'The base set of packages to allow variables for.',
30             default_string => 'Data::Dumper File::Find FindBin Log::Log4perl',
31             behavior => 'string list',
32             },
33             {
34             name => 'add_packages',
35             description => 'The set of packages to allow variables for, in addition to those given in "packages".',
36             default_string => $EMPTY,
37             behavior => 'string list',
38             },
39             );
40             }
41              
42 96     96 1 413 sub default_severity { return $SEVERITY_MEDIUM }
43 86     86 1 360 sub default_themes { return qw(core pbp maintenance) }
44 39     39 1 172 sub applies_to { return qw(PPI::Token::Symbol
45             PPI::Statement::Variable
46             PPI::Statement::Include) }
47              
48             #-----------------------------------------------------------------------------
49              
50             sub initialize_if_enabled {
51 63     63 1 238 my ($self, $config) = @_;
52              
53             $self->{_all_packages} = {
54 63         192 hashify keys %{ $self->{_packages} }, keys %{ $self->{_add_packages} }
  63         374  
  63         337  
55             };
56              
57 63         328 return $TRUE;
58             }
59              
60             #-----------------------------------------------------------------------------
61              
62             sub violates {
63 389     389 1 753 my ( $self, $elem, undef ) = @_;
64              
65 389 100 100     824 if ( $self->_is_package_var($elem) ||
      100        
66             _is_our_var($elem) ||
67             _is_vars_pragma($elem) )
68             {
69              
70 22         107 return $self->violation( $DESC, $EXPL, $elem );
71             }
72              
73 367         2962 return; # ok
74             }
75              
76             #-----------------------------------------------------------------------------
77              
78             sub _is_package_var {
79 389     389   636 my $self = shift;
80 389         571 my $elem = shift;
81 389 100       1347 return if !$elem->isa('PPI::Token::Symbol');
82 221         556 my ($package, $name) = $elem =~ m{ \A [@\$%] (.*) :: (\w+) \z }xms;
83 221 100       1579 return if not defined $package;
84 27 100       63 return if _all_upcase( $name );
85 21 100       103 return if $self->{_all_packages}->{$package};
86 13         42 return 1;
87             }
88              
89             #-----------------------------------------------------------------------------
90              
91             sub _is_our_var {
92 376     376   702 my $elem = shift;
93 376 100       1731 return if not $elem->isa('PPI::Statement::Variable');
94 96 100       327 return if $elem->type() ne 'our';
95 34 100       1585 return if _all_upcase( $elem->variables() );
96 3         19 return 1;
97             }
98              
99             #-----------------------------------------------------------------------------
100              
101             sub _is_vars_pragma {
102 373     373   2968 my $elem = shift;
103 373 100       1587 return if !$elem->isa('PPI::Statement::Include');
104 72 100       261 return if $elem->pragma() ne 'vars';
105              
106             # Older Perls don't support the C<our> keyword, so we try to let
107             # people use the C<vars> pragma instead, but only if all the
108             # variable names are uppercase. Since there are lots of ways to
109             # pass arguments to pragmas (e.g. "$foo" or qw($foo) ) we just use
110             # a regex to match things that look like variables names.
111              
112 9         430 my @varnames = $elem =~ m{ [@\$%&] (\w+) }gxms;
113              
114 9 100       471 return if !@varnames; # no valid variables specified
115 8 100       26 return if _all_upcase( @varnames );
116 6         33 return 1;
117             }
118              
119             sub _all_upcase { ##no critic(ArgUnpacking)
120 75     75   535 return all { $_ eq uc $_ } @_; ## no critic ( BuiltinFunctions::ProhibitUselessTopic )
  69     69   2438  
121             }
122              
123             1;
124              
125             __END__
126              
127             #-----------------------------------------------------------------------------
128              
129             =pod
130              
131             =head1 NAME
132              
133             Perl::Critic::Policy::Variables::ProhibitPackageVars - Eliminate globals declared with C<our> or C<use vars>.
134              
135              
136             =head1 AFFILIATION
137              
138             This Policy is part of the core L<Perl::Critic|Perl::Critic>
139             distribution.
140              
141              
142             =head1 DESCRIPTION
143              
144             Conway suggests avoiding package variables completely, because they
145             expose your internals to other packages. Never use a package variable
146             when a lexical variable will suffice. If your package needs to keep
147             some dynamic state, consider using an object or closures to keep the
148             state private.
149              
150             This policy assumes that you're using C<strict vars> so that naked
151             variable declarations are not package variables by default. Thus, it
152             complains you declare a variable with C<our> or C<use vars>, or if you
153             make reference to variable with a fully-qualified package name.
154              
155             $Some::Package::foo = 1; # not ok
156             our $foo = 1; # not ok
157             use vars '$foo'; # not ok
158             $foo = 1; # not allowed by 'strict'
159             local $foo = 1; # bad taste, but technically ok.
160             use vars '$FOO'; # ok, because it's ALL CAPS
161             my $foo = 1; # ok
162              
163             In practice though, its not really practical to prohibit all package
164             variables. Common variables like C<$VERSION> and C<@EXPORT> need to
165             be global, as do any variables that you want to Export. To work
166             around this, the Policy overlooks any variables that are in ALL_CAPS.
167             This forces you to put all your exported variables in ALL_CAPS too,
168             which seems to be the usual practice anyway.
169              
170              
171             =head1 CONFIGURATION
172              
173             There is room for exceptions. Some modules, like the core File::Find
174             module, use package variables as their only interface, and others like
175             Data::Dumper use package variables as their most common interface.
176             These module can be specified from your F<.perlcriticrc> file, and the
177             policy will ignore them.
178              
179             [Variables::ProhibitPackageVars]
180             packages = Data::Dumper File::Find FindBin Log::Log4perl
181              
182             This is the default setting. Using C<packages => will override these
183             defaults.
184              
185             You can also add packages to the defaults like so:
186              
187             [Variables::ProhibitPackageVars]
188             add_packages = My::Package
189              
190             You can add package C<main> to the list of packages, but that will
191             only OK variables explicitly in the C<main> package.
192              
193              
194             =head1 SEE ALSO
195              
196             L<Perl::Critic::Policy::Variables::ProhibitPunctuationVars|Perl::Critic::Policy::Variables::ProhibitPunctuationVars>
197              
198             L<Perl::Critic::Policy::Variables::ProhibitLocalVars|Perl::Critic::Policy::Variables::ProhibitLocalVars>
199              
200              
201             =head1 AUTHOR
202              
203             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
204              
205              
206             =head1 COPYRIGHT
207              
208             Copyright (c) 2005-2021 Imaginative Software Systems. All rights reserved.
209              
210             This program is free software; you can redistribute it and/or modify
211             it under the same terms as Perl itself. The full text of this license
212             can be found in the LICENSE file included with this module.
213              
214             =cut
215              
216             # Local Variables:
217             # mode: cperl
218             # cperl-indent-level: 4
219             # fill-column: 78
220             # indent-tabs-mode: nil
221             # c-indentation-style: bsd
222             # End:
223             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :