开发者

How can I use Smart::Comments in a module I load without changing its source?

开发者 https://www.devze.com 2022-12-18 14:22 出处:网络
How can I specify that Smart::Comments be loaded for my original script, as well as for any of the modules it directly loads. However, since it is a source-filter, it would probably wreck havoc if app

How can I specify that Smart::Comments be loaded for my original script, as well as for any of the modules it directly loads. However, since it is a source-filter, it would probably wreck havoc if applied to every module loaded by every other loaded module.

For example, my script includes

use Neu::Image;

I would like to load Smart::Comments for Neu::Image as well, but specifying

$ perl -MSmart::Comments script.pl

does not load Smart::Comments for Neu::Image.

This behavior is described in the Smart::Comments documentation:

If you're debugging an application you can also invoke it with the module from the command-line:

perl -MSmart::Comments $application.pl

Of course, this only enables smart comments in the application file itself, not in any modules that the application loads.

A few other things that I've looked at already:

  • Perl Command-Line Options
  • perldoc perlrun (I searched it for the word "module")

WORKAROUND As gbacon mentions, Smart::Comments provides an environment variable option that would allow turning it on or off. However, I would like to be able to turn it on without modifying the original source, if possible开发者_如何转开发.


You almost certainly want to add use Smart::Comments to modules that contain such and then flip the switch in your environment by setting $Smart_Comments appropriately.

Stash-munging, import-hijacking monkey-patching is madness.

But maybe you're into that sort of thing. Say you have 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;

Ordinary usage:

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

Ordinary is dull and boring, of course. With run-foo, we take bold, dashing steps!

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

(Please pardon the compactness: I shrunk it so it would all fit in an unscrolled block.)

Output:

$ ./run-foo

### $i: 0

### $i: 1

### $i: 2

### $i: 3

### $i: 4
024

¡Viva!

With @INC hooks we can substitute our own or modified sources. The code watches for attempts to require modules directly used by the program. On a hit, inject_smart_comments returns an iterator that yields one line at a time. When this crafty, artful iterator sees the package declaration, it appends an innocent-looking use Smart::Comments to the chunk, making it appear as though it were in the module's source all along.

By trying to parse Perl code with regular expressions, the code will break if the package declaration isn't on a line by itself, for example. Season to taste.


It doesn't seem like this idea makes any sense. If you are utilizing Smart::Comments in a module, why would you not want to use Smart::Comments in that module's source? Even if you could get Smart::Comments to apply to all modules loaded in a script via -M, it probably wouldn't be a good idea because:

  • You're obfuscating the fact that your modules are using smart comments by not including the use line in their source.
  • You could potentially introduce bizarre behavior from modules you use in your script which happen to have what look like smart comments, but aren't really. If a module doesn't contain smart comments, you should not force them down its throat.

As gbacon said, the right way to do this is to use the module in each of your modules that make use of it, and then suppress them with an environment variable when you don't want the output.

Also as he said, it's still probably possible to do this with some "Stash-munging, import-hijacking monkey-patching" madness, but that's a lot of work. I don't think anyone is going to put the effort into giving you a solution along those lines when it is not a good idea in the first place.

0

精彩评论

暂无评论...
验证码 换一张
取 消