Moose - Perl5のためのまったく現代的なオブジェクトシステム
package Point; use strict; use warnings; use Moose; has 'x' => (is => 'rw', isa => 'Int'); has 'y' => (is => 'rw', isa => 'Int'); sub clear { my $self = shift; $self->x(0); $self->y(0); } package Point3D; use strict; use warnings; use Moose; extends 'Point'; has 'z' => (is => 'rw', isa => 'Int'); after 'clear' => sub { my $self = shift; $self->z(0); };
Mooseは急速に成熟しつつあるモジュールで、すでに多くに人々によって利用されています。 これはテストスイートが日増しに大きくなっているということでもあり、ドキュメントもすぐにこれに続くでしょう。
これは、Mooseがまだ完了しておらず、まだ発展中のものであると考えられているとも言えます。 外側のAPIの多くが安定していますが、内部はまだ変化を被りやすいです(真剣な考えなしにそれをすることはありませんが)。
その他の詳細については、このドキュメントのFUTURE PLANSセクションを参照してください。
MooseはPerl 5オブジェクトシステムの拡張です。
Yes。 私は最近、Perl 5でオブジェクトを構築する新しい方法の爆発があり、その大半がオブジェクトやそういったものの裏返しに基づいていることを承知しています。 Mooseが違う点は、新しいPerl5のオブジェクトシステムではなく、既存のオブジェクトシステムの拡張であるという点です。
Mooseは、Perl 5のメタクラスシステムである、Class::MOPの頂点に構築されます。 このことは、Mooseがより良いPerl 5オブジェクトの構築だけではなく、メタクラスプログラミングのパワーを提供することを意味しています。
MooseはPerl 6 メタモデルのためのプロトタイプと実験に基づいたものですが、しかしMooseは実験的なものやプロトタイプではなく、これは本物です。 私は今年の後半にはMooseを生産環境に採用するつもりであり、すべての面で私が今後クラスのデファクトのビルダーとして使うことを意図したものです。
No。 MooseはPerl 6から非常に多くのひらめきを得たものですが、これ自体はPerl 6ではありません。 そうではなく、これはPerl5のOOシステムです。 私は疲れていたか変わりのない古いうんざりさせるようなPerl 5 OOコードを書いていたし、Perl 5 OOに夢中になっていたので、Mooseを構築しました。 そして、Rubyに乗り換える代わりに、Mooseを書きました :)
Mooseはできる限りクラスの構築/定義において、できる限りの多くの利便性を提供する努力をしていますが、もし望むならあなたの方法のままにしておいてください。 Mooseを使ってクラスを構築する際に注意すべき項目がいくつかあります。
Moose::Objectを継承します。
Mooseは、hasを使って定義された(継承したものを含め)すべてのアトリビュートの管理も行います。
そして、Moose::Objectから継承されたnewをあなたが呼び出すものと仮定しており、呼び出されるとすべてのインスタンス・スロットを適切に初期化し、適当な初期値を設定し、何らかの型制約または強制型変換を行います。
Mooseはクラスの名前空間にいくつかの関数をエクスポートし、クラスのセットアップに使えるようにします。 これらの関数はすべて、直接現在のクラスに作用します。
現在のクラスのメタクラスへのアクセス方法を提供するメソッドです。
カレントクラスのスーパークラス(達)を設定します。
use baseの代わりにこのアプローチを取ることが推奨されます。
use baseは実際にはクラスの@ISAへのpushを行いますが、これはextendsが変更するところだからです。
これは、スーパークラスをもたないクラスでも、Moose::Objectを間違いなく継承するようにするための重要な点です。
これは与えられた@rolesセットをローカルクラスに適用します。
Roleのサポートは現在、まったくの開発段階にあります; その他の詳細については、Moose::Roleを参照してください。
これは$nameで与えられたアトリビュートを現在のクラスに導入します。
%optionsリストはMoose::Meta::Attributeにあります)。
isはrw(read/write用)かro(read only用)を受け取ります。
これらはそれぞれ、アトリビュート名である$nameと同じ名前の、read/writeのアクセサ、またはread-onlyのアクセサを生成しようとします。
この命名されたアクセサで行われる以上のコントロールを必要とする時は、Class::MOP::Attributeから継承されたreaderやwriter、accessorオプションを使用することができます。
isaオプションは、はこのアトリビュートの実行時の型制約として、Mooseの型制約機構を設定します。
Mooseはクラスの構築時と、各アクセサの内部で、チェックを行います。
$type_name引数は文字列でなければなりません。
この文字列はクラス名か、Mooseの型定義機能を用いた型定義のどちらかです。
これはアクセサかコンストラクタから渡された値に対して、与えられた型制約によって、強制型変換を試みます。 この作業に使えるように、型を与えておかなければなりません。 Moose::Cookbook::Recipe5の使用例を参照してください。
これは、このアトリビュートに保持された値が、使用すると予想されるロールの名前を受け取ります。
これは、このアトリビュートを必須のものとして指定します。
これは、クラスの構築時に値が与えられなければならなず、アクセサを介してこのアトリビュートにundefをセットすることもできないことを意味しています。
これは、このアトリビュートの値を弱い参照として保持するように、クラスに通知します。 アトリビュートが弱い参照であると、強制型変換(coerce)はできなくなります。
これは、このスロットが絶対に必要になるまでは、作る必要がないことを、クラスに通知します。 lazyに指定されたアトリビュートは、デフォルトが与えられていなければなりません。
これは、返される値を自動的にデリファレンスするか否かを、アクセサに通知します。
これは、isaオプションがArrayRefとHashRefのどちらかである時のみ有効です。
triggerオプションは、アトリビュートに値がセットされた後で呼ばれるCODEのリファレンスです。 CODEリファレンスはインスタンス自身、更新された値とアトリビュートのメタオブジェクト(これはより高度ないじり方のためもので、ほとんどの場合は無視されます)を渡されます。 read-onlyのアトリビュートに対してtriggerを設けることはできません。
handlesオプションを使用する属性委譲の実験的なサポートがあります。
この他のドキュメントは後日になります。
この3つの項目は、Class::MOPの提供するbefore、after、aroundメソッドの変更機能の、シンタックス・シュガーです。 その他の情報については、今のところ、Class::MOPのドキュメントで見つけることができます。
キーワードsuperは、overrideメソッドの外側で呼ばれた場合、no-op(無操作命令)です。
overrideメソッドのコンテクストでは、オリジナルのメソッドと同様の引数で、次のもっとも適切なスーパークラスのメソッドを呼びます。
overrideメソッドは、「私はスーパークラスのこのメソッドを上書き(オーバーライド)しています」と明示的に宣言するためのメソッドです。
このメソッド中ではsuperを呼ぶことができ、これは期待通りに動作します。
同じように、canは通常のメソッド呼び出しとしてもとしてSUPER::プシュードパッケージでも完了できます。
これはまったく、あなたの選択次第です。
innerキーワードは、superに非常に似ており、augmentメソッドのコンテクストの外では、no-opです。
innerをsuperの逆にしたものだと考えることもできます;
Moose::Cookbookに最良の記述があります。
augmentメソッドは、「私はスーパークラスにこのメソッドを追加しています」と明示的に通知する方法です。
繰り返しになりますが、Moose::Cookbookに最良の記述があります。
これはCarp::confessの機能ですが、私が毎回使うものだったので、ここにエクスポートされています。
この機能は将来変更されるかも知れませんので、あらかじめ警告しておきます。
これはScalar::Uti::blessedの機能ですが、私が毎回使うものだったので、ここにエクスポートされています。
どこでオブジェクトのクラス名のテストをする時でも、refの代わりに使うことを強く推奨します。
Mooseはunimportメソッドを通じて、これがエクスポートするキーワードを削除する方法を提供します。
これを動作させるには、あなたのコードの末尾でno Mooseとだけ通知する必要があります。例を挙げます:
package Person;
use Moose;
has 'first_name' => (is => 'rw', isa => 'Str');
has 'last_name' => (is => 'rw', isa => 'Str');
sub full_name {
my $self = shift;
$self->first_name . ' ' . $self->last_name
}
no Moose; # Personパッケージからキーワードが削除される
Mooseは何か特定のことのためのものではありませんが、あなたが望むなら、私の気に入っているものを挙げておきます; 追加はお気軽にお寄せください :)
superとinner、cannotを同じメソッド内で使用できることには注意しておくべきでしょう。
しかしながら、これらは同じクラス階層に結合することができます;
例としてはt/014_override_augment_inner_super.tを参照。
その理由は、superがoverrideモディファイアを伴うメソッドの中でのみ有効で、innerはoverrideでは決して有効ではないからです。
実際のところ、augmentは適切なinnerを探すのに当たって、全てのoverrideメソッドをスキップしてしまいます。
これは制限のように見えるかもしれませんが、私はこの二つの特徴の分割しておく(ただし共同利用できます)ことが、それらの振る舞いを予測しやすくするので、実際にそれらの使用するのを容易にすると言う意見です。 時の経過が、私が正しかったか否かを告げてくれるでしょう。
このペーパー(lbrから#mooseで勧められました)がsuper/overrrideやinner/augmentの機能の実装に導きました。これらの機能を本当に理解したければ、私からもこれを読むように勧めます。
複雑なソフトウェアにはバグが潜むものであり、このモジュールも例外ではありません。 もしバグを見つけたら、私にemailするか、あるいはcpan-RTにバグを追加してください。
Stevan Little <stevan@iinteractive.com>
Christian Hansen <chansen@cpan.org>
Yuval Kogman <nothingmuch@woobling.org>
Copyright 2006 by Infinity Interactive, Inc.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Makio Tsukamoto, tsukamoto@gmail.com