日向夏特殊応援部隊

俺様向けメモ

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');

解説

前提はこんな感じ。

アクセサの定義
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 で定義してるから値を設定する時はアクセサ経由は出来ないので直で代入してる。

継承

use base じゃなくて、extendsを使う。

extends 'Point';

複数の親を持ちたい場合はリストで指定する。

xtends 'Foo', 'Bar', 'Baz';
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);

まぁそのままですね。