有没有一种方法可以;使用「;在Perl中使用多个其他文件的单个文件?
我想创建几个模块,这些模块将用于我项目中几乎所有的脚本和模块中。在我的每一个脚本中都可以使用d,如下所示:有没有一种方法可以;使用「;在Perl中使用多个其他文件的单个文件?,perl,module,Perl,Module,我想创建几个模块,这些模块将用于我项目中几乎所有的脚本和模块中。在我的每一个脚本中都可以使用d,如下所示: #!/usr/bin/perl use Foo::Bar; use Foo::Baz; use Foo::Qux; use Foo::Quux; # Potentially many more. 是否可以将所有这些use语句移动到新模块Foo::Corge,然后只需在我的每个脚本和模块中使用Foo::Corge 基本上,创建包含大量模块的软件包: package Lots::Of:
#!/usr/bin/perl
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
# Potentially many more.
是否可以将所有这些use语句移动到新模块
Foo::Corge
,然后只需在我的每个脚本和模块中使用Foo::Corge
基本上,创建包含大量模块的软件包:
package Lots::Of::Modules;
use strict; # strictly optional, really
# These are the modules we want everywhere we say "use Lots::Of::Modules".
# Any exports are re-imported to the module that says "use Lots::Of::Modules"
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
...
sub import {
my $caller = caller;
my $class = shift;
no strict;
*{ $caller. '::'. $_ } = \*{ $class. '::'. $_ }
for grep { !/(?:BEGIN|import)/ } keys %{ $class. '::' };
}
然后在别处使用Lots::Of::Modules
use Lots::Of::Modules;
confess 'OH NOES';
对
在Foo/Corge.pm
剩下的就是将包含子目录Foo
的目录添加到库路径(@INC
)。或者,创建Foo.pm
,并让它使用其他模块。它们将位于Foo.pm
旁边的Foo
子目录中
仔细想想,所有使用其他模块的复杂Perl模块都会一直这样做。它们不一定在同一个顶级包中(本例中为Foo
),但它们的使用也同样必要
虽然您可以使用Carp、Path::Class和坦白等等(正如jrockway所建议的那样),但从我现在的位置来看,这似乎有些过头了。是的,这是可能的,但不,您不应该这样做 我刚刚花了两周的时间摆脱了一个只使用其他模块的模块。我猜这个模块一开始是简单和无辜的。但多年来,它成长为一个巨大的野兽,有着许许多多的使用声明,其中大部分都是我们的网络应用程序运行所不需要的。最后,仅仅“使用”这个模块就花了大约20秒。它支持延迟复制和粘贴模块创建
所以再说一遍:你可能会在几个月或几年后后悔这一步。你有什么好处?您在几个模块中节省了键入几行代码。大不了。[编辑:我以前的解决方案涉及
使用Lots::Of::Modules;
有一个微妙的缺陷——请参见下文。该修复方案使事情变得更丑陋,但仍然可行。]
[编辑#2:在代码周围添加了开始{…}
,以确保在编译时定义的任何函数都可用。感谢jrockway指出这一点。]
以下代码与jrockway的代码完全相同,只是更简单、更清晰:
在Lots/Of/Modules.inc中:
要导入这4个功能:
BEGIN { defined( do 'Lots/Of/Modules.inc' ) or die; }
因为我们没有包Lots::Of::Modules
语句在该文件的开头,use
语句将导出到调用者的包中
我们必须使用
do
而不是use
或require
,因为后者只会加载文件一次(如果使用Lots::of::Modules,则会导致失败;
被多次调用,例如在单独的模块中,主程序使用d)。如果在@INC
中找不到由其参数命名的文件,则更原始的do
不会引发异常,因此需要使用定义的检查结果另一个选项是Foo::Corge只需重新导出任何感兴趣的项目,通常:
package Foo::Corge;
use base 'Exporter';
BEGIN {
our @EXPORT_OK = qw( bar baz qux quux );
use Foo::Bar qw( bar );
use Foo::Baz qw( baz );
use Foo::Qux qw( qux );
use Foo::Quux qw( quux );
}
1;
(use语句可能会超出BEGIN
,但这就是我检查的代码中的语句,以验证它是否按我认为的方式工作。该代码实际上eval
suse
s,因此它们有理由位于BEGIN
中,这可能不适用于您的情况。)使用@EXPORT代替@EXPORT\u OK更简单
图书馆是:
package mycommon;
use strict;
use warnings;
use base 'Exporter';
our @EXPORT = qw(test);
sub test {
print "this is a test";
}
1;
使用它:
#!/usr/bin/perl
use strict;
use warnings;
use mycommon;
common::test()
我的示例假设您需要从每个模块导出符号。Class和Carp是导出符号的模块示例。当您“使用”Lots::Of::Modules时,您将得到定义Lots::Of::Modules时所使用的所有内容的导出。如果组合在一起的模块没有任何共同之处,我完全同意,但将具有内聚性的相关模块组合在一起实际上是一件好事,同样,将许多内聚的代码行组合到一个函数中,然后多次调用它也是很好的。我完全不同意。很抱歉如果所有模块都做了基本相同的事情,只是略有变化,会怎么样?为什么要一直使用它们,而不仅仅是你现在需要的?对于分组属于一起的东西,我们有Perl中的包名称空间。如果所有模块都做了基本相同的事情,当然,只使用一个而不是所有模块是有意义的。但是,如果您处理的是一组互补模块,为什么不将它们分组呢?我能看到的唯一缺点是,如果你让团队变得庞大,可能会出现性能问题。我不同意。很多其他语言都是这样做的——参见CL中的ASDF。使用模块的唯一方法是在任何地方使用它。使用模块的唯一方法是在任何地方使用它?-很抱歉,但我不知道这意味着什么。如果您依赖于编译时可用的函数,那么这不起作用,因为do在运行时运行。副作用是导入函数上的原型无法工作。jrockway的观点很好。我添加了一个BEGIN块来纠正这个问题。它也有缺陷,因为它依赖于硬编码路径,而不是像“use”那样搜索@INC。对于本地开发来说没什么大不了的,但是当你尝试在其他地方安装它时,一定要玩得开心…@Dave Sherohman:我同意这是个问题。主要的问题是“使用”几乎正是我们想要的——如果有某种方法迫使它总是包含文件,那么这种丑陋的解决方法是可以避免的。(可能是“BEGIN{local%INC;use Lots::Of::Modules;}”)use=require+import。需要运行一次,导入每次运行。这将无法导出包含单词“BEGIN”或“import”(例如名为“do_important_work()”)的函数--请将正则表达式更改为/\a(?:BEGIN | import)\z/以解决此问题。它还需要一个真正的表达式(例如“1;”)作为最后一个语句。更多子语句
package mycommon;
use strict;
use warnings;
use base 'Exporter';
our @EXPORT = qw(test);
sub test {
print "this is a test";
}
1;
#!/usr/bin/perl
use strict;
use warnings;
use mycommon;
common::test()