UNIVERSAL::cantなるものを触ってみた

ぼへーっとCPANRSS眺めてたらUNIVERSAL::cantとかいうが目に付いたのでさっそく触ってみた。

以下概要のまんまだけど例。

 if ( $obj->cant('hoge') ) {
     # hogeメソッドが存在しない
 }
 else {
     # hogeメソッドが存在する
 }

つまりcanメソッドと逆の動きをするわけですね。へー。

メソッドが存在しないときを明示的に判定できるわけです。なるほどね。

ちなみにcant()だけじゃなくcan't()でも呼び出せます。これはシングルクォートが::と同じだということを利用しているわけですね。

ってことは勝手にcanパッケージにtメソッドを定義してることになるんでちょっと微妙といえば微妙なんですがまぁカブることもないだろうし見栄え的にいい感じなのでいいんじゃないでしょうか。

あとですね、本来のcanメソッドは戻り値に関数のリファレンスを返してくれるんだけどcantメソッドは返してくれないのでそういう意味ではcanメソッドとは全然違いますね。

どーせならcantでも関数のリファレンスを返すようにすればいいと思ったんですがどうでしょう?

 package UNIVERSAL;
 sub cant {
     my ($pkg, @args) = @_;
     if ( my $sub = $pkg->can( @args ) ) {
         return bless $sub , q{UNIVERSAL::cant::false};
     }
     return 1;
 }

 package UNIVERSAL::cant::false;
 use overload (
     q{""}   => sub { return shift },
     q{bool} => sub { return },
 );

ま、ちょっとトリッキーな実装ですがこれで、

 if ( my $sub = $obj->cant('hoge') ) { 
     # hogeメソッドが存在しない
 }
 else {
     # hogeメソッドが存在する
     $sub->();
 }

こう書けるようになります。

ただ、オーバーロードするものがboolだけでいいのかとか、戻り値の実態はオブジェクトだけどいいのかとか問題点は色々ありますが、まぁネタってことで。