我想创建几个模块,这些模块将用于我项目中的几乎所有脚本和模块。这些可以在我的每个脚本中使用,如下所示:
#!/usr/bin/perl
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
# Potentially many more.
是否可以将所有这些使用语句移动到一个新模块Foo::Corge
,然后只需要use Foo::Corge
在我的每个脚本和模块中?
像这样的东西应该工作:
http://mail.pm.org/pipermail/chicago-talk/2008-March/004829.html
基本上,创建包含大量模块的包:
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';
是的,这是可能的,但不,你不应该这样做。
我只花了两个星期来摆脱一个除了使用其他模块什么都不做的模块。我猜这个模块一开始是简单而无辜的。但多年来,它成长为一个巨大的野兽,拥有大量的使用语句,其中大部分对于我们的 web 应用程序的任何给定运行都不需要。最后,仅仅“使用”那个模块就花了大约 20 秒。它支持惰性复制和粘贴模块创建。
再说一遍:你可能会在几个月或几年后后悔那一步。你有什么好处?您节省了在几个模块中输入几行代码。大不了。
是的。
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
1; # Be successful
剩下的就是将包含子目录的目录Foo
添加到您的库路径 ( @INC
) 中。或者,创建Foo.pm
并让它使用其他模块。它们将Foo
位于 旁边的子目录中Foo.pm
。
如果你仔细想想,所有使用其他模块的复杂 Perl 模块都会一直这样做。它们不一定在同一个顶级包中(Foo
在这个例子中),但它们的使用是一样的。
虽然您可以使用 Carp 和 Path::Class 并承认,等等(正如 jrockway 所建议的那样),但从我坐的地方来看,这似乎有点矫枉过正。
[编辑:我之前涉及的解决方案use Lots::Of::Modules;
有一个微妙的错误——见底部。该修复使事情变得有点丑陋,但仍然可行。]
[编辑#2:BEGIN { ... }
在代码周围添加以确保定义的任何函数在编译时可用。感谢 jrockway 指出这一点。]
以下代码将完全按照 jrockway 的代码所做的,只是更简单和更清晰:
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
0; # Flag an error if called with "use" or "require" instead of "do"
要导入这 4 个函数:
BEGIN { defined( do 'Lots/Of/Modules.inc' ) or die; }
package Lots::Of::Modules;
因为我们在这个文件的开头没有语句,所以这些use
语句将导出到调用者的包中。
我们必须使用do
代替use
or require
,因为后者只会加载文件一次(如果use Lots::Of::Modules;
多次调用会导致失败,例如在use
主程序的单独模块中)。do
如果在 中找不到由其参数命名的文件,则更原始的不会引发异常@INC
,因此需要使用defined
.
另一种选择是让 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
use
BEGIN
使用 @EXPORT 而不是 @EXPORT_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()