P::pをstrict::importでエクスポート

[Perl] Dumping variables Everywhere without use() - Bulknews::Subtech - subtech
perl - Perl6の$variable.perlをPerl5で
use無しでどこでも変数をダンプするpackage P;p - ヒルズで働く@robarioの技ログ
http://naoya.g.hatena.ne.jp/naoya/20061009/1160360703
もう終わった感がありますが、別の方法を思いついたので書き残しておきます。

最近のPerlスクリプトであれば、use strictは付いているはずなので、strict::importでやっちゃう方法もあるかな、と。

で、P.pmはこうなります。

package P;
use strict;
use warnings;

BEGIN {
    my $import = strict->can('import');
    undef *strict::import;
    *strict::import = sub {
        no strict qw(refs);
        *{ ( scalar caller ) . '::p' } = sub { require YAML; warn YAML::Dump(@_) };
        goto &{$import};
    };
}
1;

これでuse Pをしていれば、use strictが付いているスコープ(no strictは関係ない)でいつでもpが使えます。

% cat main.pl
use strict;
use Foo;
p 'main.pl';

% cat Foo.pm
package Foo;
use strict;
p 'Foo.pm';
1;

% perl -MP main.pl
--- Foo.pm
--- main.pl

ただしuse Pをしていないとsub pの呼び出しがエラーになります

% perl main.pl
String found where operator expected at Foo.pm line 4, near "p 'Foo.pm'"
        (Do you need to predeclare p?)
syntax error at Foo.pm line 4, near "p 'Foo.pm'"
Compilation failed in require at main.pl line 2.
BEGIN failed--compilation aborted at main.pl line 2.

use Pしていればいつでもpが使えて、use Pしていなければ何も起こらないようにするには、P.pmを以下のように変更して

package P;
use strict;
use warnings;

sub p {
    require YAML;
    warn YAML::Dump(@_);
}

1;

strict.pmに以下のパッチを当てます。

% diff -u strict.pm /usr/lib/perl5/5.8/strict.pm
--- strict.pm   2006-10-09 13:36:25.573961600 +0900
+++ /usr/lib/perl5/5.8/strict.pm        2006-10-09 13:38:01.712201600 +0900
@@ -27,6 +27,7 @@
 sub import {
     shift;
     $^H |= @_ ? bits(@_) : $default_bits;
+    *{ ( scalar caller ) . '::p' } = $INC{'P.pm'} ? \&P::p : sub { };
 }

 sub unimport {

これで、use Pしていればp()がsub P::pを指し、していなければsub {}を指すようになります。

どれも perl -MP -e 'package XYZ; p "foo"' とすると
String found where operator expected at -e line 1, near "p "foo""
とか言われて怒られる

use strictさえ付ければ

% perl -MP -e 'package XYZ;use strict; p "foo"'
--- foo

ということで。。。

当然、パッチが当たっていない環境でuse Pせずにp()を呼び出すとエラーになりますので、根本的な解決にはなっていませんし、Core Moduleに手を入れるのがなんとも言えない空気に包まれます。



コンパイルフェーズをフックできれば全てがうまく行きそうなので、XSで何とかできないかなーと思ったりしましたが、いかんせんXSはさっぱりで・・・orz