Mooseでインスタンス名を取得する

前回 Moose を使って作ってみた演奏させてみたプログラムですが、なんも考えずにとりあえず書いたものなのでもうちょっと奇麗にしてみようと思います。

http://d.hatena.ne.jp/clmind/20090322/1237734727

んで、書いてる途中に気になった点を少しずつ調べながら書き直してみているんですが今回は一つわかった事を書いてみます。

前回のエントリを見てもらうとわかるかと思いますが。Musicianクラスを継承してVocal, Guitarlist, Bassist, Drummerというクラスを定義しています。この4クラスはSongクラスで利用しているrole(自分がバンド内で何を担当しているか)というメンバ変数を持っているんですが、これを初期化するのに『__PACKAGE__』を使っています。
この__Package__はクラス名を保持している変数で role = パッケージ名 とすることで上記4クラスは自分が何担当かというデータを保持しているわけです。

roleの初期化は4つのクラスのどれでも行われることなので本来Musicianクラス内で定義されるのが望ましいです。しかし、__PACKAGE__が保持するのはあくまでクラス名(自分の所属するPackage名)なんですね。具体的にどういうことかと言うと。

Musician.pm

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

package Musician;
use Moose;

__PACKAGE__->meta->make_immutable;

no Moose;

sub say_package {
  my $self = shift;

  print __PACKAGE__ . "\n";
}

sub say_instance {
  my $self = shift;

  print $self->meta->name . "\n";
}

1;

Vocal.pm

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

package Vocal;
use Moose;

extends 'Musician';

__PACKAGE__->meta->make_immutable;

no Moose;

1;

test.pl

#!/usr/bin/perl

use strict;
use warnings;

use Musician;
use Vocal;

my ($musician, $vocal);

$musician = Musician->new();
$vocal = Vocal->new();

print "クラス名\n";
$musician->say_package;
$vocal->say_package;

print "\n";

print "インスタンス名\n";
$musician->say_instance;
$vocal->say_instance;

test.pl実行結果

クラス名
Musician
Musician

インスタンス名
Musician
Vocal

この様に『__PACKAGE__』を参照した場合はMusicianクラスであろうがVocalクラスであろうが__PACAGE__が実際に記述されている『Musicianクラス』のパッケージ名であるMusicianが出力されています。なのでわざわざ4つのクラスに分けて同じ様な処理を書いたのですが、クラス名でなくインスタンス(newして生成したオブジェクト)自体のパッケージ名が取り出せればこんなまわりくどいことをしなくても良いわけです。で、もうソース上に答えがありますが、インスタンスのパッケージ名を取り出したい時はmeta->nameを使えば良いわけですね。metaには他にも色々保持されているみたいでprint Dumperしてみたところ色々出力されました。どうやらMooseはClass::MOPのラッパーみたいで、MOP(メタオブジェクトプロトコル)なる概念に基づいて書かれてるみたいですね。きちんと理解するにはMOPの概念を抑えろってことですねー。

後、これはおまけですが、MooseCPAN上にサンプルソースコードをMoose::Cockbookとして上げているみたいです。

http://search.cpan.org/~stevan/Moose-0.48/lib/Moose/Cookbook.pod

この辺を順に読んで行けばあれこれ書けるようになりそうですね。