Moose::Cookbook::Recipe1 - has, before, after, extends -
もの凄い乗り遅れた感ですが僕も Moooooooooooooooooose してみる。
とりあえず Cookbook をやってみる事にしてみました。
ソース
まぁ適当にテストとか追加してある。
package Point; use Moose; has 'x' => ( isa => 'Int', is => 'ro' ); has 'y' => ( isa => 'Int', is => 'rw' ); sub clear { my $self = shift; $self->{x} = 0; $self->y(0); } package Point3D; use Moose; extends 'Point'; has 'z' => ( isa => 'Int' ); after 'clear' => sub { my $self = shift; $self->{z} = 0; }; package main; use Data::Dump qw(dump); use Perl6::Say; use Test::More qw(no_plan); my $point = Point->new( x => 10, y => 12 ); ok($point->can('x'), 'has x getter'); ok($point->can('y'), 'has y getter'); is($point->x, 10, 'getter x'); is($point->y, 12, 'getter y'); eval { $point->x(1); }; if (my $err = $@) { ok($err); diag($err); } eval { $point->y('foo'); }; if (my $err = $@) { ok($err); diag($err); } $point->clear; is($point->x, 0, 'after called clear method'); is($point->y, 0, 'after called clear method'); my $point3d = Point3D->new(x => 3, y => 4, z => 5); ok(!$point3d->can('z'), 'has not z getter'); ok(defined $point3d->{z}, 'has z property'); is($point3d->{z}, 5, 'z property'); $point3d->clear; is($point3d->x, 0, 'after called clear method'); is($point3d->y, 0, 'after called clear method'); is($point3d->{z}, 0, 'after called clear method');
解説
前提はこんな感じ。
- use Moose すると strict, warnings が有効になる
- use Moose した package は Moose::Object がスーパークラスになる
- has はインスタンス属性を定義する
アクセサの定義
has 'x' => ( isa => 'Int', is => 'ro' ); has 'y' => ( isa => 'Int', is => 'rw' );
は概ね想像の通り、値として 'Int' と言う制約で、ro, rw は想像どおり read only, read write です。
has 'z' => ( isa => 'Int' );
Point3d では is を省略してるんだけど、省略するとアクセサメソッドは生成されない。
メソッドの定義
これは普通の Perl5 OO と同じ形式。
sub clear { my $self = shift; $self->{x} = 0; $self->y(0); }
但し x は ro で定義してるから値を設定する時はアクセサ経由は出来ないので直で代入してる。
modifier
AOP で言う所の advice に当たる物。
after 'clear' => sub { my $self = shift; $self->{z} = 0; };
これは clear の実行の後に行う処理って言う意味。
package Person; use Moose; use Perl6::Say; sub hello { say 'Hello'; } package ZIGOROu; use Moose; use Perl6::Say; extends 'Person'; before 'hello' => sub { say 'before'; }; after 'hello' => sub { say 'after'; }; package main; ZIGOROu->hello;
まぁこんなんで挙動は分かります。
before Hello after
って感じですね。
override したい場合は、override modifier を使う。
コンストラクタ
my $point = Point->new(x => 1, y => 2); my $point3d = Point3D->new(x => 1, y => 2, z => 3);
まぁそのままですね。