0

I'm trying to create a number of related classes within the same namespace, but the classes can't seem to find each other.

I'm working within the namespace Crypt::HSXKPasswd. My .pm files are in the correct file paths in a folder ./lib (Crypt::HSXKPasswd is defined in ./lib/Crypt/HSXKPasswd.pm etc.).

Within my main module's constructor (Crypt::HSXKPasswd->new) I try to instantiate an object of type Crypt::HSXKPasswd::Dictionary::Default.

My test file is located in ., and has the following contents:

#!/usr/bin/perl

use strict;
use warnings;
use lib './lib';
use Crypt::HSXKPasswd;

my $hsxkpasswd = Crypt::HSXKPasswd->new();

It fails to execute with the following error:

Can't locate Crypt::HSXKPasswd::Dictionary::Default in @INC (@INC contains: ./lib /Library/Perl/5.18/darwin-thread-multi-2level /Library/Perl/5.18 /Network/Library/Perl/5.18/darwin-thread-multi-2level /Network/Library/Perl/5.18 /Library/Perl/Updates/5.18.2/darwin-thread-multi-2level /Library/Perl/Updates/5.18.2 /System/Library/Perl/5.18/darwin-thread-multi-2level /System/Library/Perl/5.18 /System/Library/Perl/Extras/5.18/darwin-thread-multi-2level /System/Library/Perl/Extras/5.18 .) at lib/Crypt/HSXKPasswd.pm line 482.

Notice that @INC contains ./lib. The following head command shows that the .pm file for the module is located within the correct path under ./lib, and that it does define the correct package:

$ head -1 ./lib/Crypt/HSXKPasswd/Dictionary/Default.pm 
package Crypt::HSXKPasswd::Dictionary::Default;
$

If the .pm file exists, defines the module, and is located in the correct path relative to a folder in @INC, why is Perl not seeing it?

5
  • 1
    in your file Crypt::HSXKPasswd you need to use Crypt::HSXKPasswd::Dictionary::Default; Commented May 5, 2015 at 2:59
  • Crypt::HSXKPasswd::Dictionary::Default - the package name wasn't converted to file name. Could you please publish a couple lines around the use statement (before the change that fixed it)? Thank you. Commented May 5, 2015 at 16:48
  • @Dallaylaen - I don't have the broken code anymore, but it was a require directive rather than a use directive, and if memory serves it was using a string rather than a bare word, and might well explain the whole problem. Commented May 6, 2015 at 9:10
  • 1
    @BartB yes it does. require "Foo::Bar"; will try to load a Foo::Bar literally. You might want to replace it with use Module::Load; load "Foo::Bar"; - it should autodetect whether it's a file, or a package. Commented May 6, 2015 at 12:56
  • @Dallaylaen you should pop that into an answer, that way I can accept it and you can pick up the reputation your answer deserves! Commented May 7, 2015 at 13:15

3 Answers 3

1

Note Crypt::HSXKPasswd::Dictionary::Default in the error message - it wasn't converted into Crypt/HSXKPasswd/Dictionary/Default.pm, so Perl tried to load a package literally, and failed.

This may happen in use case like follows:

my $foo = "Foo::Bar";
require $foo; # tries lo load literal Foo::Bar

This can be overcome by using Module::Load which will autodetect whether you're going to load a module or file.

use Module::Load;

# later
my $foo = "Foo::Bar";
load $foo;  

Or one can use a string eval:

my $foo = "Foo::Bar";
eval "require $foo" or die $@; 

But note that eviling strings may be dangerous, so check the variable twice twice in this case.

Sign up to request clarification or add additional context in comments.

Comments

1

Most likely, your current working directory is not where you think it is at the time the module is loaded. Something in one of your modules may be changing the current working directory. For example, I can reproduce the problem by having a module that looks like this:

package Crypt::HSXKPasswd;

BEGIN { chdir("/"); }

use strict;
use warnings;
use Crypt::HSXKPasswd::Dictionary::Default;

1;

Your problem likely isn't this straightforward, but you probably have a module somewhere in the chain doing something similar, whether through something as direct as that BEGIN statement or less obvious, as by changing a directory before a require statement. Given that your module is failing at line 482, it's probably not a use statement that's loading the module (those are usually listed at the top of a package), so I'd lean towards a chdir() initiated somewhere before a require.

Comments

0

For reasons I don't understand, changing from using require within the constructor only when Crypt::HSXKPasswd::Dictionary::Default was needed (only needed for some paths through the constructor), to just importing it with a use statement at the top of the file, fixed the problem.

I think the moral of the story is probably not to try to optimise too soon, and not to try to be too clever for your own good!

1 Comment

See my answer. The reason that works for you is that require happens at runtime, whereas use happens at compile time. Because your use lib statement references a relative path, if your working directory changes (which is to what the path is relative), then the script may no longer be able to load modules out of that relative path at runtime.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.