Hatena::Groupcatalyst

dann@catalyst このページをアンテナに追加 RSSフィード

2008-05-01

YAPC::Asia

YAPC::Asia - dann@catalyst を含むブックマーク はてなブックマーク - YAPC::Asia - dann@catalyst YAPC::Asia - dann@catalyst のブックマークコメント

聞きたいものが多すぎる罠。YAPC::Asiaは両方いくのはちと難しそうだからどうするかなぁ。

http://conferences.yapcasia.org/ya2008/schedule

MooseX::Types使って型定義

|  MooseX::Types使って型定義 - dann@catalyst を含むブックマーク はてなブックマーク -  MooseX::Types使って型定義 - dann@catalyst  MooseX::Types使って型定義 - dann@catalyst のブックマークコメント

http://search.cpan.org/~phaylon/MooseX-Types-0.04/lib/MooseX/Types.pm

MooseX::Typesを使って、MyApp::Types::Core とか作ると、subtypeの定義を別のクラスに出すことができます。

型定義(subtype, coerce)は基本的に使いまわしたいもののはずなので、オレオレTypesを発展させて使いまわせるようにしておくと、使いどころが結構ありそうだなぁという気がします。

moose版のHTTP::Engineのほうも、Typesを別ディレクトリに分けてみました。もう少し型が増えれば、Typesの存在意義がでてくるんじゃないかと思います。あまり再利用がされなくても、クラス定義内にtype定義があるよりは、外に出したほうが美しいかなという気がするのでいいような気がしてます。

Devel::REPLでのプラグイン機構

Devel::REPLでのプラグイン機構 - dann@catalyst を含むブックマーク はてなブックマーク - Devel::REPLでのプラグイン機構 - dann@catalyst Devel::REPLでのプラグイン機構 - dann@catalyst のブックマークコメント

MooseX::Object::Plaggableを使っていて、mixinの機構をPluginの機構として応用してるっていう点で面白いなぁと思う。で、さらにmixinする側にAOP的なフックを加えることで、Pluginの実行タイミングとフックポイントを決めている。

ただ、method modifireをフックポイントへの実行するコードの登録に結び付けているのは、もっと明示的なインターフェースのほうが美しいのかもしれないなぁ。

  • どのフックポイントに
  • どのタイミングで
  • どんな処理を

ということを登録するインターフェースが明示的にあったほうがいいのかなと。要するに、上記のことを登録する関数がPluginのRoleとしてあったほうがいいのかなぁという気がする。

現状でも、MooseとRoleの仕組みをわかっていれば、Pluginは作れるんだけど、もう少し明示的なインターフェースのほうがいいのかもなぁという気もするという程度ではあるのだけれど。

Pluginの機構はもう少し色々とみてみよっと。

Perl+Java+Rubyな仕組みをMooseで

|  Perl+Java+Rubyな仕組みをMooseで - dann@catalyst を含むブックマーク はてなブックマーク -  Perl+Java+Rubyな仕組みをMooseで - dann@catalyst  Perl+Java+Rubyな仕組みをMooseで - dann@catalyst のブックマークコメント

Rubyっぽく全てをオブジェクトとして扱えて、Javaっぽく制約をつけられて、Perlっぽくプラグインを増やせて、CPANで多くのライブラリも使えるというのが、自分の中で思っているいいとこ取りの理想の形態だなぁと思ってます。

Moose+autoboxで殆ど実現できるじゃん!ってところで、面白そうなところだなぁって思ってます。

Class::MOP++

autobox++

# パフォーマンス的にどうなるのかは気になるところですが、これはえろい人がチューニングしてくれるんじゃないかと。toyプロジェクトじゃないもので誰かが使えば結構流行るんじゃないかなぁ。

Mooseの気持ちいいところ

|  Mooseの気持ちいいところ - dann@catalyst を含むブックマーク はてなブックマーク -  Mooseの気持ちいいところ - dann@catalyst  Mooseの気持ちいいところ - dann@catalyst のブックマークコメント

Mooseは、

  • 自然にOOできる仕組み
  • Java的にかっちり作る仕組み(interface+型による制約)
  • meta programmingを簡単にできる仕組み(Perlの黒魔術的なコードから開放される)
  • AOP的な横断的な関心毎を切り離す仕組み

があって、自然にコードを書けるのが気持ちいいなぁと思います。

AOPのadviceをMoose+Bread::Boardで

AOPのadviceをMoose+Bread::Boardで - dann@catalyst を含むブックマーク はてなブックマーク - AOPのadviceをMoose+Bread::Boardで - dann@catalyst AOPのadviceをMoose+Bread::Boardで - dann@catalyst のブックマークコメント

Mooseのmethod_modifireは、いわゆるAOPのadviceと同じで、before, after, arroundのadivceに対応するmethod_modifireが存在します。

Mooseの実装をみると、metaのmethod_modifireに登録してるだけなので(実際はMooseというよりも、Class::MOP使ってるだけ)、Mooseでクラスにaroundを直にかくっていう方法だけでなくて、もっと汎用的に使えそうです。

        around => sub {
            my $class = $CALLER;
            return subname 'Moose::around' => sub (@&) {
                my $code = pop @_;
                my $meta = $class->meta;
                $meta->add_around_method_modifier( $_, $code ) for @_;
            };
        },

Mooseを使って、aroundのkeywordを使って、直にクラスにarroundなどの定義をかいてしまうと、使える場所が限られてしまうのですが、これをRoleやクラスの実装から切り離すと、AOPと同じように、クラスの横断的な関心毎をクラスから切り離して扱うことが出来そうです。

実際には、以下のような感じでBread::Boardを拡張すれば使えそうです。

クラスをBread::Boardのサービスとして登録する際に、そのクラスのMethodのAttributeをみて、そのAttriubteがTransaction Attributeだったら、around method modifireとして、Transactionの開始終了を埋め込んだ実装を登録する

とすればよさそうです。

Mooseを使うと、Bread::BoardをベースにしたDIコンテナの仕組みも、より便利に使えそうですね。

MooseのMeta Attributeの仕組みはBread::Boardへのサービスの自動登録に使えそう!

MooseのMeta Attributeの仕組みはBread::Boardへのサービスの自動登録に使えそう! - dann@catalyst を含むブックマーク はてなブックマーク - MooseのMeta Attributeの仕組みはBread::Boardへのサービスの自動登録に使えそう! - dann@catalyst MooseのMeta Attributeの仕組みはBread::Boardへのサービスの自動登録に使えそう! - dann@catalyst のブックマークコメント

Bread::Boardだと、以下のようにdependenciesを書かないといけないですが、この部分を独立したファイルに書くのは、個人的にはあまりよい方法ではないんじゃないかなぁと思います。

             service ’application’ => (
                 class        => ’MyApplication’,
                 dependencies => {
                     logger => depends_on(’logger’),
                     dbh    => depends_on(’Database/dbh’),
                 }
             );

何故、これがよくないかというと、冗長だからです。

Mooseで作るクラスでは、

package MyApplication;
use Moose;
has 'logger' ...

と記述するわけで、loggerに依存しているというのは、そのクラスをみればわかります。知りたいのは実装クラスが何か、要するにloggerを実装したクラスが何か?というのがだけがわかればよいわけです。

ですから、Bread::Boardのように記述するのではなくて、コンテナ側に登録するコードで書くのではなくて、injectされる側のAttributeに何をinjectするのかを明示させたほうがいいだろうなと思っています。

以下のようにして、Serviceの登録部分は自動でするというのが、いいんだろうなぁと思いました。

  • lib/MyApp/Service/* をざっとなめて、serviceクラスをリストアップ
  • dependenciesは、各クラスのhasに書かれたattributeからinjectしたい実装クラスをinject

Attributeの追加とあるAttributeのついたもの取得は、以下のCookbookにある方法でできることがわかりました。via yappo さんblog

http://search.cpan.org/~stevan/Moose/lib/Moose/Cookbook/Recipe21.pod

ということで、上記のことも実現できるじゃん!と思っていたのでした。Mooseかわいいよ、Moose。

Role+Method Modifiersによるプラグイン機構

Role+Method Modifiersによるプラグイン機構 - dann@catalyst を含むブックマーク はてなブックマーク - Role+Method Modifiersによるプラグイン機構 - dann@catalyst Role+Method Modifiersによるプラグイン機構 - dann@catalyst のブックマークコメント

Moose使って、Method Modifiersをクラスに直に埋め込んでしまうとあまり使いどころがなさそうだなぁと思っていたのだけれど、Roleのメソッドにくっつけて使うのを、id:tokuhiromさんが書いていて、これは面白いですね。

Devel::REPLのプラグインの機構から拝借してるとのことですが、なるほどなぁと思いました。プラグインの機構としてRoleとMethod Modifiersを使うのは面白いなぁと思いました。

Pluginのフックポイントに対して、どのタイミングでフックさせるのかをMethod Modifiersで指定させて、Roleではフックポイントにフックさせる実装を用意するという形です。

Moose::Roleの使い方のサンプルp

Moose::Roleの使い方のサンプルp - dann@catalyst を含むブックマーク はてなブックマーク - Moose::Roleの使い方のサンプルp - dann@catalyst Moose::Roleの使い方のサンプルp - dann@catalyst のブックマークコメント

MooseのCookbookからRoleのInterfaceとしての役割を示すエッセンス部分を切り出してみました。

http://search.cpan.org/dist/Moose/lib/Moose/Cookbook/Recipe10.pod

#!/usr/bin/env perl
use strict;
use warnings;

{
    package Comparable;
    use Moose::Role;

    requires 'compare';

    sub equal_to {
        my ( $self, $other ) = @_;
        $self->compare($other) == 0;
    }
}

{
    package US::Currency;
    use Moose;

    with 'Comparable';

    has 'amount' => ( is => 'rw', isa => 'Num', default => 0 );

    sub compare {
        my ( $self, $other ) = @_;
        $self->amount <=> $other->amount;
    }
}

my $currency10 = US::Currency->new(amount => 10);
my $currency20 = US::Currency->new(amount => 20);
my $other_currency10 = US::Currency->new(amount =>10);

warn $currency10->compare($currency20); #-1
warn $currency20->compare($currency10); #1
warn $currency10->equal_to($other_currency10); #1

Comparableというクラスが、Interfaceとしての役割を果たしていて、MooseのRoleになっています。このComparableを実装する人は、compareメソッドを実装しなければいけませんよというように読みます。(equal_toメソッドがcompareメソッドが実装されることを期待してます。)

Comparableを実装する具象クラスが、US::Currencyです。withというキーワードはMooseのキーワードで、JavaのImplementsみたいなものだと思ってください。要するに、このInterfaceを実装しますよということを明示します。このクラスで、compareメソッドを実装すると、equal_toメソッドも実装されます。

さて、これでcompareというメソッドを実装しない場合は、どうなるか試してましょう。compareをcompare2と名前を変えて、perl -wcでチェックすると、以下のようにcompare実装しろ!と怒られます。ちゃんと、Interfaceの役割として機能してますね。

'Comparable' requires the method 'compare' to be implemented by 'US::Currency'

ゲスト