#moose で hi というと que tal, tokuhirom などと話かけられるが、これは how are you の意味なので動転してはいけない。
スペイン語らしい。 id:miyagawa++
TOP>2008年05年
#moose で hi というと que tal, tokuhirom などと話かけられるが、これは how are you の意味なので動転してはいけない。
スペイン語らしい。 id:miyagawa++
Wassr というすばらしいサイトがあるのですが、そのサイトでは XMPP でユーザーの更新情報を得ることができたり、発言情報をえたりできます。
このサイトで、それを実現させているのは、bradfitz の DJabberd というソフトウェアみたいです。これを使うと、容易に XMPP Server を構築することができます。Perl でできているので、割と簡単につくれます。もちろん bradware なので、bradware っぽい感じではあります。わからないことがあったら Livejournal のコードを読む必要があるので要注意です。
DJabberd は Danga::Socket を使った IO 多重化の1スレッドで動いています。Danga::Socket で構築されていますので、Gearman::Client::Async を使うことができます。というか、基本的に重い処理はすべて Gearman にやらせるようにしないと、サーバーがふんづまりますので、基本的にはすべての処理は Gearman にやらせるようにします。
さて、そんな DJabberd ですが、Wassr では
という3つのモジュールを定義しているようです。
RosterStorageAlwaysBoth というのは、とりあえず話しかけてきた人を全員友達扱いにします。
Bot は、その名のとおりボットのコアです。DJabberd::Bot を継承しています。DJabberd::Bot はソース読まないと使い方わからないので、がんばって解読します。基本的には process_text というメソッドを上書きすればいい。それだけです。
# $text is flagged utf8.
# $from is DJabberd::JID
# $from->as_bare_string; : jid string
# $ctx is DJabberd::BotContext
# $ctx->reply required 'flagged utf8 string'
というような引数の状況でよばれます。jid というのは、Jabber ID の略で、ユーザーの識別符号ですね。DJabberd の中では DJabberd::JID というオブジェクトで表現されています。
さて、これで済めば、なにも問題はないのですが、DJabberd::Bot はエラーの処理がちゃんとできてなくて、エラーパケットもそのまま process_text メソッドにわたってきます。しかしながら、エラーパケットであるという情報を得る手段が process_text の引数にはありません。なので、send_stanza メソッドを ad-hoc に拡張しています。
sub send_stanza { my ($self, $stanza) = @_; if ($stanza->isa('DJabberd::Message')) { ######### XXX START TOKUHIROM PATCH if ($stanza->attr('{}type') ne 'chat') { warn "unknown packet type " . $stanza->attr('{}type'); return; } ######### XXX END TOKUHIROM PATCH 以下略
AdminExtesion というのは、DJabberd の admin port(perlbal の admin port みたいなもの) のコマンドを拡張しているだけの存在です。DJabberd::Connection::Admin::CMD_* を定義して、admin port から情報を流し込めるようにしています。
22:56 tokuhirom: http://perl-mongers.org/2008/05/typo-and-test-spelling.html 22:56 tokuhirom: これなんだけど 22:57 tokuhirom: 俺の pmsetup だと、MANIFEST.SKIP に ^t/9\d_.*\.t って書いて skip してある 22:57 tokuhirom: たぶんこれは、miyagawa さんのバージョンからぱくってきたような気がする。 22:58 tokuhirom: miyagawa さんか yappo さんか typo さんか、そのへん。 22:58 tokuhirom: (つまり、pmsetup 公開している人のうちのだれか。 22:58 tokuhirom: >tomyhero さん 22:58 typester: しかしいないようだw 22:58 tokuhirom: なぬ
ENV で分岐させてもいいんだけど、いちいち設定するのめんどいから 9/\/id_*.t を全部スキップしちゃうとかいう風に命名規則をつくると楽。
とかおもってたんだけど、最近は xt/ っていうディレクトリをつかう流れだそうな。一回聞いてたんだけどさっぱり忘れてた。
see also:
みなさんこんにちは。Roppongi.PM の id:tokuhirom です。あいかわらず Moose よんでます。stevan のコードはわかりやすいのですが、普段あんまりつかわないような概念が多くて、その概念を理解する方に時間がかかりがちですね。
さて、本題です。
has の metaclass アトリビュートはたしかに便利なのだが、この手法だと、再利用性にとぼしいです。複数の機能をもったものを同時につかうことができないですね。
どちらかというと、アトリビュートのメタクラスを指定する感じじゃなくて、アトリビュートのメタクラスに Role をぶっこめた方が便利だなあ、と誰でも思うはず。
そんなあなたのための機能が、traits です。これは Moose::Cookbook にもまだのってない機能なので、あまり知られてないかもしれません。
↓のようにして trait は定義します。基本的に定義の仕方は通常のMoose::Role とおなじです。
package My::Attribute::Trait; use Moose::Role; has 'alias_to' => (is => 'ro', isa => 'Str'); after 'install_accessors' => sub { my $self = shift; $self->associated_class->add_method( $self->alias_to, $self->get_read_method_ref ); };
install_accessors メソッドの after を hook して、alias を定義しています。とても簡潔ですばらしいですね。
これをつかうときは、こんなかんじですなー。
package My::Class; use Moose; has 'bar' => ( traits => [qw/My::Attribute::Trait/], is => 'ro', isa => 'Int', alias_to => 'baz', );
んで、これが実際にどうやってつかわれるかというと、
my $anon_class = Moose::Meta::Class->create_anon_class( superclasses => [ 'Moose::Meta::Attribute' ], roles => [ qw/My::Attribute::Trait/ ], cache => 1, ); $anon_class->new( bar => ( is => 'ro', isa => 'Int', alias_to => 'baz', ) );
ってな感じですな。匿名クラスはこんなところでも活躍していますねー。
基本的には metaclass 指定するよりは traits つかうのがよさそうですね。