在不知道模块名称但知道文件名的情况下加载和使用perl模块

时间:2012-03-24 00:13:10

标签: perl modulino

我一直在使用modulino perl模式,并且想要在不知道包名称的情况下加载一个,并且只知道它所在的文件。我正在寻找可以像这样使用的东西:

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

这里的something是关键。没有requireuse,因为之后我需要模块名称。我是否必须阅读$file并解析package名称然后再使用它?我可以肯定有更好的方法。 perl总是存在。

3 个答案:

答案 0 :(得分:5)

您控制哪个文件?如果要将程序创建为modulino,然后尝试加载该文件,只需使文件中的最后一个语句返回包名称即可。 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;
    }

答案 1 :(得分:0)

不知道包意味着加载机制必须返回信息,这意味着我们需要使用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();

另见Module::PluginFinder

答案 2 :(得分:0)

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

例如:

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

输出:

Can't locate TEST::test in @INC (@INC contains: ...)
             ^^^^^^^^^^ -- not TEST/test.pm!