readpipe(バッククォート演算子)のオーバーロード
バッククォート演算子をオーバーロードしたくて、readpipe を上書いてみたのですが、なんか妙な動きをしてくれます。
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; BEGIN { *CORE::GLOBAL::readpipe = sub { warn Dumper(\@_); }; } `ls -l`; my $cmd = "ls -l"; `$cmd`;
これを実行すると、両方とも同じ結果になりそうな気がするのですが、実際はなりません。
tsucchi@over[344]% perl a.pl $VAR1 = [ 'ls -l' ]; $VAR1 = [ '$cmd' ];
うーん、これは Perl のバグのような気がするのですが、どうなんでしょうね?
変数展開したくても、再定義された readpipe 側では呼び出し元の変数の情報は(通常は)引っ張れないので、どうにもならない気がします。
何かいい方法あるのかなー?さっきから調べてるのですが、見つかりません。。。
追記
PadWalker 投入ですかね?これはこれで胡散臭いですが。。。peek level をちゃんと決めれるか分かんないですし。。。
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use PadWalker qw(peek_my); BEGIN { *CORE::GLOBAL::readpipe = sub { my ($expr) = @_; my $walker = peek_my(1); my @commands = split(/\s+/, $expr); for my $command ( @commands ) { $command = ${ $walker->{$command} } if ( $command =~ /^\$/ ); } warn join(' ', @commands); }; } `ls -l`; my $cmd = "ls -l"; `$cmd`;
tsucchi@over[354]% perl a.pl ls -l at a.pl line 16. ls -l at a.pl line 16.
追記2 (2011/07/31)
この問題(?)を解決するために、Variable::Expand::AnyLevelというモジュールを書いてみました。
真面目に研究(?)してみてわかったのですが、たぶん peek level は一意に決まる。でも変数展開するためには、手元にいったん変数を全部持ってこないとできないとか、結構めんどくさそうな処理がいろいろあったので、別のモジュールにしてみました。