Moose/Mouseのregister_implementationで短縮名を登録する時のファイル配置ってどうするんだろ

Moose::Cookbook::Meta::Recipe3みたいに、自前のTraitを作って、それをregister_implementationで短縮名でアクセス可能にする場合って、

  • MyApp::Meta::Attribute::Trait::XXXX
  • Moose::Meta::Attribute::Custom::Trait::XXXX

のファイルはどういう配置にするのがいいんだろう。

サンプルみたいにアプリのベースクラスとかに適当に埋め込んでしまえば話は早いんだけど、それもどうなのという気はする。

Moose/Meta/Attribute/Custom/Trait/XXXX.pmとか作っちゃうと、独自のTraitとか作るモジュールをインストールする度に、Mooseディレクトリ以下にMoose本体とは関係ないファイルが入ってしまうので、それも嫌な感じ。それに、Any::Moose対応しようと思ったら、Mouse/Meta/Attribute/Custom/Trait/XXXX.pmも配置することになって更に嫌な空気が漂ってくる。

Custom/にいろんな物が入ってくる前提で、Moose::Meta::Attribute::Nativeという名前区間が用意されてるのかも知れないけど、Customの中で他のモジュールと衝突する可能性も高いわけで、そこにファイルを置くのはやっぱり気が進まない。

MyApp/Meta/Attribute/Trait/XXXX.pmの中で解決できればいいけど、

has hoge => (
    traits => [qw/XXXX/],
    is     => 'rw',
    isa    => 'Str',
);

と書いた時に先に呼ばれるのはMoose::Meta::Attribute::Custom::Trait::XXXXの方なので、そいつがrequireできないとエラーで落ちてしまう。かと言って、おとなしく traits => [qw/MyApp::Meta::Attribute::Trait::XXXX/] とか書くのもダルい。

今のところ、MyApp/Meta/Attribute/Trait/XXXX.pmを

package MyApp::Meta::Attribute::Trait::XXXX;
use Any::Moose '::Role';

# acutual trait implementation

local $@;
eval "package " . any_moose . "::Meta::Attribute::Custom::Trait::XXXX;\n".
     "sub register_implementation {'MyApp::Meta::Attribute::Trait::XXXX'}";
die $@ if $@;

1;

みたいに書いて、起点になるクラスで

package MyApp;
use MyApp::Meta::Attribute::Trait::XXXX;

とかで事前にロードするようにしてるけど、これもどうにもまだるっこしい感が抜けない。

MyApp/Meta/*/Custom/以下のファイルを洗って、動的に組み込むローダとか作っちゃうのも一つの方法なのかも知れないけど、そもそもこのアプローチがいいのかどうか分からん。自前のTraitとか定義しまくってそうなモジュールを覗いてみよう。

#以下、追記
KiokuDBとかそのへんやってそうだと思って収録モジュール一覧を見てみたら、Moose::Meta::Attribute::Custom::Trait::KiokuDB::DoNotSerializeとLazyが入ってるのを確認した。

そうか、Custom::Trait直下じゃなくて、その下に自分のモジュール名で区切るのね。なるほど。で、SYNOPSISにあるように、

has bar => (
    traits => [qw(KiokuDB::DoNotSerialize)],

という名前で呼び出すと。モジュール自身の名前空間が深いとtraits書くの面倒臭そうだけど、そこは仕方ないか。

これを見た感じだと、Any::Moose対応したい場合はMouse::Meta::も作っておくのが妥当なやり方なのかなー。

(10/07追記)MooseX::AttributeHelpersに同梱されてるMoose::Meta::Attribute::Custom::Collection::Arrayでは、MooseX/AttributeHelpers/Collection/Array.pmの中に

# register the alias ...
package Moose::Meta::Attribute::Custom::Collection::Array;
sub register_implementation { 'MooseX::AttributeHelpers::Collection::Array' }

と書いてalias設定してますね。代表的なMooseXモジュールでこういうアプローチを取ってるということは、筋の悪いやり方ではないのかな。ちょっと安心した。