一時的なメソッドの上書き

[Perl] メソッドの上書き>Testに使えそう たまには呪文をとなえてみるか:仕事版/ウェブリブログ
後で元に戻す(一時的に上書きする)のであればlocalを使うと簡単にできます。



普通に書くと、元のメソッドを保存・復元する処理を書く必要があります。

package Object;
sub new { bless {}, shift }
sub method { print "This is Object\n" }

package main;
my $object = Object->new;
$object->method();


my $orig = Object->can('method'); # 保存。と言ってもコードそのものがコピーされるわけじゃなくて参照カウントが増えるだけ ← 間違ってたら教えて(><)
*Object::method = sub { print "foo bar baz\n" }; # 上書き
$object->method();


*Object::method = $orig; # 復元
$object->method();
# 実行結果
% perl overwrite.pl
This is Object
foo bar baz
This is Object

ところで、名前の付いたサブルーチンはシンボルテーブルに入ってるのでlocal化することができます。(逆に言うとシンボルテーブルに入らないmy変数などはlocal化できません)

local化されたシンボルはスコープの終わりで自動的に元の値に戻ります。(スタック)

package Object;
sub new { bless {}, shift }
sub method { print "This is Object\n" }

package main;
my $object = Object->new;
$object->method();


{
    local *Object::method = sub { print "foo bar baz\n" }; # 上書き
    $object->method();
}


# メソッドは復元されている
$object->method();

実行結果は同じです。

おまけ

localで@ARGVをいじることもできます。wrapperみたいに使える。
Perlの実行ファイルfoo.plがあったとして、以下のようなfoo-verbose.plを作った場合

{
    local @ARGV = (@ARGV, '--verbose');
    do 'foo.pl';
}

foo-verbose.plを実行すると必ずfoo.plに--verboseオプションが渡ることになります。