2

我一直在玩 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 中总是有。

4

3 回答 3

5

您控制哪些文件?如果您将程序创建为模数然后尝试加载该文件,只需使文件中的最后一条语句返回包名。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;
    }
于 2012-03-24T07:44:16.863 回答
0

不知道包意味着加载机制必须返回信息,因此我们需要使用do.

usingdo意味着我们不能使用符号表,这意味着匿名 subs。

创建一个如下所示的文件:

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多次调用,但要避免调用,因为它每次都会编译和运行文件。而是缓存它返回的值。

丑陋!这一切都是因为您不希望文件名和其中的包之间有任何关系。如果你试图规避 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();

另请参阅Module::PluginFinder

于 2012-03-24T00:26:15.103 回答
0

文字(和变量)require完全解释为文件名。

例如:

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

输出:

Can't locate TEST::test in @INC (@INC contains: ...)
             ^^^^^^^^^^ -- not TEST/test.pm!
于 2012-03-24T00:35:31.267 回答