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

时间:2010-01-28 18:35:15

标签: perl command-line module

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

例如,我的脚本包含

use Neu::Image;

我也想为Neu::Image加载Smart::Comments,但指定

$ perl -MSmart::Comments script.pl

未加载Smart::Comments的{​​{1}}。

Smart::Comments documentation

中描述了此行为
  

如果您正在调试应用程序   也可以用模块调用它   从命令行:

Neu::Image
     

当然,这只能实现智能化   应用程序文件中的注释   本身,不在任何模块中   应用程序负载。

我已经看过的其他一些事情:

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

2 个答案:

答案 0 :(得分:10)

您几乎肯定希望通过适当设置use Smart::Comments$Smart_Comments添加到包含此类的模块,然后添加flip the switch in your environment

Stash-munging,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;

普通用法:

$ perl -MFoo -e 'print foo, "\n"'
024

当然,平凡无聊乏味。使用run-foo,我们采取大胆,敏捷的步骤!

#! /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

¡万岁!

使用@INC hooks,我们可以替换自己的或修改过的来源。该代码监视程序直接使用的require模块的尝试。在命中时,inject_smart_comments返回一个迭代器,一次产生一行。当这个狡猾的,巧妙的迭代器看到包声明时,它会向块中添加一个看起来无辜的use Smart::Comments,使它看起来好像它一直在模块的源中。

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

答案 1 :(得分:2)

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

  • 您认为模块正在使用而不是的智能评论这一事实,包括其来源中的use行。
  • 您可能会在脚本中引入奇怪的行为use,这些模块碰巧看起来像是智能评论,但实际上并非如此。如果模块不包含智能注释,则不应强迫它们。。。

作为gbacon said,正确的方法是use每个模块中使用它的模块,然后在你不想要的时候使用环境变量来抑制它们输出。

同样正如他所说的那样,仍然有可能通过一些“Stash-munging,import-hijacking monkey-patching”疯狂来做到这一点,但这是很多工作。我不认为任何人都会努力为你提供一个解决方案,因为它首先不是一个好主意。