1 ##############################################################################
2 # $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/Perl-Critic/lib/Perl/Critic/Policy/Variables/ProhibitPackageVars.pm $
3 # $Date: 2008-07-03 10:19:10 -0500 (Thu, 03 Jul 2008) $
6 ##############################################################################
8 package Perl::Critic::Policy::Variables::ProhibitPackageVars;
17 use List::MoreUtils qw(all);
19 use Perl::Critic::Utils qw{
20 :booleans :characters :severities :data_conversion
22 use base 'Perl::Critic::Policy';
24 our $VERSION = '1.088';
26 #-----------------------------------------------------------------------------
28 Readonly::Scalar my $DESC => q{Package variable declared or used};
29 Readonly::Scalar my $EXPL => [ 73, 75 ];
31 #-----------------------------------------------------------------------------
33 sub supported_parameters {
37 description => 'The base set of packages to allow variables for.',
38 default_string => 'File::Find Data::Dumper',
39 behavior => 'string list',
42 name => 'add_packages',
43 description => 'The set of packages to allow variables for, in addition to those given in "packages".',
44 default_string => $EMPTY,
45 behavior => 'string list',
50 sub default_severity { return $SEVERITY_MEDIUM }
51 sub default_themes { return qw(core pbp maintenance) }
52 sub applies_to { return qw(PPI::Token::Symbol
53 PPI::Statement::Variable
54 PPI::Statement::Include) }
56 Readonly::Array our @DEFAULT_PACKAGE_EXCEPTIONS =>
57 qw( File::Find Data::Dumper );
59 #-----------------------------------------------------------------------------
61 sub initialize_if_enabled {
62 my ($self, $config) = @_;
64 $self->{_all_packages} = {
65 hashify keys %{ $self->{_packages} }, keys %{ $self->{_add_packages} }
71 #-----------------------------------------------------------------------------
74 my ( $self, $elem, undef ) = @_;
76 if ( $self->_is_package_var($elem) ||
78 _is_vars_pragma($elem) )
81 return $self->violation( $DESC, $EXPL, $elem );
87 #-----------------------------------------------------------------------------
92 return if !$elem->isa('PPI::Token::Symbol');
93 my ($package, $name) = $elem =~ m{ \A [@\$%] (.*) :: (\w+) \z }mx;
94 return if not defined $package;
95 return if _all_upcase( $name );
96 return if $self->{_all_packages}->{$package};
100 #-----------------------------------------------------------------------------
104 return if not $elem->isa('PPI::Statement::Variable');
105 return if $elem->type() ne 'our';
106 return if _all_upcase( $elem->variables() );
110 #-----------------------------------------------------------------------------
112 sub _is_vars_pragma {
114 return if !$elem->isa('PPI::Statement::Include');
115 return if $elem->pragma() ne 'vars';
117 # Older Perls don't support the C<our> keyword, so we try to let
118 # people use the C<vars> pragma instead, but only if all the
119 # variable names are uppercase. Since there are lots of ways to
120 # pass arguments to pragmas (e.g. "$foo" or qw($foo) ) we just use
121 # a regex to match things that look like variables names.
123 my @varnames = $elem =~ m{ [@\$%&] (\w+) }gmx;
125 return if !@varnames; # no valid variables specified
126 return if _all_upcase( @varnames );
130 sub _all_upcase { ##no critic(ArgUnpacking)
131 return all { $_ eq uc $_ } @_;
138 #-----------------------------------------------------------------------------
144 Perl::Critic::Policy::Variables::ProhibitPackageVars - Eliminate globals declared with C<our> or C<use vars>.
148 This Policy is part of the core L<Perl::Critic> distribution.
153 Conway suggests avoiding package variables completely, because they
154 expose your internals to other packages. Never use a package variable
155 when a lexical variable will suffice. If your package needs to keep
156 some dynamic state, consider using an object or closures to keep the
159 This policy assumes that you're using C<strict vars> so that naked
160 variable declarations are not package variables by default. Thus, it
161 complains you declare a variable with C<our> or C<use vars>, or if you
162 make reference to variable with a fully-qualified package name.
164 $Some::Package::foo = 1; #not ok
165 our $foo = 1; #not ok
166 use vars '$foo'; #not ok
167 $foo = 1; #not allowed by 'strict'
168 local $foo = 1; #bad taste, but technically ok.
169 use vars '$FOO'; #ok, because it's ALL CAPS
172 In practice though, its not really practical to prohibit all package
173 variables. Common variables like C<$VERSION> and C<@EXPORT> need to
174 be global, as do any variables that you want to Export. To work
175 around this, the Policy overlooks any variables that are in ALL_CAPS.
176 This forces you to put all your exported variables in ALL_CAPS too, which
177 seems to be the usual practice anyway.
181 There is room for exceptions. Some modules, like the core File::Find
182 module, use package variables as their only interface, and others
183 like Data::Dumper use package variables as their most common
184 interface. These module can be specified from your F<.perlcriticrc>
185 file, and the policy will ignore them.
187 [Variables::ProhibitPackageVars]
188 packages = File::Find Data::Dumper
190 This is the default setting. Using C<packages => will override
193 You can also add packages to the defaults like so:
195 [Variables::ProhibitPackageVars]
196 add_packages = My::Package
198 You can add package C<main> to the list of packages, but that will
199 only OK variables explicitly in the C<main> package.
203 L<Perl::Critic::Policy::Variables::ProhibitPunctuationVars>
205 L<Perl::Critic::Policy::Variables::ProhibitLocalVars>
209 Jeffrey Ryan Thalhammer <thaljef@cpan.org>
213 Copyright (c) 2005-2008 Jeffrey Ryan Thalhammer. All rights reserved.
215 This program is free software; you can redistribute it and/or modify
216 it under the same terms as Perl itself. The full text of this license
217 can be found in the LICENSE file included with this module.
223 # cperl-indent-level: 4
225 # indent-tabs-mode: nil
226 # c-indentation-style: bsd
228 # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :