我一直在使用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总是存在。
答案 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();
答案 2 :(得分:0)
require
中的文字(和变量)完全解释为文件名。
例如:
$var = "TEST::test";
require $var;
输出:
Can't locate TEST::test in @INC (@INC contains: ...)
^^^^^^^^^^ -- not TEST/test.pm!