views:

149

answers:

4

Hello SO,

I don't know how to do one thing in Perl and I feel I am doing something fundamentally wrong.

I am doing a larger project, so I split the task into different modules. I put the modules into the project directory, in the "modules/" subdirectory, and added this directory to PERL5LIB and PERLLIB.

All of these modules use some configuration, saved in external file in the main project directory - "../configure.yaml" if you look at it from the module file perspective.

But, right now, when I use module through "use", all relative paths in the module are taken as from the current directory of the script using these modules, not from the directory of the module itself. Not even when I use FindBin or anything.

How do I load a file, relative from the module path? Is that even possible / advisable?

A: 

Change your use Module call to require Module (or require Module; Module->import(LIST)). Then use the debugger to step through the module loading process and see where Perl thinks it is loading the files from.

mobrule
well, I dont think there is a BUG in my program - I just dont know, how to write it :) if I just write, for example, LoadFile("../configure.yaml"); into the module, and I use THAT module in a script that is somewhere else, Perl just use it as a relative path from the script file, NOT the module file. Require or debugging is not really helping, I KNOW where the problem is, I just dont know what to do with it
Karel Bílek
+8  A: 

Perl stores where modules are loaded from in the %INC hash. You can load things relative to that:

package Module::Foo;
use File::Spec;
use strict;
use warnings;

my ($volume, $directory) = File::Spec->splitpath( $INC{'Module/Foo.pm'} );
my $config_file = File::Spec->catpath( $volume, $directory, '../configure.yaml' );

%INC's keys are based on a strict translation of :: to / with .pm appended, even on Windows, VMS, etc.

Note that the values in %INC may be relative to the current directory if you put relative directories in @INC, so be careful if you change directories between the require/use and checking %INC.

ysth
and thank you, too.
Karel Bílek
+5  A: 

The global %INC table contains an entry for every module you have use'd or require'd, associated with the place that Perl found that module.

use YAML;
print $INC{"YAML.pm"};

>> /usr/lib/perl5/site_perl/5.8/YAML.pm

Is that more helpful?

mobrule
Yes, it is.. thank you :)
Karel Bílek
+4  A: 

There's a module called File::ShareDir that exists to solve this problem. You were on the right track trying FindBin, but FindBin always finds the running program, not the module that's using it. ShareDir does something quite similar to ysth's solution, except wrapped up in a nice interface.

Usage is as simple as

my $filename = File::ShareDir::module_file(__PACKAGE__,
  'my/data.txt');
# and then open $filename or whatever else.

or

my $dirname = File::ShareDir::module_dir(__PACKAGE__);
# Play ball!
hobbs