エイリアスメソッドの作成方法の続き
エイリアスメソッドの作成方法 - Unknown::Programming
前に上記記事でメソッドのエイリアスを作る方法を書いたんだけども。
Class::C3使ってるときにうまくいかないという結論のまま終わってました。
一応その後、id:charsbarさんがエイリアスメソッドの作成方法 - Charsbar::Noteという記事でAUTOLOADを使って実現する方法を書いてくれたんだけど、AUTOLOADだと全体に影響を及ぼしそうなので他に影響を与えずにエイリアスメソッドを作りたいなぁと。
そこで、最近Perl Hacks読んで思いついたので若干無茶な方法だけどエイリアスメソッドを作るモジュールを考えてみました。
名づけてSub::Alias。
package Sub::Alias; use strict; use warnings; use B::Deparse; use base qw/Exporter/; our @EXPORT_OK = qw/sub_alias/; sub sub_alias { my %sublist = @_; my $bd = B::Deparse->new; my $caller = caller; for my $subname (keys %sublist) { my $coderef = ref $sublist{$subname} eq 'CODE' ? $sublist{$subname} : $caller->can($sublist{$subname}); no strict 'refs'; *{"${caller}::$subname"} = eval sprintf qq|package $caller;sub { local *__ANON__ = '$subname'; %s }|, $bd->coderef2text($coderef); } } 1;
で実行
package Hoge; use strict; sub hoge_alias { print "Hoge::hoge_alias\n" } sub hoge { print "Hoge::hoge\n" } package Muge; use strict; use base qw/Hoge/; use Class::C3; use Sub::Alias qw/sub_alias/; sub hoge { my $self = shift; $self->next::method; } sub_alias hoge_alias => \&hoge; Muge->hoge_alias; # Hoge::hoge_alias と表示される
といった感じでうまく動くようになりました。
実装としてはB::Deparse使って関数リファレンスを文字列化し、Perl Hacksのハック#57を参考に__ANON__を一時的に書き換えるというもの凄い荒技を使ってますw
本来ならevalをちゃんと$@トラップしたりcanの戻り値見て存在チェックしたりとかしないといけませんが、とりあえずざっくり版ということでエラー処理はしてません。
しっかしコレ同じようなCPANモジュールないかな。Data::Aliasもダメポだったし。
XSでゴリゴリやればもっとスマートに実装できるかもしれませんね。
ま、でもちょっと満足。