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

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

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

 package MyClass;
 use UNIVERSAL::ref;
 sub new { bless {}, shift }
 sub ref { return 'Hoge' }
 
 package main;
 my $obj = MyClass->new;
 print ref $obj; # Hoge と表示

#ってか最近UNIVERSAL系のモジュール増えたねぇ・・・。

標準関数refの戻り値を制御できるようになるわけです。

UNIVERSAL::refをuseした状態でref関数を用意しておくと標準関数のrefが呼ばれたときにパッケージで定義したref関数が呼ばれるようになります。

用途としてはrefの戻り値を偽装したいときですかねぇ。今ちょっと思い浮かばないですが。

ちなみにUNIVERSAL::refをuseしたパッケージのみ有効なんで下記のように書いても

 package MyClass;
 use UNIVERSAL::ref;
 sub new { bless {}, shift }
 sub ref { return 'Hoge' }

 package YourClass;
 sub new { bless {}, shift }
 sub ref { return 'Muge' }
 
 package main;
 my $myobj = MyClass->new;
 print ref $myobj; # Hoge と表示

 my $yourobj = YourClass->new;
 print ref $yourobj; # YourClass と表示 # Mugeとは表示されない

といったようにYourClassではUNIVERSAL::refをuseしていないのでref関数は呼ばれないわけです。うまいことなってますね。

で元々の標準関数refを呼びたい場合はUNIVERSAL::refをuseする前にあらかじめ取得用のメソッドを定義しておく必要があります。

 package MyClass;

 sub core_ref { ref shift }

 use UNIVERSAL::ref;
 sub new { bless {}, shift }
 sub ref { return 'Hoge' }

 package main;
 my $obj = MyClass->new;
 print ref $obj;       # Hoge と表示
 print $obj->core_ref; # MyClass と表示

といった感じで。もしかしたら別の取得方法があるかもしれませんがちょっとわからなかったので。

なかなか面白いモジュールですね。

コレ使えばまったく別のモジュールを同じモジュールに見せかけることができるんで用途によっては面白い使い方ができそうかもかも。

なんか考えてみます。・・・たぶん。