The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

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
  }

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.

CONFIGURATION

None.

AUTHOR

Jeffrey Ryan Thalhammer <thaljef@cpan.org>

COPYRIGHT

Copyright (c) 2007 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.