perl - 覆盖在模块中定义但在其运行时阶段使用之前的函数?
问题描述
让我们来看一些非常简单的事情,
# Foo.pm
package Foo {
my $baz = bar();
sub bar { 42 }; ## Overwrite this
print $baz; ## Before this is executed
}
无论如何,我是否可以test.pl
运行代码来更改$baz
设置并导致Foo.pm
在屏幕上打印其他内容?
# maybe something here.
use Foo;
# maybe something here
编译器阶段是否可以强制打印以上内容7
?
解决方案
需要 hack,因为require
(因此use
)在返回之前编译和执行模块。
也一样eval
。eval
不能在不执行代码的情况下用于编译代码。
我发现的侵入性最小的解决方案是覆盖DB::postponed
. 在评估编译的所需文件之前调用它。不幸的是,它只在调试时调用(perl -d
)。
另一种解决方案是读取文件,修改它并评估修改后的文件,有点像下面这样:
use File::Slurper qw( read_binary );
eval(read_binary("Foo.pm") . <<'__EOS__') or die $@;
package Foo {
no warnings qw( redefine );
sub bar { 7 }
}
__EOS__
上面没有正确设置%INC
,它弄乱了警告使用的文件名等,它不调用DB::postponed
等等。以下是一个更强大的解决方案:
use IO::Unread qw( unread );
use Path::Class qw( dir );
BEGIN {
my $preamble = '
UNITCHECK {
no warnings qw( redefine );
*Foo::bar = sub { 7 };
}
';
my @libs = @INC;
unshift @INC, sub {
my (undef, $fn) = @_;
return undef if $_[1] ne 'Foo.pm';
for my $qfn (map dir($_)->file($fn), @libs) {
open(my $fh, '<', $qfn)
or do {
next if $!{ENOENT};
die $!;
};
unread $fh, "$preamble\n#line 1 $qfn\n";
return $fh;
}
return undef;
};
}
use Foo;
我使用UNITCHECK
了(在编译之后但在执行之前调用),因为我在覆盖之前(使用unread
)而不是读入整个文件并附加新定义。如果您想使用该方法,您可以使用返回的文件句柄
open(my $fh_for_perl, '<', \$modified_code);
return $fh_for_perl;
感谢@Grinnz 提到@INC
钩子。
推荐阅读
- javascript - 自动填充图像的 HTML 文件路径的 Javascript
- mysql - mysql replace为长文本列返回NULL值
- python - 多处理子进程随机接收 SIGTERM
- python - 从 xyz 坐标列表计算 Pandas 中的距离矩阵
- r - 为什么文档术语矩阵中的行只有零(使用 LDA 函数在 R 中进行主题建模)
- julia - 如何从 Gurobi/JuMP 获取矩阵格式的约束?
- list - SharePoint 2010:列表名称更改导致 listdata.svc 错误
- ruby - Ruby Nokogiri xml 解析
- angular - Angular:数组更改时如何更新视图?
- scala - 在 Apache Spark 的 Scala API 中,使用单引号和 $"" 表示法有区别吗?