Perl 如何在加载的模块中使用Smart::Comments而不更改其源?

Perl 如何在加载的模块中使用Smart::Comments而不更改其源?,perl,command-line,module,Perl,Command Line,Module,如何指定为原始脚本以及它直接加载的任何模块加载Smart::Comments。然而,由于它是一个源过滤器,如果将它应用到由每个其他加载的模块加载的每个模块,可能会造成严重破坏 例如,我的脚本包括 use Neu::Image; 我也想为Neu::Image加载,但要指定 $ perl -MSmart::Comments script.pl 当然,这只会启用smart 应用程序文件中的注释 本身,而不是在 应用程序加载 我已经看了一些其他的东西: (我查了一下 “模块”一词) 解决方法 正

如何指定为原始脚本以及它直接加载的任何模块加载Smart::Comments。然而,由于它是一个源过滤器,如果将它应用到由每个其他加载的模块加载的每个模块,可能会造成严重破坏

例如,我的脚本包括

use Neu::Image;
我也想为
Neu::Image
加载,但要指定

$ perl -MSmart::Comments script.pl 当然,这只会启用smart 应用程序文件中的注释 本身,而不是在 应用程序加载

我已经看了一些其他的东西:

  • (我查了一下 “模块”一词)
解决方法
正如gbacon提到的,Smart::Comments提供了一个环境变量选项,允许打开或关闭它。但是,如果可能的话,我希望能够在不修改原始源代码的情况下打开它。

您几乎肯定希望将
使用Smart::Comments
添加到包含此类内容的模块中,然后通过适当设置
$Smart\u Comments

偷吃东西,
import
-劫持猴子补丁是疯狂的行为

但也许你对这类事情感兴趣。假设你有
Foo.pm

package Foo;

use Exporter 'import';
our @EXPORT = qw/ foo /;

#use Smart::Comments;

sub foo {
  my @result;
  for (my $i = 0; $i < 5; $i++) {
    ### $i
    push @result => $i if $i % 2 == 0;
  }
  wantarray ? @result : \@result;
}

1;
(请原谅我的紧凑性:我把它缩小了,这样它就可以放在一块未经滚压的砖里。)

输出:

$ ./run-foo ### $i: 0 ### $i: 1 ### $i: 2 ### $i: 3 ### $i: 4 024 美元/润富 ###$i:0 ###$i:1 ###$i:2 ###$i:3 ###$i:4 024 “万岁

我们可以用我们自己的或修改过的资源替代。代码监视是否尝试
需要程序直接使用的
模块。点击时,
inject\u smart\u comments
返回一个迭代器,每次生成一行。当这个狡猾、巧妙的迭代器看到包声明时,它会在块中附加一个看起来无辜的
use Smart::Comments
,使其看起来就像一直在模块的源代码中一样


例如,通过尝试用正则表达式解析Perl代码,如果包声明本身不在一行上,代码就会中断。调味。

这个想法似乎没有任何意义。如果您正在模块中使用,为什么不想在该模块的源代码中使用Smart::Comments?即使您可以通过
-M
应用于脚本中加载的所有模块,也可能不是一个好主意,因为:

  • 您正在混淆模块正在使用智能注释这一事实,因为它们的源代码中没有包含
    use
  • 您可能会从脚本中
    使用的模块中引入奇怪的行为,这些模块碰巧有看起来像智能注释,但实际上不是。如果一个模块不包含智能注释,你不应该强迫它们进入它的喉咙
同样,正确的方法是
在使用该模块的每个模块中使用该模块,然后在不需要输出时使用环境变量抑制它们


同样,正如他所说的,用一些“藏匿大口、进口劫持猴子修补”的疯狂行为来实现这一点仍然是可能的,但这需要大量的工作。我认为,如果一开始不是一个好主意,就没有人会按照这些思路为你提供解决方案。

“有些男人不寻求任何合乎逻辑的东西。他们不能被收买、欺负、推理或谈判。有些男人只想看着世界燃烧。”@gbacon:你是指我使用Smart::Comments吗?我只是想找到一种“安全”玩火的方法你的问题真的是“如何在我加载的每个模块中使用Smart::Comments而不更改它们的源”?@brian实际上是的。在不引起“世界燃烧”的情况下这是可能的吗?你为什么不想改变来源?你的处境是不允许的吗?谢谢。我忘了环境开关了。哇!我是说,哇!感谢gbacon,Perl大师!感谢您对@INC hooks的引用。我真的不想让你或其他人做很多工作。我想可能有更简单的办法。哇,真是太神奇了!错误:模块必须在当前目录中。如书面所述,它不会搜索
@INC
。感谢您的回答。对我来说,Smart::注释仅用于调试。从布赖恩的评论中,我开始认为还有另一种方法可以做到这一点,但并不复杂。我不会要求任何人付出很多努力。 $ perl -MFoo -e 'print foo, "\n"' 024
#! /usr/bin/perl

use warnings;
use strict;

BEGIN {
  unshift @INC => \&inject_smart_comments;

  my %direct;
  open my $fh, "<", $0 or die "$0: open: $!";
  while (<$fh>) {
    ++$direct{$1} if /^\s*use\s+([A-Z][:\w]*)/;
  }
  close $fh;

  sub inject_smart_comments {
    my(undef,$path) = @_;
    s/[\/\\]/::/g, s/\.pm$// for my $mod = $path;
    if ($direct{$mod}) {
      open my $fh, "<", $path or die "$0: open $path: $!";
      return sub {
        return 0 unless defined($_ = <$fh>);
        s{^(\s*package\s+[A-Z][:\w]*\s*;\s*)$}
         {$1 use Smart::Comments;\n};
        return 1;
      };
    }
  }
}

use Foo;

print foo, "\n";
$ ./run-foo ### $i: 0 ### $i: 1 ### $i: 2 ### $i: 3 ### $i: 4 024