简体   繁体   English

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

[英]How can I mock builtin `require` function?

I'm going to refactoring large number of old perl scripts. 我要重构大量旧的perl脚本。 (over 150k lines, no tests, no strict, no packages, no commit logs, no comments) (超过150k行,没有测试,没有严格,没有包,没有提交日志,没有评论)

When I started to write some tests under t directory. 当我开始在t目录下编写一些测试时。 I found almost all files require each others with absolute paths. 我发现几乎所有文件require绝对路径。 So I tried mocking builtin require function to make them portable, but no luck: 所以我尝试使用内置的require函数来使它们可移植,但没有运气:

t/001-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();

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

How can I prepend a root path before Perl requires them? 如何在Perl需要之前添加根路径?

update 更新

Thank you Axeman, I modified absolute paths using following hook. 谢谢Axeman,我使用以下钩子修改了绝对路径。

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

Aren't you simply looking for 你不是在寻找

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

You don't have to. 你不必。

When a module is require d, either by require or use , perl looks through a list to see if it can locate the module by the list of (usually) directories set up as libraries for the installation. 当一个模块是require d,无论是requireuse ,PERL看起来在一个列表,看它是否可以通过设置为安装库(通常情况下)的目录列表中找到该模块。 This list is stored in a variable called @INC . 该列表存储在名为@INC的变量中。

However, @INC takes more than directories, it also takes "hooks", which are subroutines which can change the loading behavior for Perl modules. 但是, @INC需要的不仅仅是目录,它还需要“钩子”,这些子程序可以改变Perl模块的加载行为。 If you insert a hook (a subroutine) as the first entry into @INC , require will call your behavior. 如果您将钩子 (子例程)作为第一个条目插入@INC ,则require将调用您的行为。

You can find a more complete treatment at the perldoc on require . 您可以在一个更完整的治疗上的perldoc require I just wanted to give a quick profile of a hook: 我只想快速介绍一个钩子:

 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM