Perl:使用在嵌套子目录中组织的自定义嵌套模块
Perl: Use custom nested modules organised in nested sub-directories
我正在尝试弄清楚如何使用 Perl 使用在嵌套子目录中组织的嵌套模块。我的意思是,一个 test.pl 程序使用一个 Foo 模块,而这个程序又使用另一个 Bar 模块等等......让我们举一个小例子,文件可以这样组织在目录中:
./test.pl
./lib/Foo.pm
./lib/common/Bar.pm
首先想到的是在 test.pl 中使用 FindBin 模块,就像这样:
use FindBin;
use lib "$FindBin::RealBin/lib/.";
use Foo;
但是如果你想在 Foo 中对 "use Bar" 做同样的事情,你需要包括来自 test.pl 程序的所有相对路径,包括“/lib”段。这意味着 Foo 需要知道他与调用程序的相对路径。这在目录结构中强制了某种刚性。例如,您不能简单地将自定义模块复制并粘贴到任何您想要的地方并调用它。另外需要安装FindBin模块才能使用
为了解决这个问题,谷歌搜索我找到了这个解决方案: BEGIN solution 直接将路径添加到@INC。考虑到这一点,解决方案可能是:
./test.pl
#!/usr/bin/perl
use strict;
use warnings;
# Include lib in @INC
BEGIN {
use File::Basename;
my($filename, $dirs, $suffix) = fileparse(__FILE__);
my $common_path = $dirs."lib/.";
unshift(@main::INC, $common_path) ;
}
use Foo;
print "Inside: $Foo::message";
./lib/Foo.pm
package Foo;
# Include Common library
BEGIN {
use File::Basename;
my($filename, $dirs, $suffix) = fileparse(__FILE__);
$common_path = $dirs."common/.";
unshift(@main::INC, $common_path) ;
}
use Bar;
$message = " Foo > $Bar::message";
1;
./lib/common/Bar.pm
package Bar;
$message = "Bar";
1;
执行 ./test.pl 应该打印:
Inside: Foo > Bar
您可以在各自的目录中嵌套任意数量的模块(我测试了三个级别),更好的是,可以在路径的任意点复制和粘贴而不会破坏功能。
不过我不知道这种方法是否可取或有任何缺点(我是 perl 的新手)。例如,是否建议像这样直接编辑@INC?。建议为此使用 BEGIN 代码块吗?。或者,是否有更好的方法来做到这一点(允许在模块目录结构的任意点复制和粘贴目录)以便在不触及模块内部代码的情况下工作?
不要在模块中更改 @INC
。将其留给脚本。
use FindBin qw( $RealBin );
use lib "$RealBin/lib", "$RealBin/lib/common";
That means Foo needs to be aware of his relative path to the calling program.
如果脚本和彼此都有库,那不是问题,使用 use lib
是有道理的。
否则,它只是一个供任何脚本使用的模块,不应该使用use lib
。相反,它应该安装到标准安装目录(或由 env var PERL5LIB
指定的自定义目录)。
顺便说一下,你可能不应该把 common
放在 lib
里面。这意味着你可以做 use common::Bar;
,这是错误的。
我正在尝试弄清楚如何使用 Perl 使用在嵌套子目录中组织的嵌套模块。我的意思是,一个 test.pl 程序使用一个 Foo 模块,而这个程序又使用另一个 Bar 模块等等......让我们举一个小例子,文件可以这样组织在目录中:
./test.pl
./lib/Foo.pm
./lib/common/Bar.pm
首先想到的是在 test.pl 中使用 FindBin 模块,就像这样:
use FindBin;
use lib "$FindBin::RealBin/lib/.";
use Foo;
但是如果你想在 Foo 中对 "use Bar" 做同样的事情,你需要包括来自 test.pl 程序的所有相对路径,包括“/lib”段。这意味着 Foo 需要知道他与调用程序的相对路径。这在目录结构中强制了某种刚性。例如,您不能简单地将自定义模块复制并粘贴到任何您想要的地方并调用它。另外需要安装FindBin模块才能使用
为了解决这个问题,谷歌搜索我找到了这个解决方案: BEGIN solution 直接将路径添加到@INC。考虑到这一点,解决方案可能是:
./test.pl
#!/usr/bin/perl
use strict;
use warnings;
# Include lib in @INC
BEGIN {
use File::Basename;
my($filename, $dirs, $suffix) = fileparse(__FILE__);
my $common_path = $dirs."lib/.";
unshift(@main::INC, $common_path) ;
}
use Foo;
print "Inside: $Foo::message";
./lib/Foo.pm
package Foo;
# Include Common library
BEGIN {
use File::Basename;
my($filename, $dirs, $suffix) = fileparse(__FILE__);
$common_path = $dirs."common/.";
unshift(@main::INC, $common_path) ;
}
use Bar;
$message = " Foo > $Bar::message";
1;
./lib/common/Bar.pm
package Bar;
$message = "Bar";
1;
执行 ./test.pl 应该打印:
Inside: Foo > Bar
您可以在各自的目录中嵌套任意数量的模块(我测试了三个级别),更好的是,可以在路径的任意点复制和粘贴而不会破坏功能。 不过我不知道这种方法是否可取或有任何缺点(我是 perl 的新手)。例如,是否建议像这样直接编辑@INC?。建议为此使用 BEGIN 代码块吗?。或者,是否有更好的方法来做到这一点(允许在模块目录结构的任意点复制和粘贴目录)以便在不触及模块内部代码的情况下工作?
不要在模块中更改 @INC
。将其留给脚本。
use FindBin qw( $RealBin );
use lib "$RealBin/lib", "$RealBin/lib/common";
That means Foo needs to be aware of his relative path to the calling program.
如果脚本和彼此都有库,那不是问题,使用 use lib
是有道理的。
否则,它只是一个供任何脚本使用的模块,不应该使用use lib
。相反,它应该安装到标准安装目录(或由 env var PERL5LIB
指定的自定义目录)。
顺便说一下,你可能不应该把 common
放在 lib
里面。这意味着你可以做 use common::Bar;
,这是错误的。