如何包装需求和使用?

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/ 我认为您正在搜索的术语是您想要检测 userequire 【参考方案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;

【讨论】:

这是否适用于全局(例如,对于其他模块加载的模块)? 要求需要比这更奇怪才能说它需要一个源过滤器:)

以上是关于如何包装需求和使用?的主要内容,如果未能解决你的问题,请参考以下文章

JS中基本包装类型说明需求文档

基本类型包装类

ide机构分享面面俱到!包装如何打造陈列优势

[javaweb]Java过滤器与包装设计模式的实用案例.

如何使用 varargin 和 varargout 包装函数?

如何使用打开和关闭标记包装所选文本?