#######################################################################
# $Date: 2006-07-16 22:15:05 -0700 (Sun, 16 Jul 2006) $
# $Author: thaljef $
# $Revision: 506 $
########################################################################
use strict;
use List::MoreUtils qw(all);
our $VERSION = '0.18';
$VERSION = eval $VERSION; ## no critic
#---------------------------------------------------------------------------
my $desc = q{Package variable declared or used};
my $expl = [ 73, 75 ];
#---------------------------------------------------------------------------
sub default_severity { return $SEVERITY_MEDIUM }
sub applies_to {
return qw( PPI::Token::Symbol
PPI::Statement::Variable
PPI::Statement::Include );
}
#---------------------------------------------------------------------------
sub violates {
my ( $self, $elem, $doc ) = @_;
if ( _is_package_var($elem)
|| _is_our_var($elem)
|| _is_vars_pragma($elem) )
{
my $sev = $self->get_severity();
return Perl::Critic::Violation->new( $desc, $expl, $elem, $sev );
}
return; #ok!
}
sub _is_package_var {
my $elem = shift;
$elem->isa('PPI::Token::Symbol') || return;
return $elem =~ m{ \A [@\$%] .* :: }mx && $elem !~ m{ :: [A-Z0-9_]+ \z }mx;
}
sub _is_our_var {
my $elem = shift;
$elem->isa('PPI::Statement::Variable') || return;
return $elem->type() eq 'our' && !_all_upcase( $elem->variables() );
}
sub _is_vars_pragma {
my $elem = shift;
$elem->isa('PPI::Statement::Include') || return;
$elem->pragma() eq 'vars' || return;
# Older Perls don't support the C<our> keyword, so we try to let
# people use the C<vars> pragma instead, but only if all the
# variable names are uppercase. Since there are lots of ways to
# pass arguments to pragmas (e.g. "$foo" or qw($foo) ) we just use
# a regex to match things that look like variables names.
return $elem =~ m{ [@\$%&] ( [\w+] ) }mx
&& $1 =~ m{ [a-z] }mx;
}
sub _all_upcase {
return all { $_ eq uc $_ } @_;
}
1;
__END__
#---------------------------------------------------------------------------
=pod
=head1 NAME
Perl::Critic::Policy::Variables::ProhibitPackageVars
=head1 DESCRIPTION
Conway suggests avoiding package variables completely, because they
expose your internals to other packages. Never use a package variable
when a lexical variable will suffice. If your package needs to keep
some dynamic state, consider using an object or closures to keep the
state private.
This policy assumes that you're using C<strict vars> so that naked
variable declarations are not package variables by default. Thus, it
complains you declare a variable with C<our> or C<use vars>, or if you
make reference to variable with a fully-qualified package name.
$Some::Package::foo = 1; #not ok
our $foo = 1; #not ok
use vars '$foo'; #not ok
$foo = 1; #not allowed by 'strict'
local $foo = 1; #bad taste, but technically ok.
use vars '$FOO'; #ok, because it's ALL CAPS
my $foo = 1; #ok
In practice though, its not really practical to prohibit all package
variables. Common variables like C<$VERSION> and C<@EXPORT> need to
be global, as do any variables that you want to Export. To work
around this, the Policy overlooks any variables that are in ALL_CAPS.
This forces you to put all your exported variables in ALL_CAPS too, which
seems to be the usual practice anyway.
=head1 SEE ALSO
L<Perl::Critic::Policy::Variables::ProhibitPunctuationVars>
L<Perl::Critic::Policy::Variables::ProhibitLocalVars>
=head1 AUTHOR
Jeffrey Ryan Thalhammer <thaljef@cpan.org>
=head1 COPYRIGHT
Copyright (c) 2005-2006 Jeffrey Ryan Thalhammer. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself. The full text of this license
can be found in the LICENSE file included with this module.
=cut