File Coverage

blib/lib/Perl/Critic/Policy/Variables/ProhibitPackageVars.pm
Criterion Covered Total %
statement 50 55 90.9
branch 15 24 62.5
condition 4 6 66.6
subroutine 18 18 100.0
pod 5 6 83.3
total 92 109 84.4


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Variables::ProhibitPackageVars;
2              
3 40     40   26667 use 5.010001;
  40         165  
4 40     40   288 use strict;
  40         136  
  40         855  
5 40     40   223 use warnings;
  40         115  
  40         986  
6              
7 40     40   242 use Readonly;
  40         136  
  40         1926  
8              
9 40     40   303 use List::SomeUtils qw(all);
  40         137  
  40         1994  
10              
11 40         2032 use Perl::Critic::Utils qw{
12             :booleans :characters :severities :data_conversion
13 40     40   287 };
  40         117  
14 40     40   13905 use parent 'Perl::Critic::Policy';
  40         113  
  40         254  
15              
16             our $VERSION = '1.150';
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 91     91 0 2329 name => 'packages',
29             description => 'The base set of packages to allow variables for.',
30             default_string => 'Data::Dumper File::Find FindBin Log::Log4perl Test::Builder Text::Wrap',
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 75     75 1 630 sub default_severity { return $SEVERITY_MEDIUM }
43 86     86 1 335 sub default_themes { return qw(core pbp maintenance) }
44 30     30 1 116 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 54     54 1 185 my ($self, $config) = @_;
52              
53             $self->{_all_packages} = {
54 54         193 hashify keys %{ $self->{_packages} }, keys %{ $self->{_add_packages} }
  54         424  
  54         264  
55             };
56              
57 54         271 return $TRUE;
58             }
59              
60             #-----------------------------------------------------------------------------
61              
62             sub violates {
63 314     314 1 472 my ( $self, $elem, undef ) = @_;
64              
65 314 50 66     549 if ( $self->_is_package_var($elem) ||
      66        
66             _is_our_var($elem) ||
67             _is_vars_pragma($elem) )
68             {
69              
70 1         13 return $self->violation( $DESC, $EXPL, $elem );
71             }
72              
73 313         2138 return; # ok
74             }
75              
76             #-----------------------------------------------------------------------------
77              
78             sub _is_package_var {
79 314     314   459 my $self = shift;
80 314         389 my $elem = shift;
81 314 100       862 return if !$elem->isa('PPI::Token::Symbol');
82 172         297 my ($package, $name) = $elem =~ m{ \A [@\$%] (.*) :: (\w+) \z }xms;
83 172 100       951 return if not defined $package;
84 1 50       8 return if _all_upcase( $name );
85 1 50       6 return if $self->{_all_packages}->{$package};
86 1         4 return 1;
87             }
88              
89             #-----------------------------------------------------------------------------
90              
91             sub _is_our_var {
92 313     313   439 my $elem = shift;
93 313 100       1175 return if not $elem->isa('PPI::Statement::Variable');
94 85 100       212 return if $elem->type() ne 'our';
95 27 50       1066 return if _all_upcase( $elem->variables() );
96 0         0 return 1;
97             }
98              
99             #-----------------------------------------------------------------------------
100              
101             sub _is_vars_pragma {
102 313     313   2078 my $elem = shift;
103 313 100       1011 return if !$elem->isa('PPI::Statement::Include');
104 57 50       161 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 0         0 my @varnames = $elem =~ m{ [@\$%&] (\w+) }gxms;
113              
114 0 0       0 return if !@varnames; # no valid variables specified
115 0 0       0 return if _all_upcase( @varnames );
116 0         0 return 1;
117             }
118              
119             sub _all_upcase { ##no critic(ArgUnpacking)
120 28     28   278 return all { $_ eq uc } @_;
  28     28   1375  
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-2023 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 :