Загрузите и используйте модуль Perl, не зная имени модуля, но зная имя файла - PullRequest
2 голосов
/ 24 марта 2012

Я играл с шаблоном modulino perl и хотел бы загрузить его, не зная имени пакета и только файла, в котором он находится.Я ищу что-то, что можно использовать следующим образом:

eval {
  my $file = "some-file-name-in-the-hierarchy-unrelated-to-package-name";
  my $module = something($file);
  $module->sub1();
};

Ключ something здесь.Нет require или use, так как впоследствии мне понадобится имя модуля.Нужно ли читать $file и анализировать имя package, чтобы потом использовать его?Там может быть лучший способ, я уверен.Там всегда есть в Perl.

Ответы [ 3 ]

5 голосов
/ 24 марта 2012

Какими файлами вы управляете?Если вы создаете программу как модуль и затем пытаетесь загрузить этот файл, просто сделайте последний оператор в файле, возвращающий имя пакета. require ожидает, что вы вернете истинное значение, и большинство модулей используют 1;.Однако вы можете использовать любое истинное значение, которое вам нравится.Это будет возвращаемое значение require :

# i_dont_know_whats_inside
package Buster;

__PACKAGE__;

Загрузка проста:

my $package = require 'i_dont_know_whats_inside';

print "Package is $package\n";

$package->new( ... );

Если вы не можете контролировать загружаемый файлнетрудно выяснить, что внутри:

my @packages = load_file( 'i_dont_know_whats_inside' );

print "Packages are @packages\n";

sub load_file {
    my $file = shift;
    require Module::Extract::Namespaces;
    my @packages = Module::Extract::Namespaces->from_file( $file );
    my $rc = require $file;
    return @packages;
    }
0 голосов
/ 24 марта 2012

Литералы (и переменные) в require интерпретируются точно как имя файла.

Например:

$var = "TEST::test";
require $var;

вывод:

Can't locate TEST::test in @INC (@INC contains: ...)
             ^^^^^^^^^^ -- not TEST/test.pm!
0 голосов
/ 24 марта 2012

Не зная, что пакет означает, что информация должна быть возвращена механизмом загрузки, что означает, что нам нужно использовать do.

Использование do означает, что мы не можем использовать таблицу символов, что означает анонимные подпрограммы.

Создайте файл, который выглядит следующим образом:

sub foo { ... }
sub bar { ... }

{
   foo => \&foo,
   bar => \&bar,
};

или как

{
   foo => sub { ... },
   bar => sub { ... },
};

Тогда используйте

my $table = do '/abs/path/to/file.pl' or die $@;
$table{foo}->();

или

my $table = do 'rel/path/to/file.pl' or die $@;  # Relative to entries in @INC
$table{foo}->();

Вы можете вызывать do более одного раза, но избегайте его, поскольку он компилирует и запускает файл каждый раз. Вместо этого кэшируйте возвращаемое значение.

UGLY! И все потому, что вы не хотите никаких связей между именем файла и пакетом в нем. Если вы пытаетесь обойти требования Perl, ожидайте безобразия. Это даже не поможет вам выполнить это требование, поэтому избавьтесь от него.

Вместо этого следует создать файл, который выглядит следующим образом:

package Some::Package;

sub foo { shift; ... }
sub bar { shift; ... }

1;

Телефонный код будет:

my $file= 'Some/Package.pm';
my $pkg = $file;
$file =~ s{\.pm\z}{};
$file =~ s{/}{::}g;

require $file;
$pkg->foo();

См. Также Модуль :: PluginFinder .

...