=encoding utf8 =pod =head1 題名 Moose::Cookbook::Roles::Recipe1 - Moose::Roleの例 =head1 概要 package Eq; use Moose::Role; requires 'equal_to'; sub not_equal_to { my ( $self, $other ) = @_; not $self->equal_to($other); } package Comparable; use Moose::Role; with 'Eq'; requires 'compare'; sub equal_to { my ( $self, $other ) = @_; $self->compare($other) == 0; } sub greater_than { my ( $self, $other ) = @_; $self->compare($other) == 1; } sub less_than { my ( $self, $other ) = @_; $self->compare($other) == -1; } sub greater_than_or_equal_to { my ( $self, $other ) = @_; $self->greater_than($other) || $self->equal_to($other); } sub less_than_or_equal_to { my ( $self, $other ) = @_; $self->less_than($other) || $self->equal_to($other); } package Printable; use Moose::Role; requires 'to_string'; package US::Currency; use Moose; with 'Comparable', 'Printable'; has 'amount' => ( is => 'rw', isa => 'Num', default => 0 ); sub compare { my ( $self, $other ) = @_; $self->amount <=> $other->amount; } sub to_string { my $self = shift; sprintf '$%0.2f USD' => $self->amount; } =head1 本文 Rolesにはおもに2つの目的があります。インタフェースと、コードの再利用です。このレシピでは、比較を定義するロールとオブジェクトのコードを表示するロールを利用して、コードの再利用について説明します。 まずはCから見ていきましょう。最初にCがCになっているところに注目してください。また、Cという新しいシュガー関数も使われています。 requires 'equal_to'; これは、このロールを取り込むクラスはかならずCというメソッドを用意する必要がある、という意味です。このメソッドは、ロールを取り込むクラスに直書きしてもよいですし、ほかのロールから取り込んでもかまいません。 Cロールには、要求したCメソッドを利用したCというメソッドが定義されています。このようにすると、ロールを取り込むクラスが用意しなければならないメソッドを最小限にとどめることができます。 次のCロールは、Cロールを下敷きにして作られています。ここではCという新しいシュガー関数を利用してCをCの中に取り込んでいます。 with 'Eq'; C関数は取り込みたいロールのリストを引数に取ります。この例では、Cが要求しているCメソッドをCロールが用意していますが、そのようにしないこともできます(その場合はCを取り込むクラスが自前でCを用意する必要があります)。言い換えると、ロールは必須メソッドを用意「しなくても」ほかのロールを取り込める、ということです。 CロールはCというメソッドを要求します。 requires 'compare'; また、Cロールはほかにも最終的にはCに依存するいくつかのメソッドを提供しています。 sub equal_to { my ( $self, $other ) = @_; $self->compare($other) == 0; } sub greater_than { my ( $self, $other ) = @_; $self->compare($other) == 1; } sub less_than { my ( $self, $other ) = @_; $self->compare($other) == -1; } sub greater_than_or_equal_to { my ( $self, $other ) = @_; $self->greater_than($other) || $self->equal_to($other); } sub less_than_or_equal_to { my ( $self, $other ) = @_; $self->less_than($other) || $self->equal_to($other); } 最後はCロールです。このロールはインタフェースを提供するためだけに存在しています(メソッドはなく、必須メソッドのリストしかありません)。この場合、Cメソッドだけを要求しています。 インタフェースロールが便利なのは、メソッドと「名前」の双方を定義してくれるからです。このロールを組み込んだクラスはかならずCメソッドを持っていることがわかるだけでなく、このメソッドが期待通りの意味を持っていることも想定できます(おそらく実際のコードではCロールのドキュメントにメソッドの意味が書かれるはずです)。 最後のCクラスでは、CロールとCロールを両方取り込んでいます。 with 'Comparable', 'Printable'; また、Cという、通常のMooseのアトリビュートも定義されています。 has 'amount' => ( is => 'rw', isa => 'Num', default => 0 ); 最後に、私たちのロールが要求しているメソッドの実装を見ていきます。Cメソッドはこうです。 sub compare { my ( $self, $other ) = @_; $self->amount <=> $other->amount; } Cロールを取り込んでこのメソッドを定義してやると、C、C、C、C、Cというメソッドが自由に使えるようになります。 あとは、Cメソッドです。 sub to_string { my $self = shift; sprintf '$%0.2f USD' => $self->amount; } =head1 まとめ ロールは非常に強力なものになりえます。再利用可能な振る舞いをカプセル化したり、クラスが提供するメソッドの(意味やインタフェースといった)情報をやりとりしたりするうえではすばらしいツールです。 =head1 脚注 =over 4 =item (1) CとCという2つのクラスがあるものと思ってください。どちらにもCというメソッドがありますが、オブジェクトにCメソッドの実装を要求するだけでは、このメソッドが「実際になにをするか」はまだなんとも言えません。ところが、Cロールを実装しているオブジェクトを要求していれば、ある程度意味がわかるようになります。 =back =head1 作者 Stevan Little Estevan@iinteractive.comE Dave Rolsky Eautarch@urth.orgE =head1 COPYRIGHT AND LICENSE Copyright 2006-2009 by Infinity Interactive, Inc. L This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut