NAME
Perl::Critic::Policy::Modules::RequireExplicitInclusion
AFFILIATION
This policy is part of Perl::Critic::StricterSubs.
DESCRIPTION
Checks that, if a reference is made to something inside of another package, that a module with the name of the package has been use
d or require
d.
Without importing a package, it is unlikely that references to things inside it even exist. Due to the flexible nature of Perl, use strict;
can not complain about references to things outside of the current package and thus won't detect this situation.
Explanation
As an example, assume there is a third-party Foo
module with a bar()
subroutine. You then create a module of your own.
package My::Module;
...
$x = Foo::bar($y);
...
You don't have to worry about whether Foo
exports bar()
or not because you're fully qualifying the name. Or do you? You then create a program plugh that uses your module that also needs to use Foo
directly.
#!/usr/bin/perl
...
use Foo;
use My::Module qw{ &frob };
...
This works fine. At some later time, you use your module in a xyzzy program.
#!/usr/bin/perl
...
use My::Module qw{ &frob };
...
You now get compilation problems in the previously robust My::Module
. What is going on is that plugh loaded the Foo
module prior to My::Module
, which means that, when My::Module
refers to Foo::bar()
, the subroutine actually exists, even though My::Module
didn't actually use Foo;
. When xyzzy attempted to use My::Module
without doing a use Foo;
, My::Module
fails because Foo::bar()
doesn't exist.
Enforcement
Assuming that there are no use
or require
statements within the current scope:
@foo = localtime; #ok
@Bar::foo = localtime #not ok
@::foo = localtime; #ok
@main::foo = localtime; #ok
baz(23, 'something', $x); #ok
Bar::baz(23, 'something', $x); #not ok
::baz(23, 'something', $x); #ok
main::baz(23, 'something', $x); #ok
Only modules that are symbolically referenced by a use
or require
are considered valid. Loading a file does not count.
use Foo;
require Bar;
require 'Baz.pm';
$Foo:x = 57; #ok
$Bar:x = 57; #ok
$Baz:x = 57; #not ok
Qualifying a name with the name of the current package is valid.
package Xyzzy;
my $ducks;
sub increment_duck_count {
$Xyzzy::ducks++; #ok
}
A use
or require
statement is taken into account only when it is in the scope of a file or a BEGIN
, CHECK
, or INIT
block.
use File::Scope;
BEGIN {
require Begin::Block;
}
CHECK {
require Check::Block;
}
INIT {
require Init::Block;
}
END {
require End::Block;
}
push @File::Scope::numbers, 52, 93, 25; #ok
push @Begin::Block::numbers, 52, 93, 25; #ok
push @Check::Block::numbers, 52, 93, 25; #ok
push @Init::Block::numbers, 52, 93, 25; #ok
push @End::Block::numbers, 52, 93, 25; #not ok
{
require Lexical::Block;
push @Lexical::Block::numbers, 52, 93, 25; #not ok
}
CONFIGURATION
You can configure a list of modules that should be ignored by this policy. For example, it's common to use Test::Builder's variables in functions built on Test::More.
use Test::More
sub test_something {
local $Test::Builder::Level = $Test::Builder::Level + 1;
return is( ... );
}
Using Test::More also brings in Test::Builder, so you don't need to do a call to use
. Unfortunately that trips this policy.
So to ignore violations on Test::Builder, you can add to your perlcriticrc file this section:
[Modules::RequireExplicitInclusion]
ignore_modules = Test::Builder
The ignore_modules
argument can take a space-delimited list of modules, or of regexes, or both.
[Modules::RequireExplicitInclusion]
ignore_modules = Test::Builder /MooseX::/
CAVEATS
1.) It is assumed that the code for a package exists in a module of the same name.
2.) It is assumed that a module will contain no more than one package. This Policy will not complain about any problems in a module containing multiple package
statements. For example, a module containing
package Foo;
sub frob {
$Xyzzy::factor = rand 100;
}
package Bar;
sub frob {
$Plugh::factor = rand 1000;
}
will not result in any violations. There really shouldn't be more than one package within a module anyway.
3.) No checks of whether the name actually exists in the referenced package are done. E.g., if a call to a Foo::process_widgets()
subroutine is made, this Policy does not check that a process_widgets()
subroutine actually exists in the Foo
package.
DIAGNOSTICS
Modules::RequireExplicitInclusion: Cannot cope with multiple packages in file
-
This warning happens when the file under analysis contains multiple packages, which is not currently supported. This Policy will simply ignore any file with multiple packages.
Perl::Critic advises putting multiple packages in one file, and has additional Policies to help enforce that.
SEE ALSO
Perl::Critic::Policy::Modules::ProhibitMultiplePackages
AUTHOR
Jeffrey Ryan Thalhammer <thaljef@cpan.org>
COPYRIGHT
Copyright 2007-2024 Jeffrey Ryan Thalhammer and Andy Lester
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.