我如何模拟内置`require`函数?

时间:2014-02-17 16:24:19

标签: perl mocking refactoring require

我要重构大量旧的perl脚本。 (超过150k行,没有测试,没有严格,没有包,没有提交日志,没有评论)

当我开始在t目录下编写一些测试时。我发现几乎所有文件require都是绝对路径。所以我尝试使用内置的require函数来使它们可移植,但没有运气:

T / 001-require.t

use strict;
use warnings;
use Test::More;
use FindBin;

BEGIN {
    my $root = "$FindBin::RealBin/../";
    sub require {
        $_[0] = $root . $_[0];
        CORE::require(@_);
    }
}

require_ok "foo.pl";

done_testing();

上面的脚本给了我:Error: Can't locate foo.pl in @INC...

如何在Perl需要之前添加根路径?

更新

谢谢Axeman,我使用以下钩子修改了绝对路径。

my $root = "$RealBin/../";
unshift @INC, sub {
    my ($coderef, $filename) = @_;
    $filename =~ s/^\///;
    open(FILE, '<', $root . $filename);
    return *FILE;
};

2 个答案:

答案 0 :(得分:6)

你不是只是在寻找

use FindBin qw( $RealBin );
use lib "$RealBin/..";

答案 1 :(得分:4)

你不必。

当模块为require时,无论是require还是use,perl都会查看列表以查看它是否可以通过(通常)目录列表找到模块作为安装库。此列表存储在名为@INC的变量中。

但是,@INC需要的不仅仅是目录,它还需要“钩子”,这些子程序可以改变Perl模块的加载行为。如果您插入 hook (子例程)作为@INC的第一个条目,则require将调用您的行为。

您可以在perldoc on require找到更完整的治疗方法。我只想快速介绍一个钩子:

 sub inc_hook {
     my ( $ref_to_this_sub, $relative_module_path ) = @_;
     # $relative_module_path will be in directory form: Root/Package.pm

     # return nothing to pass it to standard behavior
     return unless _i_want_to_handle( $relative_module_path );

     # most commonly, return handle to source
     return my $io_handle_to_source = handle_module( $relative_module_path );
 }

 unshift @INC, inc_hook;