如何有条件地使警告致命?

Mic*_*man 4 perl

我希望根据用户的偏好,致命错误可以降级为警告(或者相反,警告可以升级为致命错误)。目前,我正在die像这样使用和覆盖它:

my $force;
BEGIN {
    no warnings 'once';
    Getopt::Long::Configure('pass_through');
    GetOptions('force', \$force);
    *CORE::GLOBAL::die = sub { warn @_ } if $force;
    Getopt::Long::Configure('no_pass_through');
}

use My::Module;
...
die "maybe";
...
exit(1) if $force;
exit(0); # success!
Run Code Online (Sandbox Code Playgroud)

我不喜欢这种方法,主要是因为有几个地方我仍然想死(例如缺少命令行参数)。我宁愿更改(大多数)实例dietowarn并执行条件use warnings FATAL => 'all'1。问题是它use warnings是词法范围的,所以这是无效的:

if (!$force) {
    use warnings FATAL => 'all';
}
Run Code Online (Sandbox Code Playgroud)

尝试使用后缀条件是一个语法错误:

use warnings FATAL => 'all' unless $force;
Run Code Online (Sandbox Code Playgroud)

并且use不能在表达式中使用:

$force or use warnings FATAL => 'all';  # syntax error
Run Code Online (Sandbox Code Playgroud)

我可以想到各种令人讨厌的解决方法(定义我自己的 warn/die、在 if/else 中复制我的主脚本代码等),但我正在寻求一种有条件地应用于use warnings当前词法范围的优雅解决方案。(将其应用于父范围也可以,但可能需要黑魔法。)


1:实际上,我想添加use warnings::register到我的模块和use warnings FATAL => 'My::Module'脚本中,但对于这个问题的目的来说,区别并不重要。

tob*_*ink 5

你可以尝试:

use if !$force, warnings => qw( FATAL all );
Run Code Online (Sandbox Code Playgroud)

是的,有一个名为 的模块if随 Perl 一起分发,使条件导入变得非常容易。

请注意,这是在编译时评估的,因此$force需要在编译时定义。(可能在一个BEGIN { ... }块内。)根据您问题中的代码示例,您似乎已经弄清楚了该部分。

或者,更多手动:

BEGIN {
    require warnings;
    warnings->import(qw/ FATAL all /) unless $force;
}
Run Code Online (Sandbox Code Playgroud)

一种完全不同的方法是使用信号处理程序$SIG{__WARN__}$SIG{__DIE__}在运行时决定是否死亡。