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   27459 use 5.010001;
  40         185  
4 40     40   302 use strict;
  40         108  
  40         895  
5 40     40   243 use warnings;
  40         118  
  40         1089  
6              
7 40     40   236 use Readonly;
  40         127  
  40         2137  
8              
9 40     40   309 use List::SomeUtils qw(all);
  40         131  
  40         2171  
10              
11 40         2193 use Perl::Critic::Utils qw{
12             :booleans :characters :severities :data_conversion
13 40     40   292 };
  40         137  
14 40     40   14313 use parent 'Perl::Critic::Policy';
  40         114  
  40         245  
15              
16             our $VERSION = '1.146';
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 2447 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 420 sub default_severity { return $SEVERITY_MEDIUM }
43 86     86 1 444 sub default_themes { return qw(core pbp maintenance) }
44 39     39 1 152 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 317 my ($self, $config) = @_;
52              
53             $self->{_all_packages} = {
54 63         164 hashify keys %{ $self->{_packages} }, keys %{ $self->{_add_packages} }
  63         441  
  63         339  
55             };
56              
57 63         378 return $TRUE;
58             }
59              
60             #-----------------------------------------------------------------------------
61              
62             sub violates {
63 389     389 1 766 my ( $self, $elem, undef ) = @_;
64              
65 389 100 100     858 if ( $self->_is_package_var($elem) ||
      100        
66             _is_our_var($elem) ||
67             _is_vars_pragma($elem) )
68             {
69              
70 22         99 return $self->violation( $DESC, $EXPL, $elem );
71             }
72              
73 367         2966 return; # ok
74             }
75              
76             #-----------------------------------------------------------------------------
77              
78             sub _is_package_var {
79 389     389   652 my $self = shift;
80 389         608 my $elem = shift;
81 389 100       1369 return if !$elem->isa('PPI::Token::Symbol');
82 221         511 my ($package, $name) = $elem =~ m{ \A [@\$%] (.*) :: (\w+) \z }xms;
83 221 100       1595 return if not defined $package;
84 27 100       69 return if _all_upcase( $name );
85 21 100       127 return if $self->{_all_packages}->{$package};
86 13         47 return 1;
87             }
88              
89             #-----------------------------------------------------------------------------
90              
91             sub _is_our_var {
92 376     376   704 my $elem = shift;
93 376 100       1626 return if not $elem->isa('PPI::Statement::Variable');
94 96 100       295 return if $elem->type() ne 'our';
95 34 100       1512 return if _all_upcase( $elem->variables() );
96 3         19 return 1;
97             }
98              
99             #-----------------------------------------------------------------------------
100              
101             sub _is_vars_pragma {
102 373     373   2873 my $elem = shift;
103 373 100       1559 return if !$elem->isa('PPI::Statement::Include');
104 72 100       256 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         333 my @varnames = $elem =~ m{ [@\$%&] (\w+) }gxms;
113              
114 9 100       456 return if !@varnames; # no valid variables specified
115 8 100       23 return if _all_upcase( @varnames );
116 6         67 return 1;
117             }
118              
119             sub _all_upcase { ##no critic(ArgUnpacking)
120 75     75   543 return all { $_ eq uc $_ } @_; ## no critic ( BuiltinFunctions::ProhibitUselessTopic )
  69     69   2478  
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 :