Как загрузить файл относительно пути к модулю?

Я не знаю, как сделать что-то в Perl, и я чувствую, что делаю что-то принципиально неправильное.

Я делаю большой проект, поэтому я разбил задачу на разные модули. Я поместил модули в каталог проекта, в поддиректорию "modules/" и добавил этот каталог в PERL5LIB и PERLLIB.

Все эти модули используют некоторую конфигурацию, сохраненную во внешнем файле в главной директории проекта - "../configure.yaml", если вы посмотрите на нее с точки зрения файла модуля.

Но сейчас, когда я использую модуль через "использование", все относительные пути в модуле берутся из текущего каталога script с использованием этих модулей, а не из каталога самого модуля. Даже когда я использую FindBin или что-то еще.

Как загрузить файл, относительно пути к модулю? Это даже возможно/целесообразно?

Ответ 1

Perl хранит, где модули загружаются из хеша% INC. Вы можете загружать вещи относительно этого:

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 основаны на строгом переводе:: to/with.pm, добавленном, даже на Windows, VMS и т.д.

Обратите внимание, что значения в% INC могут относиться к текущему каталогу, если вы помещаете относительные каталоги в @INC, поэтому будьте осторожны, если вы меняете каталоги между требованием/использованием и проверкой% INC.

Ответ 2

Там существует модуль, называемый File::ShareDir, который существует для решения этой проблемы. Вы были на правильном пути, пытаясь найти FindBin, но FindBin всегда находит запущенную программу, а не модуль, который ее использует. ShareDir делает что-то очень похожее на решение ysth, за исключением завершенного в приятном интерфейсе.

Использование так же просто, как

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

или

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

Ответ 3

Глобальная таблица %INC содержит запись для каждого модуля, у которого есть use 'd или require' d, связанного с местом, в котором Perl нашел этот модуль.

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

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

Это более полезно?

Ответ 4

Измените вызов use Module на require Module (или require Module; Module->import(LIST)). Затем используйте отладчик, чтобы пройти процесс загрузки модуля и посмотреть, как Perl считает, что он загружает файлы.