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 used or required.

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.