題名¶
Moose::Cookbook::Basics::Recipe11 - Mooseを使っていないベースクラスを拡張する
概要¶
package My::DateTime;
use Moose;
extends qw( DateTime Moose::Object );
use DateTime::Calendar::Mayan;
has 'mayan_date' => (
is => 'ro',
isa => 'DateTime::Calendar::Mayan',
init_arg => undef,
lazy => 1,
builder => '_build_mayan_date',
clearer => '_clear_mayan_date',
predicate => 'has_mayan_date',
);
sub new {
my $class = shift;
my $obj = $class->SUPER::new(@_);
return $class->meta->new_object(
__INSTANCE__ => $obj,
@_,
);
}
after 'set' => sub {
$_[0]->_clear_mayan_date;
};
sub _build_mayan_date {
DateTime::Calendar::Mayan->from_object( object => $_[0] );
}
本文¶
このレシピではMooseを利用してMooseベースではない親クラスをサブクラス化する方法を説明します。このレシピでうまく行くのは親クラスがblessされたハッシュリファレンスの場合のみです。親クラスがちょっと変わったことをしている場合はMooseX::InsideOutを試してみてください。
また、MooseX::NonMooseを試してみてもよいかもしれません。これを使うと面倒な作業はすべてやってくれます。
いくつか注釈を入れておきたい箇所があります。
use Moose;
extends qw( DateTime Moose::Object );
まず、いつものようにuse Moose
します。こうするとアトリビュートを宣言したり、おなじみのシュガー関数をすべて利用できるようになります。
extends
の宣言にはDateTimeだけでなく、明示的にMoose::Objectを入れておきます。こうすると、does
のようにMoose::Objectが提供しているメソッドも使えるようになります。
コンストラクタにはMooseを使っていない親クラスを使うときに特有のハック/パターン(ハックたん?)が見られます。
sub new {
my $class = shift;
my $obj = $class->SUPER::new(@_);
return $class->meta->new_object(
__INSTANCE__ => $obj,
@_,
);
}
ここでは明示的に$class->meta->new_object
を呼んで、作成済みのオブジェクトを__INSTANCE__
キーとともに渡しています。内部的にはMooseが既存のオブジェクトを受け取り、あればサブクラスで定義されているアトリビュートの初期化を行います。
after
モディファイアは期待通りの動作をします。set
がMooseを使っていない親クラスで定義されていても問題ありません。
まとめ¶
Mooseは、ここで紹介したパターンにしたがえば、Mooseを使っていないクラスともうまく共存できます。アトリビュートの宣言、メソッドモディファイア、(新しいアトリビュートの)型制約、ロールといったMooseの力は、サブクラスの中でもすべて利用できます。
ただし、親クラスの「アトリビュート」はMooseのアトリビュートではありませんから、簡単にはオーバーライドできません。また、コンストラクタをインライン展開することもできません。メタクラスのオブジェクトコンストラクタを明示的に利用する必要があるためです。
作者¶
Dave Rolsky <[email protected]>
コピーライト & ライセンス¶
Copyright 2009 by Infinity Interactive, Inc.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.