如何包装需求和使用?
Posted
技术标签:
【中文标题】如何包装需求和使用?【英文标题】:How can I wrap require and use? 【发布时间】:2021-03-12 18:27:02 【问题描述】:假设我想包装 require
这样,
package MyModule;
use Data::Dumper;
也会输出,
MyModule -> Data::Dumper
MyModule -> Data/Dumper.pm
对于所有包和所有requires
/use
语句。我该怎么办?
【问题讨论】:
这将是goto &CORE::require
- CORE::GLOBAL:: 用于覆盖而不是调用,所以你只是调用了你自己的覆盖。除了 require 不是可从 CORE:: 调用的内置函数之一,如 CORE docs 中所述。
s/callable from CORE::/referenceable as a subroutine/
我认为您正在搜索的术语是您想要检测 use
和 require
。
【参考方案1】:
BEGIN
unshift @INC, sub
printf "%s -> %s\n", ( caller() )[0], $_[1];
return;
;
请参阅require
's documentation 中以“您也可以在导入工具中插入挂钩”开头的段落。
【讨论】:
注意使用列表切片而不是不必要地构建数组。【参考方案2】:您不能将 require
内置作为子例程引用,例如 goto
,但您可以从 CORE 调用它。
use strict;
use warnings;
BEGIN
*CORE::GLOBAL::require = sub
printf "%s -> %s\n", [caller()]->[0], $_[0];
CORE::require $_[0];
;
use Data::Dumper;
您也可以考虑Devel::TraceUse,它与上述类似,但更健壮且信息量更大,并且可以从命令行轻松调用。
【讨论】:
【参考方案3】:您可以查看Devel::TraceUse 内部,查看您正在尝试执行的工作代码。但是,更改定义并不是一个好计划,因为您不知道还有谁也更改了定义,并且会想知道为什么他们的东西停止工作。
您不需要(或不应该)覆盖require
。在@INC
中添加一个代码引用并在最后返回false,这样看起来就失败了,Perl 将在@INC
中继续下一步:
#!perl
use v5.10;
# https://***.com/a/2541138/2766176
BEGIN
unshift @INC, sub
my( $package, $file ) = caller(0);
say "$package -> $_[1]";
return 0;
;
use Data::Dumper;
say "Hello";
这个输出:
main -> Data/Dumper.pm
Data::Dumper -> constant.pm
constant -> strict.pm
constant -> warnings/register.pm
warnings::register -> warnings.pm
Data::Dumper -> Carp.pm
Carp -> overloading.pm
Carp -> Exporter.pm
Data::Dumper -> XSLoader.pm
Data::Dumper -> bytes.pm
Hello
【讨论】:
另外,你应该什么都不返回,而不是错误的。 啊,你确实打败了我。这就是我将答案留在标签中的结果。 :( 至于返回值,这没什么大不了的,但是文档中的措辞是“如果返回一个空列表、undef 或没有与上面的前 3 个值匹配的任何内容,则 require 会查看 @ 的剩余元素INC。” 哦。最新的文档说“子例程应该不返回任何内容,或者按以下顺序返回最多四个值的列表:”(我的答案中的链接。)【参考方案4】:奇怪的需求需要奇怪的解决方案:使用源过滤器。
#!/usr/bin/perl
package Wrap::Use;
use Filter::Simple sub
warn $1 while /use (.*?);/sg; # stupid SO: /
;
BEGIN Wrap::Use->import
use strict;
use warnings;
use Time::Piece;
【讨论】:
这是否适用于全局(例如,对于其他模块加载的模块)? 要求需要比这更奇怪才能说它需要一个源过滤器:)以上是关于如何包装需求和使用?的主要内容,如果未能解决你的问题,请参考以下文章