如何挂钩Perl的use/require以便抛出异常? [英] How can I hook into Perl's use/require so I can throw an exception?

查看:126
本文介绍了如何挂钩Perl的use/require以便抛出异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果已经加载了文件,是否仍然可以挂接到use/require,所以我可以抛出异常?在我即将发布的 nextgen::blacklist 中,我正在尝试如果使用某些模块,将导致死亡.我正在使用perldoc -f require中提到的object-hook方法:有三个类似的钩子 object ,带有subref 的 array和 subref .这篇文章中的示例是对象挂钩,您可以在

If a file is already loaded, is there anyway to hook into the use/require so I can throw an exception? In my upcoming nextgen::blacklist, I'm trying to die if certain modules are used. I'm using the object-hook method as mentioned in perldoc -f require: there are three-like hooks object, array with subref, and subref. The example in this post is the object-hook, you can find my attempt of the sub-ref hook in nextgen::blacklist.

我想要的语法是这样的:

The syntax I'm desiring is something like:

perl -Mnextgen -E"use NEXT"

package Foo;
use nextgen;
use NEXT;

理想情况下,应该抛出这样的消息:

Ideally it is supposed to throw a message like this:

nextgen::blacklist violation with import attempt for: [ NEXT (NEXT.pm) ] try 'use mro' instead.

我已经尝试了很多不同的方法.

I've tried this a bunch of different ways.

package Class;
use Data::Dumper;
use strict;
use warnings;

sub install {
  unshift @main::INC, bless {}, __PACKAGE__
    unless ref $main::INC[0] eq __PACKAGE__
  ;
}

sub reset_cache { undef %main::INC }

sub Class::INC {
  my ( $self, $pmfile ) = @_;
  warn Dumper [\%main::INC, $pmfile];
  #undef %INC;
} 

package main;
  BEGIN { Class->install; undef %main::INC }
  use strict;
  use strict;
  use strict;
  use strict;
  use warnings;
  use strict;
  use warnings;

似乎%INC只是在这些钩子之后设置的.我对任何允许我抛出异常的东西都感兴趣.如果尝试加载/重新加载模块而忽略了它的状态是其他不使用编译指示的模块的依存关系,那么我想死.

It seems as if %INC is only set after these hooks. I'm interested in anything that will allow me to throw an exception. If an attempt is made to load/reload a module dispite the status of it as a dependency of other modules that don't use my pragma, I want to die.

package Foo;
use NEXT;

package main;
use Foo; (which uses Next.pm);
use NEXT.pm; ## Throw exception

推荐答案

您可能想将coderef放在开头的@INC上,如perldoc -f require中所述.从那里,您可以引发异常以防止某些模块被加载,或者不执行任何其他要求以继续其在其他@INC条目中查找该模块的正常工作.

You probably want to put a coderef onto the beginning @INC, as described in perldoc -f require. From there, you can raise exceptions to prevent certain modules from being loaded, or do nothing to let require carry on with its normal job of looking up the module in the other @INC entries.

$ perl -E'BEGIN { unshift @INC, sub { die q{no NEXT} if pop eq q{NEXT.pm}; () }; }; use Carp; say q{success}'
success
$ perl -E'BEGIN { unshift @INC, sub { die q{no NEXT} if pop eq q{NEXT.pm}; () }; }; use NEXT; say q{success}'
no NEXT at -e line 1.
BEGIN failed--compilation aborted at -e line 1.

如果您希望该行为是词汇性的,则应使用Perl的提示哈希%^H.处理这个问题有点麻烦,所以我建议使用 Devel::Pragma ,它可以为您处理所有血腥细节.

If you want that behaviour to be lexical, you should make use of Perl's hints hash %^H. Dealing with that is a little fiddly, so I'd recommend using Devel::Pragma, which can take care of all the gory details for you.

正如您所指出的,对于已加载的模块,不会执行@INC挂钩.如果您还需要挂接到已加载模块的userequire,则覆盖CORE::GLOBAL::require会起作用,因为每次尝试加载模块时都会调用它.

As you pointed out, the @INC hooks won't be executed for a module that's already loaded. If you also need to hook into the use or require of a loaded module, overriding CORE::GLOBAL::require would work, as it is called for every attempt to load a module.

$ perl -E'BEGIN { *CORE::GLOBAL::require = sub { warn @_ } } use NEXT; use NEXT;'
NEXT.pm at -e line 1
NEXT.pm at -e line 1.

此外,作为NEXT的维护者,我完全赞成完全阻止人们使用它. :-)

Also, as the maintainer of NEXT, I completely approve of preventing people from using it, at all, ever. :-)

这篇关于如何挂钩Perl的use/require以便抛出异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆