2016年12月31日

2016年まとめ

会社のブログ書きました

Posted by Yappo at 22:43 | Comments (0) | TrackBack

2014年07月09日

YAPC::Asia 2014 でトークしたい

最近は他の言語とかの勉強をちょっとづつしてるんですが Java8 がでてぞんがい普通っぽくなったらしい Java を特に使ってみようと思って色々覚えようとしてるなかで、逆に Perl への気づきや学びやつらさあるところ等を発見する機会になったので、外から見た Perl という観点で

Java For Perl Mongers

というタイトルでトーク募集しています。

JPA の会長が

って言ってて危機感感じたので、僕しゃべりたいのでJava For Perl Mongersのページの中にあるソーシャルボタンでガンガン拡散してもらえると嬉しいです!

よろしくおねがいします!!!

Posted by Yappo at 13:58 | Comments (0) | TrackBack

2014年06月09日

\s is space character, and includes 'no-break space(0xA0)'.

perl -E 'my $x = pack "C", 160; $x = "A${x}B"; say(join ",", unpack "C*", $x); $x =~ s/\s//; say(join ",", unpack "C*", $x)'
65,160,66
65,66
perl -E 'my $x = "ム"; say(join ",", unpack "C*", $x); $x =~ s/\s//; say(join ",", unpack "C*", $x)'
227,131,160
227,131

160 = 0xA0

UTF8 string に対して、うっかり byte data に対して s/\s// とかすると 0xA0 を使っている UTF8 string が broken どす。

\s is space character, and includes 'no-break space'.

Posted by Yappo at 22:35 | Comments (0) | TrackBack

2014年04月03日

re: Text::Xslateで未設定の変数を検出する a.k.a Text::Xslate hash_with_default best practice

むかしごろーがText::Xslateで未設定の変数を検出する - Islands in the byte streamで、未定義のテンプレート変数を使おうとしたら警告だすソリューション作ってたけど、それだと [% IF unknown_var %] とかした時に true 扱いになってしまってひどい目に合うので、いい感じにするソリューション書いてみた。

hash_with_default の callback では undef を返しつつ、存在しない事を目立つ感じでレンダリングするかんじ。

で、これは毎回 controller が hash_with_default するのめんどいので Proj::Web::render を生やして Amon2 で透過的に使えるようにしようとおもった。
そして、 tie hash とかアクセスしまくるとパフォーマンスに悪影響あるから本番で動かさないの鉄則ね。

HASH の中の HASH の key も調べたいなら hash_with_default_walker みたいな関数でやればよさそう。

あと Text::Xslate 3.1.2 は if (exists $self->[0]{$key}) すべきところを if (defined $value) してるので、バージョン上がるのまったほうがいい(pull request 投げたので、次のバージョンで治ってる)

Posted by Yappo at 16:31 | Comments (0) | TrackBack

2014年04月01日

Yokohama.PM #10 でひとつ上のmysql について話してきました #yokohamapm

最近ここで色々調べてた、あまり良く知られてない DBD::mysql の便利機能についてまとめて発表してきました。

http://yappo.github.io/talks/2014-yokohamapm10-dbd_mysql/

このへん知っとくとひと皮むけた感じに成長出来ると思います。僕は結局 mysql_use_result だけたまに使ってます。

発表終わった帰り道にZごろうさんとかにに「避け入ってる場にしては内容がむづかしすぎるよ!」と言われました。

Posted by Yappo at 12:41 | Comments (0) | TrackBack

2014年02月18日

mysql_use_result on DBD::mysql

DBD::mysql において、例えばテーブルの中に大量のレコードが入っているテーブルにクエリを投げる場合は execute で凄いブロックされた経験は誰にでも有るはず。

my $sth = $dbh->prepare('SELECT * FROM okkiinari');
$sth->execute; # ここで okkiinari テーブルのデータを全部読み込んでる

だからみんなは LIMIT OFFSET とか頑張ったりするんですが、これを回避するための mysql_use_result っていうオプションがある。

connect する時に

my $dbh= DBI->connect('DBI:mysql:test;mysql_use_result=1', 'root', '');
と指定したり、途中で
$dbh->{mysql_use_result}=1; 
(これは prepare 前にやる)したり
$sth->{mysql_use_result} = 1
したり
$sth->prepare($sql, { mysql_use_result => 1 })
したときに有効になる。

このオプションを利用すると、通常は mysql_store_result を利用して mysqld からの結果を受け取っていたものを mysql_use_resultするので、 okkiinari テーブルの全データを読み込めるだけのバッファメモリを確保しなくても省メモリで全データを舐める事が可能なのです。

mysql_use_result を使うと $sth->rows で結果行を取ろうとしても0が帰ってきたり、全レコード取得する or $sth->finish するまで、該当レコードが READ LOCK かかるみたいな雰囲気でしたが、 fetch row を1秒おきにするスクリプトを走らせながら裏でレコード更新してもロックされない(当然 fetch 中のスクリプトの内容はクエリ発行前の値が出る)とかなのでよくわかりませんでした。

ちなみに DBD::mysql は async API を使うと mysql_use_result の併用が出来ないので悲しい。
mysql_db_async_result の中で rows を取ってきて、結果があったかどうかで分岐してるんだけど、ざっとコード見た感じ使えない理由がないからよくわからない。

async API を使えても使えなくても mysql_fetch_row するとこの前で select して監視すると、 mysqld のクエリ処理が終わった後のデータ転送を似非非同期的に取り扱う事は可能ではある。
その場合は烏賊みたいなめんどっちい感じ(ちゃんと使うにはもっとだるいことになる)をすると良い。

$sth-->execute;
while (1) {
while (1) {
my $ret = IO::Select-->new($dbh-->mysql_fd)-->can_read(0);
last if $ret;
...; # *1 read 出来るまでの間にやっときたいこと
}
my $row = $sth-->fetchrow_hashref;
last unless $row;
...
}

なんで似非非同期的かというと、mysql_fetch_row の中で read_one_row するために read_one_row 経由で cli_safe_read する時に全部のパケットを読み込んでるので(参考)パケットのキリが良い時は延々と cli_safe_read の中でブロックするし MAX_PACKET_LENGTH がでっかかったら、そもそもずっと読んでるし運が良くない限り *1 とかに処理はいらないっていうオチです。そもそも普通の web アプリに於いては1個のパケットの中で結果が戻ってくるケースばっかじゃないでしょうか。

あと mysql_use_result して全件取ってきてもクライアントには優しいですが、サーバ側でどんなことになるかはよく知らないのできっと偉い人が解説してくれて、ブクマコメントに url 入れてくれるとおもいます。

Posted by Yappo at 18:59 | Comments (0) | TrackBack

2014年02月17日

MYSQL_ASYNC

dbd_st_prepare で { async => 1 } のとき
imp_sth->is_async = TRUE;
imp_sth->use_server_side_prepare = FALSE;


mysql_st_internal_execute
dbh の時
async = (bool) (imp_dbh->async_query_in_flight != NULL);
sth の時
async = imp_sth->is_async;
if(async) {
imp_dbh->async_query_in_flight = imp_sth;
} else {
imp_dbh->async_query_in_flight = NULL;
}
非同期で mysql_send_query が成功したら return 0


dbd_st_execute
if(imp_dbh->async_query_in_flight) {
DBIc_ACTIVE_on(imp_sth);
return 0;
}


dbd_st_fetch
if(imp_dbh->async_query_in_flight) {
if(mysql_db_async_result(sth, &imp_sth->result) <= 0) {
return Nullav;
}
}


dbd_st_finish
D_imp_dbh_from_sth;
if(imp_dbh->async_query_in_flight) {
mysql_db_async_result(sth, &imp_sth->result);
}


mysql_db_async_result
impl_sth->result imp_dbh->async_query_in_flight = NULL して、に結果を入れて 結果行数


mysql_db_async_ready
fds.fd = dbh->pmysql->net.fd;
fds.events = POLLIN;

retval = poll(&fds, 1, 0);


do(dbh, statement, attr=Nullsv, ...) で { async => 1 } のとき
use_server_side_prepare = FALSE; /* for now */
imp_dbh->async_query_in_flight = imp_dbh;


imp_dbh->async_query_in_flight が立ってたらだめなの
dbd_db_commit(SV* dbh, imp_dbh_t* imp_dbh)
dbd_db_rollback(SV* dbh, imp_dbh_t* imp_dbh) {
int dbd_st_execute(SV* sth, imp_sth_t* imp_sth)
int dbd_bind_ph(SV *sth, imp_sth_t *imp_sth, SV *param, SV *value,
IV sql_type, SV *attribs, int is_inout, IV maxlen) {
SV *mysql_db_last_insert_id(SV *dbh, imp_dbh_t *imp_dbh,
SV *catalog, SV *schema, SV *table, SV *field, SV *attr)

type_info_all(dbh)
_ListDBs(dbh)
do(dbh, statement, attr=Nullsv, ...)
ping(dbh)
quote(dbh, str, type=NULL)
void _async_check(dbh)

まとめ

  • libmysqlclient は関係なくて DBD::mysql 独自
  • server side prepared statement は使えない
  • execute とかで mysql_send_query したあと mysql_store_result せずに即座に戻って、 fetch とかする関数の最初に mysql_store_result を呼び出す感じであとで読むしてる
  • なので mysql_async_result 呼ばないで fetchrow_hashref とかいきなり呼んでも何も支障ないというか mysql_async_result 呼ぶだけコストかかる感じがある
  • fetch するか mysql_async_result 呼ぶまではトランザクション終了させたり新規のクエリは投げられない(同じ sth で)
  • mysql_async_ready は内部的に poll 呼んでるだけ
  • mysql_fd が読み込み可能状態じゃ無くても fetch とか mysql_async_result を急に呼び出しても何も問題ないが、単純にそこでブロックするだけだから async api 使う意味ない
  • mysql_db_async_ready は poll(&fds, 1, 0) してるだけで、 readable じゃなければ即戻ってきちゃうのでマジ使う意味ないので mysql_fd を自前で select してハンドリングしたほうがいい。とは言え、重いクエリを裏で投げてて perl 側で思い処理を並列にやるユースケースだと、 perl 側の処理終わったら mysql_async_ready 呼びまくってもいいけど、それって先に mysqld 側で処理終わってる前提なので、その前提外れると busy loop するから結局使わない方がいい
  • エラーメッセージが時たま内部の構造体のメンバ変数名だしてきてウケる
  • 大事なことですが、 mysqld から result が送られて来てからの respons 受信処理は非同期に出来ない。あくまでも mysqld 側のクエリが終わるまでの間を自由に使えるってこと

Posted by Yappo at 23:03 | Comments (0) | TrackBack

2014年02月12日

DBD::mysql Async API

MySQL の Async API 使って思いクエリを並列処理したら早いかと思ったらそうでも無い風味。
Web アプリの時のように、クライアント側の並列度があがれば差が縮まる感じだけどそうでもない。

ある程度重いクエリの想定で SELECT SLEEP(0.05) とか投げてみたけどやっぱり普通に使った方が早い。
Async API 使うのにコストがかかるのかな、と思って IO::Select 使ってみたらかなり早くなったので AnyEvent がわりとボトルネックっぽい。
とは言え微妙な誤差ではあるので、普通に DBI 使ってればいい気がしてきた。

perl 5.18.2
DBI 1.63
DBD::mysql 4.025
AnyEvent 7.07
IO::Select 1.21

async-mysql-ioselect.pl が全入りベンチ(思考回数少なめ)
async-mysql.pl は IO::Select 使う前に数回ベンチとったやつ。

async-mysql-ioselect.plを10倍ループ回したのは以下のとおりだった。

1 process
Rate Async-Serial Async-Parallel Normal IO-Select
Async-Serial 559/s -- -4% -15% -17%
Async-Parallel 583/s 4% -- -11% -14%
Normal 656/s 17% 12% -- -3%
IO-Select 676/s 21% 16% 3% --
8 process
Rate Async-Parallel Async-Serial Normal IO-Select
Async-Parallel 17.0/s -- -0% -7% -13%
Async-Serial 17.1/s 0% -- -7% -13%
Normal 18.4/s 8% 8% -- -6%
IO-Select 19.6/s 15% 15% 6% --

Posted by Yappo at 20:33 | Comments (0) | TrackBack

2013年11月26日

Shibuya Plack/PSGI Conference #1 #plackcon 開催してきた

yapc hackathon の後の飯で「最近 perl のイベント少ないからもうちょっと頑張ろうぜ!」って話になって、とりあえず plackcon やろうぜ!ってなったので開催しました。

やろうと決めたのは9月末だったけど、実際動き出したのは2週間前でとりあえずダブル基調講演の fujiwara さんと kazeburo さんの予定抑えて会場抑えて1週間前にスピーカー全員決まって募集した感じでございました。
fujiwara さんに ISUCON3 で新たに得られた知見を話してもらおうと思ってたのに実際の ISUCON3 は HTTP レイヤーの問題は殆どなくてまったくアテが外れてしまって fujiwara さんに多大な苦労を書けてしまって申し訳ありませんでした!1事前に出題内容さえしっていれば。。!

80人くらい集まる勉強会的なのやった事無かったけど、なんか知らないけど事故も喧嘩もなく終わって良かったです。 soozycon くらいのノリでも何とかなるんですね。
受付してくれたり門番してくれたり、帰りのカード回収してくれたりトイレまでの経路が無いの教えてくれたりした方々やスピーカーの方々や、ゆるふわな進行に耐えてくださった皆様並びに会場を貸してくれた LINE さんありがとうございました!

トイレのとこのドアはなんか僕でも解放出来たらしいので次あったらちゃんと生きようと思います。

ぼくの成果


教訓

「タイムキーパー重要」
つぎなんかやる時にタイムキーパーするひと探してからやります。。

Posted by Yappo at 17:48 | Comments (0) | TrackBack

2013年09月30日

homebrew libpng and Imager::File::PNG with Carton

for cpanm
$ cpanm --look Imager::File::PNG
$ perl ./Makefile.PL --libpath=/usr/local/opt/libpng/lib --incpath=/usr/local/opt/libpng/include
for carton
$ cd /usr/lib
$ sudo ln -s /usr/local/opt/libpng/lib/libpng.dylib
$ cd /usr/include
$ sudo ln -s /usr/local/opt/libpng/include/png.h
$ sudo ln -s /usr/local/opt/libpng/include/pngconf.h
$ sudo ln -s /usr/local/opt/libpng/include/pnglibconf.h
普通だと Makefile.PL にオプション与えれば済むけど、 carton だとそういうの出来ないので手っ取り早く symlink でできるよ。
Posted by Yappo at 18:40 | Comments (0) | TrackBack

2013年09月24日

YAPC::Asia 2013 #yapcasia

今日みた夢が「blog 書かないと干すぞ!」ってがちぎれる941さんとlestrratさんがでてきたので書く事にした Yappo です。みなさん週末はいかがお過ごしでしたか?僕はカート大会いって箱根で温泉と美味しいご飯食べてきました。

本編発表資料

社内開発簡単化と世界で戦う開発を考える技術
明らかに会場でかくていっぱい人見に来る、裏発表の DeNA の人が Yappo に負けないクオリティにする!的な宣言してて泣きそうになったのでささやかな反撃でタイトルぱくりました。

1日目の午後一から40分の枠をもらったので、仕事向けのアプリケーション開発で考えなきゃいけない事と、雛形スクリプトを作る時に便利なKsgkの紹介をしました。基本的にはコピペ脳は害でしか無いのでいかにしてコピペを排除するか、ちゃんと自分の頭で考えていくか。のような話をしました。

わりとぐにゃらくんの発表内容に近い。というか作ってる雛形の思想が MobaSif に近い物があるので、雛形で生成されるコード(=WAF)は既存の有用なモジュールのグルーを提供する。みたいな事を僕も言ってたのですがぐにゃらくんも言ってたらしいですね。 GunyaSif のプレゼン見にいこうと思ってたら時間がすぎてたので何かでみようと思います。

割と最近僕はアウトプットしてなかったので、ここ一年で僕がやってきてた事の紹介をする。というテーマの裏には、同僚の人達へのプレゼンもついでに行うつもりでやってた、というか後者の目的が大きかったのですが、YAPC開催週に入社したての人が僕のを見てて実際にうんうんうなずかれると逆に照れて緊張するというのを発見した。

僕の発表が少しでも参考になって皆が楽になると嬉しいです。

LT: HTTP::Body::Builder

I NEEEEEEEEEEEEEED HTTP::Body::Builder !!!!!!1111

いっつも multipart/form-data の API を叩く時にまともに処理できる CPAN module が無くていらっとしてたんですが、まぁわりと〆切追われたりしてる時だから適当に乗り越えてたんですね。
ここ最近もそれやる必要になって mala に「いい方法しらない?」って聞いたら自分で作るしかないねって言われた事が発端となってやった LT です。

日本の LT とかだと割とこういう「俺の欲しいモジュール誰か作ってくれ!」プレゼンって少ないのですが、具体的な仕様を提示してお願いする感じにすると割とちゃんとした反応があるので有用かなと思います。今回もみんな HTTP::Body::Builder の必要性感じてくれましたし。

LT終わった後ひろむが資料よこせって言ったから、多分明日の LT で実装するだろうなと思って資料 pushして放置してたら二日目のLT直前にリリースしててましたね。
僕はその時 HUB してたのですが、慌てて缶ビール買いにいってました(作った人にビール奢るって宣言してた)。

ひろむのLTで最初 Test::Power やりだして焦ったけど、ちゃんと作ったよっていったので安心して壇上にあがりこんでビール渡せましたね!
941さんが近くにいたから、絶対止められるからどうすり抜けるかとかシミュレーションしてたのですが、そのへん意図汲み取ったのか忙しかったのか疲れてたのかでガードされずにすり抜けられた。
ビール渡して満足そうに帰ってる間にひろむがビール開けて追い出されてたらしいのを見逃したのが残念でした!缶ビール直接渡すと200%飲みだすだろうから裏を読んで服数本買ってコンビニの袋に入れて渡したのに意味なかった!1

こういう、誰かが発表してた内容をカンファレンス会期中に別の人の発表でレスポンスを返す。みたいな奴はもっとみんなやった方がいいですね!
人の発表中に上がり込むのは海外でも事例あんま聞かないけどw

あとはねこむに懇談会で HTTP::Body::Builder 作ってくれる?って聞いたらお腹ぽんぽんされてマッチョの方のボディビルダーと同じ言葉だったって気づいた。

前夜祭

わりとYAPCで発表した人って感想なにも書いてないから、たまには感想も書こうとおもったからこっから書く。

ビール飲みながら資料書いてたら終わってた。

現実逃避として拍手するサイトの DOS とかしてたけど、あれ皆でやってるから本当に自分が攻撃してるやつ成立するかわかりずらいので改善が必要だと思った。

前夜祭おわって適当に HUB に集まってみんなで飲んでたけど何話してたかだいぶ記憶にない。 bonnu さんが凄かったのだけ覚えてる。

1日目

朝一でいこうと思ってたけど深遠な理由により30分おくれて出発したけど、途中で特急待ちとかで次の電車が30分後くらいのエキセントリックな状況になったので東京駅から成田エクスプレスにのって武蔵小杉まで行った。乗り換えだるくて死にそうだった。

前日のうちから資料が出来てて余裕だったので kazeburo さんの話から参加して聞いてた。 kazeburo さんと一緒に ptrace した事あるから読めた。

kazeburo さんの終わってから昼飯までの記憶が無い。

ひるは学食。 overlast が「学食なんてどんなメニュー頼んでも全部同じ味だから一緒」とか酷い事言ってた。 miyagawa さんが持ち運び無線充電器の話してた。

自分のトーク終わってから、ぼーっと takesako さんの話みてたら会長から急遽今日の LT でれるか?!?って聞かれたので、今から作るでれるって応えた。

習字が飾ってある所で寝ながら資料作る。

ねるの秋田から BoF スペースで資料作ったら makamaka さんが Acme 大全の要望募集してまーすって言ってたから dan.pm 入れてっていったら「!?!?」ってされた。なんてこったい。

思量出来たからお店で飲食して休憩してから LT に行った。

準備とか資料公開であんま聞いてなかった。

懇親会

techno_neko さんに「本当は Plack::Middleware::ServerStatus::Audio 作って LT したかったんすよー」とか話してたら、それに近い話さっきしてたっていわれて、実際に作った人いた。けど、やっぱり全部 Perl で完結させたいからアイデア上げるから作って下さい!って言ったので完成楽しみ。あと Hokkaido.PM に呼んでくれるって言ってくれたのでそれも楽しみ。(ちなみに去年の懇談会で Fukuoka.PM 呼んでくれるって言ってくれて今に至るので嫌な予感しかしてない)

にこにこしながら dan さんがやってきて LT 資料の英語に凄いどや顔でつっこみ入れられてる時に makamaka さん通りがかったので捕まえて dan.pm ちゃんとみたかどうか聞いたけど dan さんがキョトンとしてどっかへ去った。

dan.pm って下らない事やってるけど、わりと皆のしらない Perl の機能つかってすごい頑張ってるから良いよ!って説明してて、今度はまた皆しらない機能使って Acme module 作るって宣言しといた。

あと Amon2::Plugin::L10N のお陰で仕事が凄く速くおわってたすかった!って言われたのでこんな僕でも生きてる価値が1mmくらいあるってわかった。

1日目夜

だんじょうさんが飲み屋に来た

2日目

最初のセッションから余裕で参加。 ikasama さんの見た。女の子の写真みて ikasama さんが癒されてた。

hidek さんの見ようと思ったけど gossy product 追っかけてなかったから、 hidek さん干しで見にいった。 PerlMotion 動くとこまでいっててよかった。みんなもこの辺のやるといいよ。

昼は LINE の会社の人事の人が弁当余らせてこまってたから、みんなでもらって適当に外でて地べたに座って食べた。

ruby session は mput さんが暴れないというサプライズがあった。

ruby session おわってから皆で HUB いった、 mput さんが Ruby 1.9.x からインデントが狂ってると警告を出すオプションが追加された、コアの方で実装されてる。って言ってて、これ便利そうだから Perl に持ってきたらいいと思った。あとは miyagawa さんが持ち運び無線充電器の話してた。

LT はじまるまでずっと HUB に居ててわりと本編みてない。わりと ruby session の続きの話を延々としてました。

barimi さんが言ってた初心者で twitter bot 作るってやつ。初心者は chat 的なやつの bot 作ると割とインタラクティヴ性あって楽しいので皆も初心者に与える題材として bot とか教えるといいですよ。

perl クイズで近藤さんが勝つの本当にチート過ぎて酷かったw

ikebe さんのアンコールセッションでサプライズ発表があると思ってたけど、本当にサプライズ卒業発表しててびびりましたね。

後夜祭

始まるまで適当な店入って時間潰してたら、超満員とか言ってたので gfx しました。さんまの刺身美味しかった。

わりともうみんな疲れてた

hackathon

こんかいみんな cookie とか言ってて良くわからないからググって cookie clicker hack してた。

javascript:setInterval(function () { $("#bigCookie").click(); }, 1);
javascript:setInterval(function () { if ($("#goldenCookie").style.display == "block") { $("#goldenCookie").click() }; }, 100); 

こんな感じで捗る事を理解した。

あとは makamaka さんと話してた Acme の実装作る為に perlguets の読み直しとか、実装の mock を作ったりとかしてたけど、だいぶ疲れてるからスローペースでしたね。

打ち上げの店のキュウリがおいしかった。

race

50msec で一周するカート大会にいってきた。道中の電車で心臓ばくばくしすぎてて死にそうだったけど、運転したらそういう疲れが全部吹き飛んだので、単純に室内にこもりすぎてて不健康になってっただけだったという結論になった。次 YAPC やる人は運動とか取り入れた方がいいですよ。

レース結果は僕のチームBが3位で、ベストラップの順位が2位だったので、うっかりトロフィー貰っ贈呈禁止規定に引っかかって処分されなくてよかった。

かえりは箱根ちかいから温泉いって、渓流沿いの飯やでうまいめしをくった。特に YAPC 中はちゃんと和食食えてなかったのでめちゃうまかったは。

next event

hackathon の後に、わりとイベント少なすぎるから皆気合い入れてあつまるからコンスタントにイベントやろう見たいな話をしてて、 Shibuya.pl という Plack のイベントをやる事にした。とりあえず fujiwara さんとか ISUCON3 で忙しいので、それが終わった後の11月の平日にでもやりましょう。
ikasama さんも11月くらいに Testing Casual やるって言ってるから要調整

「YAPC::Asia もう終わりって言ってるけど、やってほしいなでも自分はやりたくないな」とか思ってたら本気でもう開催されないってのを皆は認識した方が良くて、別に1000人とか集めなくていいので300人規模とかで来年からやるとかでもいいですね。僕も開催しないから適当だけど。

とりあえず来年は東北で YAPC::Asia が開催らしいから、いまから東北旅行楽しみです。

Perl徹底攻略 (WEB+DB PRESS plus)
大沢 和宏 cho45(さとう) 小林 篤 和田 裕介 嶋田 裕二(xaicron) 牧 大輔(lestrrat) 奥 一穂 広木 大地 伊藤 直也 長野 雅広 藤原 俊一郎 伊藤 智章 まかまか般若波羅蜜 小飼 弾 近藤 嘉雪 中川 勝樹 宮川 達彦 tokuhirom 藤 吾郎(gfx) 村瀬 大輔
技術評論社
売り上げランキング: 7,279
Posted by Yappo at 12:59 | Comments (0) | TrackBack

2013年09月19日

今日はYAPC前夜祭ですね & 明日のYAPC1日目でしゃべります

今日は YAPC の前夜祭ですね!
今年の YAPC の前夜祭は、去年の YAPC で好評を博した 前夜祭 が 慶応大学が会場 となって開催されます!
僕は 前夜祭 には参加者として参加していて、楽しい催しになるように努力しますので是非是非ご参加下さいませ!
前夜祭 - YAPC::Asia Tokyo 2013

さて、明日のYAPC1日目、13:00〜13:40 では僕が「社内開発簡単化と世界で戦う開発を考える技術」と題して発表致します。
が、なんかスライド書いてたら「amon2-setup.pl を俺色に染める」というよりは「僕の一年間の Open & Share」みたいな感じになってしまったので、
多分そういう感じの話になると思います。僕の一年間 に詳しい方は既に知っている情報が多い感じなので、そこら辺ご注意下さい!
本トークでは具体的に言うと以下の様な話をする予定です。

- ありがちな開発初期に行う呪文のコピペ
- コピペを無くす為に考える事
- それの失敗談
- アプリ開発で便利な最近僕が作ったモジュール
- ops のヒトから椅子飛んでこない為にやってる事
- 雛形で作ったアプリのテストを Ukigumo 連携する事についての所感

ただ、最後の Ukigumo の所はどうでしょうか、もしかしたら無理かもわかりませんね!
なぜならまだスライドが完成していないのです。ハラハラ。

アプリケーションのディレクトリ配置や、標準でセットアップされるべき機能から deploy 初期設定全般 の情報は非常に便利だと思っているんですが、その情報は最近表にでてこないので、そのあたりの知識の共有や議論なんかも出来ると素晴らしいと思っております。
「こんなことやってるぜ!」という知見をお持ちの方は talk 中に話割り込んできていいので是非教えてください!

それでは皆様、YAPC 会場でお会いしましょう!

参考文献

Posted by Yappo at 16:11 | Comments (0) | TrackBack

2013年09月05日

配布するスクリプトが依存しているモジュールを実行時にスマートに入れてもらう方法

社内ツールなどで Perl スクリプトを配布する時にいちばん気になるトピックとしては、スクリプト中で依存しているモジュールをどうやってインストールさせるか?
という所ですね、最近は toolchain が強まってきて cpanm --installdeps . とか carton install をやってもらえば良いのですが、たかだかちょっとしたツールだったら git clone してもらってすぐにスクリプト叩いてもらいたんじゃんすか

ってことで、スマートかつクールにこの問題に対処するスクリプトの雛形を書いてみました。 core module 以外には Carton を予め入れておく必要があるのがまだまだ敷居高いですが、エンジニア向けのツールだったらだいぶ手間は下がるでしょう。

ポイントとしては、コードで使うモジュールを use する前の BEGIN ブロックで必要なモジュールを既に入れておくので、 Acme::Hidek が未インストールな状態でもエラーにならずに実行可能という点と、 carton を使って依存モジュールをインストールしているので carton exec で起動した相当の処理を行っている点です。

ここから話を広げた話題を YAPC::Asia 2013 TOKYO で発表するので興味のある人は来るといいです。

Posted by Yappo at 17:43 | Comments (0) | TrackBack

2013年07月25日

Try::Lite supported of older perls

I fixed Try::Lite's nexted try-catch block don't work on older perls, because I received that bug report by koba04.

https://metacpan.org/release/YAPPO/Try-Lite-0.0.3/

Try::Lite は最近の Perl で開発したため、うっかり古い Perl の例外処理が変なやつに対応するのを忘れてました。

pull-req 受け取ってから4ヶ月かかってしまったんですが、例外処理ややこしいせいがあってパッチの意図が良くわからんくて放置してたってのがあります!
最初貰ったやつだと RAII して $@ を良い感じに元に戻すみたいな事してたけど、よく考えたら普通に書けば RAII いらんくなったので今の形になりました。

Try::Lite だと catch block での error は $_ に入れてくれるので $@ の nest とか考えなくていいのですが、 Try::Lite だと $@ を使ってて 5.12 以下の時に色々配慮しないとだめなので頭ぐるぐるしてました。


Perl 徹底攻略の記事でも書いたけど、やっぱり例外処理は自分で作らずにこういうモジュールを使っとくといいのです。
まぁ、最近の perl だとまっとうな感じになってるので、新しいのみんなつかおう

Posted by Yappo at 18:54 | Comments (0) | TrackBack

2013年07月18日

Perl徹底攻略という本を作った話

来週火曜日に、ここ最近もっともイケてる Perl の本が出ることになりました。
ちなみに僕もなんか書いてるけど、役に立つことは書いてません。

基本的には Web+DB PRESS で連載されている記事が集まっていますが、ちょさんの部分は Perl 5.18 までの話題を取り扱ったり、yusukebeのところなんかは Twitter の API がもろもろ変わっちゃったので、ほぼ全部書き直しで YouTube API の話になってたりとか、既存の連載を読んでる人にも新しい情報ありますね。

載っている記事としても連載だけではなくて弾さんのアルファギークに逢いたいから Perl Hacker が出ている記事を中心に再収録してあるところもポイントです。
あとは今回のために naoya さんが新規に原稿書いてくれた事も目玉ですね。内容としては「Perlプログラミング救命病棟2013」みたいな感じです。

基本的には Perl の初歩の初歩というオライリー系の本を読めば済むような話は載っていなくて、ラクダ本、はじめてのPerlを読み進めた人が、次に何をしたらいいのか?という道標として使いやすい構成になっています。

構成としても、最近の Perl の新機能や難しいリファレンス周りの解説から入っていって、今どき主流の Perl 開発環境セットアップのしかた、そして Web アプリを作る上で基礎になる PSGI/Plack の勉強をして、Web アプリ開発の実践としての Amon2 紹介、そしてテンプレート、データベス。
という形で、オライリー本の次の人達が用意に近代 Perl を学べる形になってます。

そこから先も、本当に仕事で使える知識が続いていっているので Perl の会社に入りたての newbie な人も実践で使えるんじゃないかと思いますね。
また単純なプログラミングの話以外にも Perl の文化的な記事も多めに取り入れているのでだいぶ捗ると思います。


実際現物が届いてページを捲ってみると、良い感じの構成になってるなーと思いました。
最初は Perl Hackers Hub だけ再収録って話だったんだけど、途中からどうせなら Web+DB PRESS の Perl 周り集大成的に弾さんのも全部ぶっこもうぜ!って言ったら採用されたりとかして、幅が広がってよかったりとか、価格についてもみんな色々話あってたりとか色々あったけど書くのめんどくさくなった。
緒方さん稲尾さん、どうもありがとうございました&おつかれさまでした!1

という事で、1社に10冊くらい置いといても良いくらいの本なので、どうぞご予約ください。

Perl徹底攻略 (WEB+DB PRESS plus)
大沢 和宏 cho45(さとう) 小林 篤 和田 裕介 嶋田 裕二(xaicron) 牧 大輔(lestrrat) 奥 一穂 広木 大地 伊藤 直也 長野 雅広 藤原 俊一郎 伊藤 智章 まかまか般若波羅蜜 小飼 弾 近藤 嘉雪 中川 勝樹 宮川 達彦 tokuhirom 藤 吾郎(gfx) 村瀬 大輔
技術評論社
売り上げランキング: 7,279
Posted by Yappo at 14:53 | Comments (0) | TrackBack

2013年06月11日

perl prototype constant bug?

Yappo::proto is not inline expansion?
in perl 5.18.0
本来なら Dump(Yappo::proto); となってる部分はコンパイル時に Dump(1); という解釈されてるので my $x = Yappo::proto . ''; のところで Yappo::proto の中身に PV の値が入ってても関係無いはずなのに実際は関係ある。みたいな変な挙動になってる。 というか定数なのに内部的に文字列の "1" が追加されちゃってる。
Posted by Yappo at 19:14 | Comments (0) | TrackBack

2013年05月23日

while or goto

use strict;
use warnings;
use Benchmark 'cmpthese';

cmpthese( 100 => {
wile => sub {
my $i = 0;
while () {
return if $i++ == 1_000_000;
}
},
goto => sub {
my $i = 0;
LOOP:
return if $i++ == 1_000_000;
goto LOOP;
},
});

__END__

# on v5.16.3
Rate goto wile
goto 9.37/s -- -54%
wile 20.4/s 118% --

# on v5.17.2
Rate goto wile
goto 7.22/s -- -54%
wile 15.8/s 118% --

# on v5.18.0
Rate goto wile
goto 9.30/s -- -43%
wile 16.2/s 74% --

Posted by Yappo at 14:37 | Comments (0) | TrackBack

2013年05月15日

zh-hans, zh-hant に対応してない!って怒られた時は

Amon2::Plugin::L10N だと以下のように書けます。
po/zh-hant.po とか po/zh-hans.po とかは用意しとかなくていいです。きもちわるいけど。

my $LANG_RE = qr/\A(?:en|ja|zh-tw|zh-cn)\z/;
__PACKAGE__->load_plugins('L10N' => {
    default_lang          => 'en',
    accept_langs          => [qw/ en ja zh-tw zh-cn zh-hans zh-hant /],
    po_dir                => 'po',
    before_detection_hook => __PACKAGE__->is_development ? sub {
        my ($c) = @_;

        my $param_lang = $c->req->param('lang');
        if ($param_lang && $param_lang =~ $LANG_RE) {
            $c->session->set('lang', $param_lang);
            return $param_lang;
        } elsif (! defined $param_lang) {
            my $session_lang = $c->session->get('lang');
            if ($session_lang && $session_lang =~ $LANG_RE) {
                return $session_lang;
            }
        }
        $c->session->set('lang', '');
        return;
    } : undef,
    after_detection_hook  => sub {
        my($c, $lang) = @_;
        return 'zh-tw' if $lang eq 'zh-hans';
        return 'zh-cn' if $lang eq 'zh-hant';
        return $lang;
    },
});
Posted by Yappo at 20:45 | Comments (0) | TrackBack

2013年05月09日

Amon2 で国際化アプリを簡単に書く Amon2::Plugin::L10N を出しました

Perl で L10N する方法としてはPerl でつくった web サイトを L10N する方法 - tokuhirom's blog.が有名ですが、昨今はうっかりパンケーキとか唐揚げを食べてたらロンドンとかに海外進出しちゃうようなのが当たり前になった現代においては、 blog のコードをコピペするやつは死んどけば良いので、死なないため殺されない為に実用的に CPANize して殺す側に回りました。

https://metacpan.org/release/Amon2-Plugin-L10N/(現在の最新版は v0.1.3 です。)

貴方のプロジェクトのベースクラス、例えば Amazlet.pm などの中に以下のコードを埋め込みます。

__PACKAGE__->load_plugins('L10N' => {
    accept_langs => [qw/ en ja zh-tw zh-cn fr /],
});

その後 xslate の function として以下のような関数を登録するのです。

sub l {
    my $string = shift;
    my @args = map { Text::Xslate::html_escape($_) } @_; # escape arguments
    Text::Xslate::mark_raw( Amazlet-> context-> loc($string, @args) );
}

そうすると temp/index.tt などの中に [% l('hello! amazlet world!') %] などと書けるようになります。

po/ja.po とかが適切な感じで入っていれば 'hello! amazlet world! が適切な言語の物に変換されて表示されます。

po ファイル管理だるい

自前で ja.po とか作るのだるいので簡単なスクリプト添付してあります。ただ、スクリプトを動かす為のモジュールは標準でインストールされないので

$ cpanm --width-suggests Amon2::Plugin::L10N
とやって入れてから
$ amon2-xgettext.pl en ja zh-tw zh-cn fr 
ってすれば lib や tmpl 以下の中から適切に探して作ってくれます。

まとめ

Amon2::Plugin::L10N を使ってみんなで国際化して変化でガラパゴスしましょう。詳細は pod 見ると良いです。

Posted by Yappo at 17:38 | Comments (0) | TrackBack

2013年04月25日

HTTP::AcceptLanguage - Accept-Language ヘッダを解析して適切な言語を返す君

月曜日の悪魔こと yappo です。
今時のグローバルな社会ではみなさん多言語対応の web アプリを書いているとおもいますが、その時に使う Accept-Language を解析してくれるのを書きました。

HTTP::AcceptLanguage

Plack なアプリだったら。

my $lang = HTTP::AcceptLanguage->new($req->header('Accept-Language'))->match(qw/ en fr es ja zh-tw /);
ってするだけで、英語フランス語スペイン語日本語台湾語の中からユーザが利用可能な最適な言語を探して返してくれます。

もし適切な言語が無ければ undef を返すので、あなたがおすすめの言語で返しておくといいでしょう。

I18N::AcceptLanguage っていうのが既にあるんですが、名前空間がわかりづらいのと、ドキュメントがわかりづらいのと、コードが余計な事やってるのと、インデントが独自すぎてコード読めないのと、頑張ってコード読むとバグがあったり解釈がRFCの通りになってなかったりして、ハマった時のデバッグが不能だったので作りました。

まぁ、 RFC の件はあんまどうでもいい。っていうか RFC なんか信じてたら世界が破滅するので厳密な実装にはなってなくて、あるていど実用的にしてあります。

Posted by Yappo at 17:06 | Comments (0) | TrackBack

2013年04月01日

#perlcasual で例外処理の話した

こんにちわ!
先週金曜日に NHN で開催された PerlCasual っていうイベントで Perl の例外処理最新ベストプラクティスの話をして来ました。

http://yappo.github.com/talks/20130329-perlcasual7-exception/

yusukebe が開催するよって言うから、話したいって言ったら「もうスピーカーきめちゃった!」とか言われてたんですが、カジュアルに仲間に入れてもらえました。

スピリチュアルな話とかぼうよくわからないんで感想とか書けないんですが、yusukebeさん駄目な人間さん、NHNさんありがとうございました!

Posted by Yappo at 18:17 | Comments (0) | TrackBack

2013年03月26日

lingr-ircd でお気楽 perl チャット

最近 Perlの話題を日本語で – Lingr という革新性力が活発ですが、やっぱり lingr は情報密度が薄いから、情報密度が濃い irc client から使いたいっていう事で1週遅れで導入しました。

材料

  • Perl(筆者はCentOSに最初から入ってる5.8.8を使っています)
  • Carton(適当に入れてください、筆者は sudo cpan Carton で入れました)
  • git

入れ方

  1. git clone git://github.com/tokuhirom/lingr-ircd.git
  2. cd lingr-ircd (5.8.8 標準の Scalar::Util が Mouse で動かんから cpanfile に requires 'Scalar::Util' => '1.27'; っての追加した)
  3. carton install
  4. Developer CenterのYour Appsのregister a new appで適当にアプリ登録
  5. carton exec -- perl ./bin/lingr-ircd --ircd_host=127.0.0.1 --ircd_port=[好きな奴] --lingr_user=[lingr のユーザ名] --lingr_password=[lingr のパスワード] --lingr_api_key=[Your Apps の key 列]
  6. 移動すると入ってるチャンネル名一覧が出るから、起動した irc server につないで /join #perl_jp とかすればいい
  7. なんかユーザ一覧取れないけど、待ってればだれか発言するし、挨拶でもすれば帰ってくるから接続テスト完了する

happy lingr life !

Posted by Yappo at 15:48 | Comments (0) | TrackBack

2013年03月13日

perlbrew best practice

perlbrew には

$ perlbrew upgrade-perl
というのが実装されてるのがあまりにも有名ですが、これは現在使ってる環境の perl を、そのマイナーバージョンの中で一番新しいバージョンにアップグレードしてくれるんです。
perl-5.16.1 を使っていたら perl-5.16.3 に perl-5.14.2 を使っていたら perl-5.14.4 に。という具合ですね。
同じマイナーバージョンの Perl では XS バイナリの互換性とか保証されているので、すでにインストールされているモジュールはそのまま利用できる状態になっています。

だがしかし

$ perlbrew install perl-5.16.2
して作った環境を upgrade-perl すると 5.16.3 が入ってるのに perl-5.16.2 って名前がついたままでキモい!
実際には(c)tokuhirom みたいになってて、どのバージョンかわかるんだけど perl-5.16.2 (5.16.3) とかもっときもい!

ってことで、最初に perlbrew 環境をセットアップするときは

$ perlbrew install perl-5.17.2 --as perl-5.17
みたいな感じでマイナーバージョン止まりの名前に変えておいて、 security release が出たら perlbrew upgrade-perl とかするとスマートに運用出来る事でしょう。

別のバージョンからモジュール持ってくる方法

例えば、ついでに perl-5.16 から perl-5.17 に移行したい時とかは、こうやると 5.16 で入れてたのを引き継げる。

$ perlbrew install perl-5.17
$ perlbrew switch perl-5.17
$ /Users/onapeko/perl5/perlbrew/perls/perl-5.16/bin/perl -MExtUtils::Installed -E 'say($_) for ExtUtils::Installed->new->modules' | cpanm

追記

もっと良い事を教えてもらった。

$ perlbrew use perl-5.16
$ perlbrew list-modules | perlbrew exec --with perl-5.17 cpanm
ってやるのが一番簡単に perl-5.16 のモジュールを 5.17 に入れられる。 help の一番最後に書いてあった!

参考文献: Upgrade in Place with Perlbrew
安定的な Perl アプリケーション運用のための perlbrew 運用テクニック - tokuhirom's blog. blog.64p.org

Posted by Yappo at 15:21 | Comments (0) | TrackBack

perlbrew lib

perlbrew best practice まとめようと思ったら perlbrew lib なるコマンド見つけたので使ってみた。
なんか、一度ビルドした perl binary と元の site_perl を使いまわして、新たに lib path だけ変えて複数の環境を手軽に切り替える事が出来るってやつみたい。

例えば perl-5.17 の環境に @suneo って lib を作ると、 perl-5.17 の通常のライブラリパスに追加されて @suneo のライブラリパスが利用できる。そして cpanm で install するときは @suneo を汚さない。という branch っぽい作業するときに便利そう。

作る

$ perlbrew lib create suneo
ってコマンドで suneo っていうのができます。 perlbrew list してみると
 $ perlbrew list
  perl-5.14.1
  perl-5.15.2
  perl-5.16.0
  perl-5.16.1
* perl-5.17 (5.17.2)
  perl-5.17@suneo
  perl-5.17.2
  perl-5.17.5
みたいになっります。
$ perlbrew lib create perl-5.17@suneo
って感じでフルで指定もできますね。

使う

普通に

$ perlbrew use perl-5.17@suneo
ってするだけです。

lib path を見るとこんな感じ。

$ perl -E 'say join "\n", @INC'
/Users/onasui/.perlbrew/libs/perl-5.17@suneo/lib/perl5/darwin-2level
/Users/onasui/.perlbrew/libs/perl-5.17@suneo/lib/perl5
/Users/onasui/perl5/perlbrew/perls/perl-5.17/lib/site_perl/5.17.2/darwin-2level
/Users/onasui/perl5/perlbrew/perls/perl-5.17/lib/site_perl/5.17.2
/Users/onasui/perl5/perlbrew/perls/perl-5.17/lib/5.17.2/darwin-2level
/Users/onasui/perl5/perlbrew/perls/perl-5.17/lib/5.17.2
.

cpanm

普通にいれれます。

$ cpanm -v Acme::Acotie
...
OK
Successfully installed Acme-Acotie-0.02
Installing /Users/onasui/.perlbrew/libs/perl-5.17@suneo/lib/perl5/darwin-2level/.meta/Acme-Acotie-0.02/install.json
Installing /Users/onasui/.perlbrew/libs/perl-5.17@suneo/lib/perl5/darwin-2level/.meta/Acme-Acotie-0.02/MYMETA.json
3 distributions installed
という感じで普段と違うところに入ります。

へんなとこ

最新の App::perlbrew/0.59 だと use perl-5.17@suneo したら use perl-5.17 できなくなっちゃって、一度ターミナル落とさないと use できなくなって頭がふっとーしそーだおぉ。

まとめ

最近は carton 使ってるから、俺は使うかどうかわからない。

Posted by Yappo at 14:39 | Comments (0) | TrackBack

2013年03月12日

ikachan が優しくなったよ

見た目があれだなーと思ってたところに、ひろむせんせいが css をあててくれました!
やったね!

https://metacpan.org/release/YAPPO/App-Ikachan-0.11/

Posted by Yappo at 13:48 | Comments (0) | TrackBack

2013年03月08日

ikachan 新バージョン出したよ

App::Ikachan 0.10 でました。

3つの新機能が追加です

大量のチャンネルに JOIN した状態で Excess Flood された後にサーバに繋ぎ直して元居たチャンネルに入り直そうとする時に
短期間で JOIN しまくるので、 JOIN だけで Excess Flood されてまたサーバからキックされてしまう無限ループしてしまう酷い状況だったのですが sleep しながら JOIN するように AnySan の方で変えたので、この不具合が解消された予定です。

cpanfile で依存モジュール管理するようになったので、 carton で依存モジュールの管理が可能になりました。

ふしはらかん画伯による、とっても可愛いロゴ画像が搭載されました!
どのようなロゴかは是非アップデートしてお試し下さい!

Posted by Yappo at 13:42 | Comments (0) | TrackBack

2013年03月07日

Perl で L10N するのに Locale::Maketext::Extract::Plugin::Xslate っての書いた

Perl で L10N するにはhttp://blog.64p.org/entry/20110224/1298521852こういうことするんですが、今時はTTなんかつかわない!Xslateだ!ってことで Locale::Maketext::Extract::Plugin::TT 使ってたんですが、いろいろ怪しいのでちゃんとしたの作ったよ!

https://metacpan.org/release/Locale-Maketext-Extract-Plugin-Xslate

他のプラグインとちょっとだけオプション変わっちゃうけど、 start_tag とか変えるのも対応できるし syntax も全部対応できるよ。

Text::Xslate の AST とる internal な API 使ってるけど、 gfx に話して internal 扱いやめてもらうことになったので、安心してご利用いただけます。


非建設的な DIS や FUD が万円している昨今ではございますが、中の人達は非常に建設的ですね。

Posted by Yappo at 17:46 | Comments (0) | TrackBack

2013年03月04日

Carton Conferenceやってきました

cpanm / carton の新しいバージョンも出たことだし、そろそろみんなの carton の知見を集めましょうってことで Carton Conference を開催して来ました。

当日の模様は動画では無くはやりの podcast で配信します。
Podcast SP1: 2013/03/02 Carton Conference Tokyo 2013 / riywo's Podcast

carton 業界の今までとこれからをが見える貴重な音声ですので皆さん、どうぞご利用ください。
僕の死霊はhttp://yappo.github.com/talks/20130227-cartoncon/です。

podcast してくれた riywo さんと、会場提供やら準備をして頂いたLINE(仮)さんと中野人に感謝です。

Posted by Yappo at 17:04 | Comments (0) | TrackBack

2013年02月18日

Try::Lite 「より安全な例外キャッチを簡単に」

I wrote too safety exception handling module.
https://metacpan.org/release/Try-Lite

$@ の処理を安全に取り扱う例外処理モジュールとしては Try::Tiny があまりにも有名ですが、別の実装を作ってみました。

アプリケーションを作る時は、よく例外クラスを作ってから die bless {}, $foo_class; みたいな形のオブジェクトの例外を投げて、上流の方で eval で受け取ってから $@ の isa を調べて例外に応じた処理をする事が多いと思います。
ここで問題になるのが、受け取った例外の中から不要な物を、さらに上位に向けて rethrow するわけですが、 rethrow するのを忘れてしまうとクリティカルなバグを発生させる要因となります。

また普通の言語で良くあるような try {} catch (e = IOException) {} catch (e = PermissionException) {} のようなに、例外クラス毎の処理を可読性良く書きたかったいという問題もありました。当然 TryCatch.pm のような、そのものの文法を提供してくれるモジュールもあるのですが、あくまで黒魔術的な実装ではなくて、メンテナンスビリティの事を考えて誰が見てもわかる実装で用意したいという問題もありました。

そして、それらの問題を解決する手段として Try::Lite を書いたのです。

使い方は簡単で

use Try::Lite;

try {
    ...;
    IOException->throw('なんかメッセージ');
} (
    'IOException' => sub {
        say $@;
    }
);
の用に、最初に例外が発生するかもしれないコードブロックを書いてから、その後ろの引き数に受け取りたいクラス名と処理したい関数を渡してあげます。

ISA を見ているので、例外したオブジェクトが継承しているクラスを指定していてもキャッチ可能です。

package Exception;
use parent 'Exception::Tiny';
package IOException;
use parent --norequire, 'Exception';
package main;

try {
    ...;
    IOException->throw('なんかメッセージ');
} (
    'Exception' => sub {
        say $@;
    }
);

クラス名の変わりに * がワイルドカードとして指定出来ます。この場合は die 'aaa' 等の普通の文字列な例外も補足して処理可能になります。

try {
    ...;
    die 'foo';
} (
    '*' => sub {
        say $@;
    }
);

Exception::Tiny との組み合わせ

Try::Lite は blessed な $@ を発生させる例外のコードだったらどんな例外クラスを使ってても良いんですが、 Exception::Tiny との組み合わせ例も書いておきます。

# user table を引いて、レコードが無ければ 404 を返して、それ以外の例外は上流に rethrow させる
package Exception;
use parent 'Exception::Tiny';

...

my $user = try {
    Exception->throw if $error;
    get_user( user_id => $user_id );
} ( 'Exception' => sub { $@ } );
if (Exception->caught($user) {
    return $c->res_404;
}

以下のコードでも同じ事出来るし依存するモジュール減るのですが、 Try::Lite 使っとけば不意の retrhow 漏れが防げるので安全側に実装できるかな。と思います。
my $user = eval {
    Exception->throw if $error;
    get_user( user_id => $user_id );
};
if (my $e = $@) {
    if (Exception->caught($e) {
        return $c->res_404;
    }
    die $e;
}

Posted by Yappo at 18:06 | Comments (0) | TrackBack

2013年02月15日

Log::Dispatch::Screen::Color::Emotional も作ってみた

ref: http://blog.64p.org/entry/2013/02/15/152508
ref: http://d.hatena.ne.jp/hirose31/20130215/1360908384

変なプラガブル機構になっててめんどいし、最近 Log::Dispatch 使ってなくて自前で log メソッド書いてる。

Posted by Yappo at 16:28 | Comments (0) | TrackBack

2013年02月13日

Exception::Tiny - ちょー簡単な例外処理

I wrote too easy exception interface module.
https://metacpan.org/release/Exception-Tiny

既存の例外処理モジュールは、結構頑張ってるのが多くてドキュメント凄いいっぱいあったり実装が読みにくかったり痒い所がかけないので、おばあちゃんの孫の手的な実装をリリースしました。

例外処理に最低限必要な実装しか無いので使うのが簡単です。
例外クラスにアクセサを生やしたければ、お好きなアクセサーで生やすもよいし、例外の階層構造作りたければ普通に use parent すればいいし、既存の実装を変えたければ user parent 'Exception::Tiny'; で継承された側のモジュールでメソッドを上書きすればいいです。

Exception::Tiny 本体のお約束はなくて、普通に Perl のルールさえ知ってれば好きな例外処理を書けるのでとっても簡単ですね!

例えば以下のようにテラカンタンに書けます。

use strict;
use warnings;
use lib 'lib';
use 5.012;

package IOException;
use parent 'Exception::Tiny';
use Class::Accessor::Lite (
    ro => [qw/ fh /],
);

package FileException;
use parent -norequire, 'IOException';
use Class::Accessor::Lite (
    ro => [qw/ filepath /],
);

package NetworkException;
use parent -norequire, 'IOException';

package HTTPException;
use parent -norequire, 'NetworkException';
use Class::Accessor::Lite (
    ro => [qw/ uri code /],
);

sub as_string {
    my $self = shift;
    sprintf "HTTPException: message=%s, fh=%s, code=%s, uri=%s\n", $self->message, $self->fh, $self->code, $self->uri;
}

package OtherException;
use parent 'Exception::Tiny';

package RethrowException;
use parent 'Exception::Tiny';

package main;


sub exception (&) {
    my $cb = shift;
    eval { $cb->() };

    given ($@) {
        when (HTTPException->caught($_)) {
            warn "$_\n";
        }
        when (IOException->caught($_)) {
            printf STDERR "fh=%s\n", $_->fh;
            warn "$_\n";
            warn "-----------------------\n";
        }
        when (RethrowException->caught($_)) {
            $_->rethrow;
        }
        when (Exception::Tiny->caught($_)) {
            warn "$_\n";
            warn "-----------------------\n";
        }
        default {
            warn "$@\n";
            warn "-----------------------\n";
        }
    }
}

exception {
    die 'normal die';
};

exception {
    FileException->throw(
        filepath => '/foo/bar',
        fh       => 'FILE HANDLE',
    );
};

exception {
    HTTPException->throw(
        message => 'not found',
        code    => '404',
        uri     => 'http://example.com',
        fh      => 'TCP HANDLE',
    );
};

exception {
    OtherException->throw;
};

eval {
    exception {
        RethrowException->throw('rethrow');
    };
};
if (my $e = $@) {
    warn $e if RethrowException->caught($e);
}

__END__
normal die at ./winecall.pl line 69.

-----------------------
fh=FILE HANDLEFileException at ./winecall.pl line 73.
-----------------------
HTTPException: message=not found, fh=TCP HANDLE, code=404, uri=http://example.com
OtherException at ./winecall.pl line 89.
-----------------------
rethrow at ./winecall.pl line 94. at ./winecall.pl line 98.

happy exception!

Posted by Yappo at 13:03 | Comments (0) | TrackBack

2013年01月16日

PLACK_ENV my way

開発用 = development
本番用 = production
テスト = test


なんで deployment じゃなくて production を使っているかって言うと

de(?:ve|p)lo[yp]ment

だから

Posted by Yappo at 18:32 | Comments (0) | TrackBack

2013年01月11日

plackp -R したプロセスを終了する時には SIGHUP ではなく SIGTERM を送るべき、もしくは daemontools で plackup -R するのは筋が悪い話

スレタイ速報だから内容は無いけど、 plackup -R や plackup -r した場合には Plack::Loader::Restarter で fork して親プロセスでファイルシステム監視をして、変更があったら子プロセスで立ち上げた plack を再起動するみたいな事やってるんだけど、この親プロセスに対して SIGTERM を送ると子プロセスの方にも TERM 送ってくれるから良いんだけど、うっかり SIGHUP を送っちゃうと親プロセスだけ死んで子プロセスだけ生き続けるという事になる。

-R, -r は開発用なので基本的にはコマンドラインで plackup 起動した時に使うから問題にはならない。が、うっかり daemontools 配下で plackup -R とかすると、 server starter 使ってるつもりで svc -h とかでうっかり HUP を送ってしまったりするのである。
そうすると plackup のプロセスが initd の子供になっちゃて残り続けて daemontools 配下で立ち上げようとした plackup が port が塞がって起動しないような事になる。
Starlet とかで子プロセスを増やしていたら、さらに対処がめんどくさい事この上ない。

なので、 daemontools 配下で -R, -r つかっちゃだめって結論に半年前になってたのにうっかり忘れててハマったのでエントリ書いたわけ。

でも何かしらの事情で -R, -r 相当の事を daemontools 配下の plackup でやりたい時もあるかもしれないので、そういう時は素直に server starter とか使っとくと良い。 デフォルトで HUP 受け取った時に子プロセスに TERM を送ってくれる。
もし server starter 使いたくなかったら watcher --signal=TERM -- plackup -R ... みたいな事すればよい。

Posted by Yappo at 15:00 | Comments (0) | TrackBack

2012年11月28日

DSN に sql-mode=... 付けてもなんもなんないんだよ糞が!

最初の方に追記しておくと生DBI限定の話です。僕のしらない wrapper モジュールだと動くのかもしれません。
けど、こういうエントリを僕が書いてる時点で、そういうモジュールは筋悪いんだとおもいます。

人のプロジェクトのコードを見てたら

my $dbh = DBI->connect('dbi:mysql:dbname=geekdb;sql-mode=STRICT_TRANS_TABLES', 'yappo', 'moneyfriend', %attr);
みたいな感じの DSN があったんですよね。
他にも attribute てんこもりだったんで、それコミットした人に聞いて見たら「秘伝のタレです」的なのが帰ってきたので、僕も何も考えないで「これでSTRICT_TRANS_TABLES効いたら、まぁ捗るから付けとこう」って感じでコピペして付けてたんだけど、さいきん鉄板 DBI 選手権あったのでコメント書いたら「有効になるわけねーだろ!」的な椅子が飛んできて、調べたら確かに意味ない設定でした。

エントリ書いてからもっかい確かめようと思って実装みてたんですが、延々と XS コード出てきて説明面倒になってきたので禿げてないでコード書いてみた。
DBI 1.622
DBD::mysql 4.022

だめなばあい

MySQL のドキュメントを見ると「STRICT_TRANS_TABLES は厳格なんで ENUM に定義してない値とかいれてもエラーだよ」って書いてあるので、分かりやすく ENUM で定義されてないデータを突っ込んでみる。

use strict;
use warnings;
use 5.012;
use DBI;

my $dbh = DBI->connect(
    'dbi:mysql:dbname=geekdb;sql-mode=STRICT_TRANS_TABLES', 'yappo', 'moneyfriend',
    +{
        PrintError => 0,
        RaiseError => 1,
        AutoCommit => 1,
    }
);

$dbh->do(q{DROP TABLE IF EXISTS geeks});
$dbh->do(q{CREATE TABLE geeks (                                                                             
    geek ENUM('matz', 'dan') NOT NULL                                                                          
)});


$dbh->do(q{INSERT INTO geeks (geek) VALUES('dan')});
my($geek1) = $dbh->selectrow_array('SELECT geek FROM geeks LIMIT 1');
say $geek1;
$dbh->do(q{DELETE FROM geeks});

$dbh->do(q{INSERT INTO geeks (geek) VALUES('hyoshiok')});
my($geek2) = $dbh->selectrow_array('SELECT geek FROM geeks LIMIT 1');
say $geek2;

これを実行すると、普通に実行されてるが $geek1 で dan を表示してるのに $geek2 では何も表示しないで終わってる。
これは hyoshiok という文字列が geek の ENUM に定義されてないから、なにも入れられてないって事で STRICT_TRANS_TABLES が有効になってなさそう。。。。!

大丈夫な例

椅子とともに SET SESSION sql_mode=... しろと言われたので、 connect 時に SQL を打ってみる。
ここで何も考えないで $dbh->do つかってやっちゃうと reconnect した時とかに無効になるので、筋良く Callbacks オプションを使う。
説明は椅子プロさんの解説が Perl Advent Calendar に乗ってた!

use strict;
use warnings;
use 5.012;
use DBI;

my $dbh = DBI->connect(
    'dbi:mysql:dbname=geekdb;sql-mode=STRICT_TRANS_TABLES', 'yappo', 'moneyfriend',
    +{
        PrintError => 0,
        RaiseError => 1,
        AutoCommit => 1,
        Callbacks  => +{
            connected => sub {
                my $dbh = shift;
                $dbh->do(q{SET SESSION sql_mode=STRICT_TRANS_TABLES});
                return;
            },
	},
    }
);

$dbh->do(q{DROP TABLE IF EXISTS geeks});
$dbh->do(q{CREATE TABLE geeks (                                                                             
    geek ENUM('matz', 'dan') NOT NULL                                                                          
)});

$dbh->do(q{INSERT INTO geeks (geek) VALUES('dan')});
my($geek1) = $dbh->selectrow_array('SELECT geek FROM geeks LIMIT 1');
say $geek1;
$dbh->do(q{DELETE FROM geeks});

$dbh->do(q{INSERT INTO geeks (geek) VALUES('hyoshiok')});
my($geek2) = $dbh->selectrow_array('SELECT geek FROM geeks LIMIT 1');
say $geek2;

今度のケースを実行すると。。。

dan
DBD::mysql::db do failed: Data truncated for column 'geek' at row 1 at ./hoge.pl line 32.
ちゃんとエラーが出てくれてて STRICT_TRANS_TABLES が有効になってるっぽい!111

まとめ

DSN を良きにしてくれる O/R Mapper とかあるのかなとおもって DBIC みてもそういう実装じゃないし、そもそも DSN 変な拡張入れる筋悪なの使う人は迷惑なので、実際なくて良かった。

ということで、接続してから

SET SESSION sql_mode=...;
すべし、と椅子プロさんに指摘頂きました。

本日の教訓

コピペでプロジェクト始めるやつは空気椅子で仕事してろや!

Posted by Yappo at 13:37 | Comments (0) | TrackBack

2012年11月26日

サービスをつぶさない為に Web アプリを書く時にやっとくと良い事2選

テンプレートのエラーが出た時にアプリケーションのログだけに書くのでは無く、誰にでも「ここがえらってるよ!」って見えるようにしとくと間違いが少なくなる傾向があるのでテンプレートエンジンでフック出来るようになっておいてたら、それをうまく使うと良い。

また、テンプレートエンジンがレンダリングしてるフェーズで DB にクエリが飛ぶような構造で書いてあると、非エンジニアのカジュアルにテンプレートいじる人が甚大なクエリを実装してしまう可能性があるので、これも早期に発見しないとサービスが止まってしまい会社の売り上げが下がってしまい社員が路頭に迷うケースが発生してしまうので、これらも未然に防がなければならない。

Text::Xslate + Amon2 ならこうかける。

package MyProje::Web;
...;
{
    my $view_conf = __PACKAGE__->config->{'Text::Xslate'} || +{};
    if ($ENV{PLACK_ENV} eq 'development') {
        $view_conf->{warn_handler} = sub {
            warn @_;
            Text::Xslate->print(
                Text::Xslate::mark_raw('<span style="color: red; font-size: 1.8em;">'),
                '[[', @_, ']]', 
                Text::Xslate::mark_raw('</span>')
            );
        };
    }
    my $view = Text::Xslate->new(%{ $view_conf });
    sub create_view { $view }
}
...
sub render {
    my ($c, $tmpl, $vars) = @_;
    if ($ENV{PLACK_ENV} eq 'development') {
        require DBIx::Tracer;
        $tracer = DBIx::Tracer->new(
            sub {
                return unless Text::Xslate->current_engine;
                my %args = @_;
                my $sql = $args{sql};
                warn "Do not execute query in a view: $sql";
                Text::Xslate->print(
                    Text::Xslate::mark_raw('<span style="color: red; font-size: 1.8em;">'),
                   "[[ Do not execute query in a view: $sql ]]",
                   Text::Xslate::mark_raw('</span>')
                );
            }
        );
    }
    $c->SUPER::render($tmpl, $vars);
}

ログに吐いておいたらエンジニアくらいにしか気づかないが、ブラウザから分かるように真っ赤に大きく明らかなエラーっぽいのを返す事でアンテナの感度が低めな人にも「なんかおかしいよこれ」って言ってもらえるので、結果的には事故が未然に防げておいしいご飯と暖かい布団で生活出来るようになるわけである。

こんかいは、うっかり Perl で例を書いたが他の言語でも応用が利くでしょう。

参考文献
Xslate 1.0006 released! - Islands in the byte stream
How can I deny a DB access in a view? - tokuhirom's blog.

2012年11月08日

ExclusiveLock::Guard という排他ロック簡単にやるモジュール書いた

ファイルを使って排他ロックするには、適当にロックファイルを作って flock $fh, LOCK_EX とかすると思います。
flock で使ったファイルハンドルが close されたら自動的に unlock されるので、最初っから Guard な感じなんだけどロック用のファイルも一緒に消したいので ExclusiveLock::Guard ってのを作った。

use ExclusiveLock::Guard;
my $lock = ExclusiveLock::Guard->>new('/tmp/megazaru.lock');

って書くだけで $lock が生きてる間はロックかかってて、ロック外れたらファイルも一緒に消してくれるというだけの物。

ノンブロッキングなインターフェィスが欲しければ

use ExclusiveLock::Guard;
my $lock = ExclusiveLock::Guard->>new('/tmp/megazaru.lock', nonblocking =>l 1);
die '別の人にロックされてるよ'  unless $lock->is_locked;

みたいな風に書けます。

MySQL::NameLocker 使えば同じ事を MySQL の SET_LOCK 使って実装してるんだけど、ファイルロックでこういうの無かったので。

Posted by Yappo at 17:53 | Comments (0) | TrackBack

2012年11月05日

WEB+DB PRESS Perl連載枠「Perl Hackers Hub」のまとめ

そろそろ3周目も無事おわりそうなので、今までやった事をまとめて検討したい。

Vol.55 2010年2月24日発売 【第1回】PSGI/Plack……フレームワークとサーバをつなぐエンジン……宮川達彦
ベッケンバウアーだったんだけど、縁があって第一回目に。
Vol.56 2010年4月24日発売 【第2回】AnyEventでイベント駆動プログラミング……牧 大輔
たしか非同期プログラミングのブームが終焉してて実用的に使われだしてた時期だったかなと。
Vol.57 2010年6月24日発売 【第3回】DBIx::Classでデータベース操作……村瀬 大輔,Japan Perl Association[監修]
まだまだ Skinny とかは早過ぎたし、世界的なビッグウェーブの DBIC で ORM のネタをダストか云々だった気がした
Vol.58 2010年8月24日発売 【第4回】Twitterから学ぶ,Web APIのキホン……和田 裕介,Japan Perl Association[監修]
まっしゅあっぽーまっしゅあっぽーていうネタも必要だよねて気な
Vol.59 2010年10月23日発売 【第5回】Xslate……次世代テンプレートエンジン……藤 吾郎,Japan Perl Association[監修]
Xslate 売り出し期に突入してたし、テンプレートエンジンも TT 以外の物を見るようにしないとね的な感じと YAPC 連動だっけか
Vol.60 2010年12月22日発売 【第6回】UNIXプログラミングの勘所……奥 一穂,Japan Perl Association[監修]
プログラミングの基本のキの字を解説するのも捗りますねとかそういう感じだったかな
Vol.61 2011年2月24日発売 【第7回】新人さんのための仕事で使えるPerl基礎知識……横山 彰子,Japan Perl Association[監修]
ここまで、わりとガチだったので Perl とか良くわからない人向けに特にガチでも無い一目線で Perl の導入記事かいてもらうと、案外捗りそうだという紙の声が聞こえたりした
Vol.62 2011年4月23日発売 【第8回】Perlによる大規模システム開発・設計のツボ……広木 大地,Japan Perl Association[監修]
Perl を使った大規模システムの大規模チーム開発のプロフェッショナルによる、新人向けのチーム開発のいろは
Vol.63 2011年6月24日発売 【第9回】高速なWeb APIの実装とテスト…… Mobage APIを支えるノウハウ……嶋田 裕二(xaicron),Japan Perl Association[監修]
前号とは違った側面での高スループットを出すシステムをどうやって作るか生大好きみたいな
Vol.64 2011年8月24日発売 【第10回】ジョブキューで後回し大作戦……TheSchwartz,Qudo,Q4M……小林 篤,Japan Perl Association[監修]
Webサイト作るのにもキューってのは多用されてるので、そろそろ話題に出しましょうという
Vol.65 2011年10月22日発売 【第11回】ログでアプリケーションの改善プロセスを回す……長野 雅広,Japan Perl Association[監修]
開発に取ってはログは基本中の基本というところで、ログの人にいろいろ解説してもらう
Vol.66 2011年12月23日発売 【第12回】小飼 弾のPerlハッカーに逢いたい♥……小飼 弾,Japan Perl Association[監修]
最初から YAPC と絡めたいよねという事で、だったらアルファギークに逢いたいの時の感じがやりやすいらしいという事で、いろいろいってたらだいぶ豪勢になった
Vol.67 2012年2月24日発売 【第13回】メタオブジェクトプロトコル入門……Shawn M Moore,牧 大輔,Japan Perl Association[監修]
日本に住んでない人にも書いてもらいたいよねーとは思ってて、ちょうど YAPC の前夜祭で快諾もらってしかも話題的にも良い題材で書いてもらえる事になった
Vol.68 2012年4月24日発売 【第14回】最新Perl使いこなし術 ……リファレンスの引き方,5.10以降の新機能……cho45(さとう),Japan Perl Association[監修]
Perl5.10 以降の機能について紙媒体であまり出てないとおもってたので、分かりやすい解説書く事で定評のあるちょさんに
Vol.69 2012年6月23日発売 【第15回】Perl meets beats ……鳴らして学ぶシンセサイザー入門……伊藤 智章,Japan Perl Association[監修]
関東以外の人にも積極的に書いてもらいたくて、運良く書いてくれる人が見つかりつつ、今までとはだいぶ違う面白い記事になった
Vol.70 2012年8月24日発売 【第16回】Perl内部構造の深遠に迫る……藤 吾郎(gfx),Japan Perl Association[監修]
ほんとは一人一回が良いと思ってたんだけど、 Xslate の時にこのネタと天秤にかけてて不採用だったんだけど、やっぱりコアネタ欲しいということで、だいぶ捗る記事に
Vol.71 2012年10月24日発売 【第17回】Webアプリケーションのパフォーマンス改善……藤原 俊一郎,Japan Perl Association[監修]
iscon二連続優勝に導いた人によるパフォーマンスチューニングの極意が書いてあるのですごいですね
Vol.72 Amon2 tokuhirom
よくよく考えたら WAF の話とか出てきてなかったし、 Amon2 は少なくとも日本では一般的な物になったので改めてきちんと紙に出しましょう。という
Vol.73 なにかなー?だれかなー?
誰にお願いしよう
シーズン4
へとつづくのかな。。。!?そろそろ naoya さんの出番とかこないかな

改めて見直してみるとネタ被ってなくてすごいw
あとこれ、一人だけで絶対に書けない濃度だからやばいな、これ発案した人凄いなと思いました。


WEB+DB PRESS Vol.71
WEB+DB PRESS Vol.71
posted with amazlet at 12.11.05
竹迫 良範 Jxck じょさん 後藤 秀宣 藤原 俊一郎 奥野 幹也 堤 智代 森田 創 中島 聡 A-Listers はまちや2 相澤 歩 柴田 博志 池田 尚史 梅澤 雄一郎 九岡 佑介 近藤 宇智朗 佐藤 鉄平 mala
技術評論社
売り上げランキング: 395
Posted by Yappo at 14:03 | Comments (0) | TrackBack

2012年10月04日

Perl の サブルーチンリファレンスとコードリファレンスの違いと prottype の & について

Perl 初心者なので、うっかりはまったので質問してみたら理解力深まったので open & share します。

17:33 < acotie> sub html_builder (&){}
17:33 < acotie> my $x = sub {};
17:33 < acotie> html_builder $x;
17:34 < acotie> これで Type of arg 1 to main::html_builder must be block or sub {} (not private variable) 
17:34 < acotie> て怒られない方法あった気がしたのに忘れたくらい初心者です
17:35 < jox__> html_builder \&{$x};
17:35 < jox__> or &html_builder($x)
17:37 < acotie> おおー
17:37 < acotie> ああー & つけるんだった
17:37 < acotie> あざっす!
17:38 < acotie> & 付ければ protoype 効かないのはバグじゃないんだよね
17:39 < jox__> umu
17:39 < jox__> Perl4との互換性のためですね!
17:39 < tokuhirom> ww
17:39 < acotie> あざっすあざっす!
17:39 < jox__> ぼくは html_builder(\&{$x}) のほうが好きだけど!
17:40 < jox__> てかひろむにきけばいいのにw
17:40 < tokuhirom> w
17:40 < tokuhirom> \&{$x} の方がなにしたいかわからんなw
17:40 < jox__> まあねえ…
17:40 < jox__> うーむw
17:40 < jox__> ぼくにはわかります!
17:40 < acotie> あるぇってなりそう
17:40 < tokuhirom> というか現時点で、今どういう読み方するのかよくわかってないw
17:41 < jox__> (&) prototypeはサブルーチンリファレンスも受け付けるのです。
17:41 < acotie> やりたい事はわかるけど、わかんないw
17:41 < jox__> つまり html_builder(\&hoge) は valid.
17:41 < jox__> で、これはあくまでも構文上の問題なので、適当に構文をあわせてやればパーサが納得してくれるというわけ。
17:42 < acotie> サブルーチンリファレンス と コードリファレンス の違いすら分かってない Perl 初心者です!
17:42 < jox__> 同じです!
17:42 < acotie> w
17:42 < acotie> あとでググれるようにブログにろぐのっけといていいですか//
17:42 < jox__> 重箱の隅突くの(・A・)イクナイ!!
17:42 < jox__> どうぞ!
17:42 < acotie> あざす
17:42 < acotie> や、つついてないw
17:43 < jox__> ><
17:43 < acotie> サブルーチンリファレンス 受け付けるけど コードリファレンス 受け付けて無いじゃんw
17:43 < acotie> Perl ってそういうとこあるよねって納得したからいいや!
17:44 < jox__> や、構文の問題で、パーサにとってコードリファレンス(=サブルーチンリファレンス)に見えるかどうかが問題なのです。
17:44 < acotie> なるほどね
17:44 < acotie> $code だと、じっさい動かさないとわからん!ってことね
17:44 < jox__> sousou
17:44 < acotie> かしこさ 1 あがった
17:45 < acotie> &$code する事により、パーサは $code がサブルーチンなんだなって認識して、その上でリファレンスに渡し直す。と
17:45 < gfx__> (\@) とかもそうで、sub hoge(\@); とかすると hoge($value) ははじいて hoge(\@{$hoge}) と書かなきゃならない。 
17:46 < acotie> であるならば \&$code にしたほうが正しいな
17:46 < cho45> そうなんだ!
17:46 < jox__> でしょ!
17:46 < acotie> コメント付きでかかないと後続だれもわからんから、それだけかかなきゃいけないw
17:46 < jox__> ><
17:46 < acotie> いがいとログのびたw

まとめるとプロトタイプ付きの関数を呼ぶ時にプロトタイプ宣言うざいのを回避する方法として &foo($code) みたいに呼ぶとかやれるんですが(Perl4 の後方互換性のため)せっかく型指定されてるので、それをわざわざ回避せずにパーサにコードリファレンスだと明示的に知らせる事が出来る foo(\&$code ) みたいな呼び出し方が正しいという事ですね。

ただ、 \&$code / \&{ $code } とか書かれてもやってる意図が伝わりにくいので、そういうコードを書く時には、こちらのエントリをコメントに添えて実装すると捗りますね。

Posted by Yappo at 17:51 | Comments (0) | TrackBack

2012年10月02日

YAPC::Asia TOKYO 2012 と Geohash リリースのお知らせ #yapcasia

僕の YAPC::Asia TOKYO 2012 さっき終わったので書く事にしよう。悪意は無いので素直に読んで頂ければと。

位置情報系処理のお話 a.k.a 続・自文書抽出日本的住所

http://yappo.github.com/talks/20120928-yapcasia2012-geo/

ikasama さんとかには、前のプレゼンとか見てたら見なくて平気だよね敵な事言われたけど、大体新しいトピックでお伝えしました。

基本的には CPAN での位置情報の扱い方と、視覚化の重要性の話と、位置情報は様々なサービスに欠かせないという話と、住所を美味く扱う話、その他注目するべき事と言った内容で緩く話してきました。

やるネタとしては住所正規化API出した時に決まってたのですが、その後色々とネタが増えて行ったのでした。結果だけを見るならカンファレンスドリブン開発というかカンファレンスドリブン業務ってアピールできますね。

位置情報関連のシステムは、どのような種類のサービスでも活用出来るって所をメインで覚えといてもらいたかった所でしたが、意図通りの印象を持ってもらえて感激ですね。

話す事はだいたいもう決まってたんだけど、順番決めたり書き起すのがギリギリになりましたね。

ltthon

良かったと言う話が方々で出てる通り、最初は大失敗すると思ってましたが成功して良かったですね。カンファレンスの潤滑油的な役割で大成功です。

  1. メインホールの近くである事
  2. 目の前に電源が大量にあった事
  3. 会場が複数拠点である事
  4. 長い時間やってる事
  5. 本編の発表本数が多い事
  6. 全体の参加者数が膨大である事
  7. 専念するチームがあった事

が成功の要因で、どれが欠けても失敗したんじゃないかなと思います。登壇者数、飛び入り数、観客数的な意味で。単体イベントとして開催しても人集まっても、あのレベルの盛り上がりとムーヴメントは作れないでしょうね。あくまでサブイベントであるべき。

そんな僕も、うかうかと飛び入りしてしまった組でドラクエ10の発表をしてきました。

http://yappo.github.com/talks/20120929-yapcasia2012-ltthon/

2分で飛び入り出来る人!?とか言われて飛び入りしちゃったのでゲームの話だけしたって印象を与えましたが、残りの3分でドラクエの話をふまえた上で大事な事を言う予定でしたね。エンジニアリングやプログラマとしてのあり方を伝える予定でしたけど2分で切る!っていわれたから、全行程は40分だけど最初の25分の内容しか喋らなかったわー

after hackathon

通常は、終わった後にハッカソンが開催されるのですが、今年も開催されました。

今年はだいぶ綱渡り的開催だったのですが、台風きて終了時間が早いという中でも皆 shipit してたので、ここ最近一番成果が出てたんじゃないかと思いますね。

僕も Geohash という CPAN モジュールをリリースしました。これからは Geo::Hash や Geo::Hash::XS を使わずにこちらを使いましょう。

mixi さん、もりもとさん、たかいさん、台風やってきてる真っ最中だと言うのに会場として貸して頂いて有り難うございました!

YAPC の感想

よかったんじゃないでしょうか。

僕もだけど、日本人だけで固まってたの気になったけど。

あと、僕のトーク中ずっと最前列で寝てたkamipoさんが面白かったです。

非公式後夜祭

今回は、かんさんが目黒遠いから幹事やりたく無いという事で、一日目の懇談会の時に本郷に詳しいまんでーくんに無理矢理幹事やってもらって、つつがなく良い感じの後夜祭ができましたね!

今後

毎年他の場所でやるべきとかそういう話が出てますが、 YAPC::Asia だとなんか大事っぽいから YAPC::Tiny みたいな軽いノリで YAPC::Tohoku とかを Sendai.PM の人にやってもらったら良さそうだねー的な事を miyagawa さんとYAPCの前に話してたんですが、MAX 50人くらいで開催する分には関東から半分くらい来そうだし出来そうな気がするんだけどどうでしょ?

YAPC::Tohoku やったら700人越えるほうの YAPC::Asia は、その年やらないの?とか言われそうだけど同じ年に平行してやればいいだけっしょ。

もうあのイベントはお化けなんだから、他の地域で開催する人は気楽にやったほうがいいんじゃないのかなーという所ですね。

関係無いけど北海道と仙台と福岡と沖縄に行く約束をした気がするのでYAPPOC::ASIAでもやりましょう。

そういえば、今回も ideaxidea の田口さんに呼び止められてから名前確認されるプレイを受けました。

Posted by Yappo at 20:48 | Comments (0) | TrackBack

2012年08月28日

Net::Twitter::Lite の update_with_media を使って Twitter で画像と位置情報付き tweet をする方法

なんか Twiyyer API まわりが騒がしいらしいという噂は聞いてますが Net::Twitter::Lite で画像付きツイートする APIに対応したバージョンが今年出ていたのでちょっと使ってみました。


binmode STDOUT => 'utf8';

my($message, $file) = (decode(utf8 => $ARGV[0]), $ARGV[1]);

my $config = pit_get('Net::Twitter::Lite-image-upload', require => {
consumer_key => 'consumer_key',
consumer_secret => 'consumer_secrt',
token => 'token',
token_secret => 'token_secret',
});

my $twitterw = Net::Twitter::Lite->new(
legacy_lists_api => 0,
ssl => 1,
upload_url => 'https://upload.twitter.com/1',
%{ $config }
);
$twitterw->access_token($config->{token});
$twitterw->access_token_secret($config->{token_secret});

my($filename) = $file =~ m{/([^/]+)$};

say "tweet: $message $file";
update_with_media($message, $file, $filename, '35.6184057279992', '139.727510749509');

sub update_with_media {
my($msg, $file, $filename, $lat, $lng) = @_;

my $content = do {
open my $fh, '<:bytes', $file or die "$!: $file";
local $/;
<$fh>;
};

$twitterw->update_with_media(
encode(utf8 => $msg),
[ undef, $filename, Content_Type => 'image/jpeg', Content => $content ],
{
display_coorrdinates => 'true',
lat => $lat,
long => $lng,
},
);
}

ポイントは upload_url を指定しておかないと Net::Twitter::API にパラメータが実装されてないので動かない所ですね(die "update_with_media: 400: URL must be absolute"; するよ!)。display_coorrdinates は位置情報を表示するかどうか決めるパラメータって書いてあるけど false にしても良ーわからん教えて tsupo さん。

という事で見事キャプテンの写真が位置情報付きツイートできました。(Echofon とかの普通のクライアントとかでも普通に画像でます)


Line
Line
posted with amazlet at 12.08.28
Yua Kotegawa
Carlsen Verlag GmbH

Posted by Yappo at 18:45 | Comments (0) | TrackBack

2012年08月14日

本物の KEN_ALL.csv の処理が簡単に出来る Parse::JapanesePostalCode をリリースした

空前の KEN_ALL.csv ブームが凄かったのが記憶に新しいばかりですが、この郵政さんが公開している郵便番号ファイルをカジュアルにパース出来るモジュールを作りました。

https://metacpan.org/release/Parse-JapanesePostalCode
https://github.com/yappo/p5-Parse-JapanesePostalCode

使い方はとても簡単で

use Parse::JapanesePostalCode;
my $parser = Parse::JapanesePostalCode->new( file => 'KEN_ALL.csv' );
while (my $obj = $parser->fetch_obj) {
    my @list = map { $_ ? $_ : () } ($obj->zip, $obj->pref, $obj->district, $obj->city, $obj->ward, $obj->town);
    if ($obj->has_subtown) {
        push @list, join '/', @{ $obj->subtown };
    }
    if ($obj->build) {
        my $str = $obj->build;
        $str .= $obj->floor . 'F' if $obj->floor;
        push @list, $str;
    }
}
と言う感じのコードで簡単にパースして使いやすい形にしてくれます。

以前からのノウハウや、住所正規化API作った時のノウハウ、さらにそれの最新の知見を盛り込んでいるので最新版のデータではだいたい使いやすい結果が返ってくるとおもいます。
番地の並びや特殊な表記はそのままに残してありますが、そのへんは使う人が都合よく出来るように、そして現実的にはそのへんの細かい所はスルーでokなので、そのままの状態にしてあります。
わかりやすく言うと、現実的な成形をある程度しているのでカジュアルユーズや Web サービスで使う分には問題のないデータが作れます。

その他、郡と町村の分離、政令指定都市での市と区の分離、ビル名の分離や階の抽出、複数の小字があった場合等は ARRAY ref にして取れるなどが出来ます。
もちろん複数行のレコードにも対応しているし、オブジェクトで返して欲しくなければ、オブジェクト化や簡単な処理をしていないほぼそのままのデータも取れます。

CPAN には Geo::Postcodes::JP っていう KEN_ALL.csv を処理できるモジュールが既にあるのですが、たいそうなモジュールでかつ、処理としては微妙なのでパースだけ出来るモジュールを作りました。

今後は JIGYOUSYO.csv にも対応したいなーとも思ってますが、実際に使う時になるまでは僕は実装しなさそうです。
あとは、差分データもどうしようかなーと思ってるんですが、差分処理はパーサの範囲外かなーと思ってて、差分データだけパース出来れば良いかなと思ってる所です。
もちろんパッチ歓迎です。

まとめ

  • 郵便番号データの処理ノウハウがない人でも、僕のノウハウを使って簡単に処理出来るモジュールをリリースしました
  • YAPC で、本物の KEN_ALL.csv をお見せすると言いましたが、もうお見せしてしました
  • YAPC では、本物の国交省データ処理をお見せしますよ
美味しんぼ (1) (ビッグコミックス)
雁屋 哲
小学館
売り上げランキング: 158776
Posted by Yappo at 20:01 | Comments (0) | TrackBack

そういえば YAPC のチケットうってるらしいですよ

http://yapcasia.org/2012/talk/show/96627a88-ab9d-11e1-a255-2a656aeab6a4
僕もしゃべります。

なんというか、一言でいうと
YAPC で僕のトークをみにきてください。本物のKEN_ALL.csvとはどういう物かお見せしますよ
というかんじです。

ちょっとした大ネタも用意してあります。
4sq に興味ある人も見にきた方がいいです。

(参考) http://blog.64p.org/entry/2012/08/14/191118
http://tagomoris.hatenablog.com/entry/2012/08/14/191418

Posted by Yappo at 19:40 | Comments (0) | TrackBack

2012年08月13日

「初めてのPerl 第6版」がでたそうです

「初めてのPerl 第6版」が発売されました | 近藤嘉雪のプログラミング工房

「初めてのPerl 第6版」がでたそうです - tokuhirom's blog.

「初めてのPerl 第6版」がでたそうです - Islands in the byte stream

Perl 5.14 に対応してモダンな書き方の説明になっているそうですので、Perl 5.8 のままおいていかれてる人や Perl 5.6 のままの知識の人などはこの機会に再入門してみてもよいのでは?

初めてのPerl 第6版
初めてのPerl 第6版
posted with amazlet at 12.08.13
Randal L. Schwartz brian d foy Tom Phoenix
オライリージャパン
売り上げランキング: 2883
Posted by Yappo at 14:24 | Comments (0) | TrackBack

2012年08月06日

YAPC::ASIA TOKYO 2012 で位置情報関連の発表をしてきます

トークが採択されたようなので。。。

まだだいぶ先だけど9月後半に開催されるYAPC::ASIA TOKYO 2012で位置情報関連の話してきます。

http://yapcasia.org/2012/talk/show/767bd582-abb3-11e1-85bd-57a46aeab6a4

住所関連ネタとかでは6年くらい前からやってるんですが、それらの過去の発表の内容をベースとして今現在どういう事をやっているのか、やろうとしているのかとかを話す予定です。

アカデミックな感じとは真逆の現実路線のプレゼンになる方向性です。

Perl とか知らなくても理解出来るような話になる予定なのでチケットの購入はお早めに。

Posted by Yappo at 14:32 | Comments (0) | TrackBack

2012年06月28日

さいきんの ShipIt

最近 ShipIt したものとか。

AnySan/ikachan

IRC に繋げる時に user を nickname と変えたいよっていう pull-req 貰ったので対応した。
おかげで ikachan の導入事例が一個増えた。

Geo::Coordinates::Converter

YAML::Base が廃止されてるのに inc/YAML.pm が use YAML::Base してて make 出来なかった馬具を、ずっと放置してたのをいい加減直した。

String::Diff

YAML::Base ずっと放置してたのを直したのと、 5.16.0 から quotemeta で 、 がエスケープされるようになってテストこけるの対応した。

あと RT に来てた String::Diff を使うと XSS するってのに対処出来るようなオプションを追加した。
存外使われてるっぽいので、真面目にメンテナンスしました。

ちなみに、会社で隔週水曜日の夕方からオフィスの和室使って Open & Hackathon ってのをやってるんだけど、その枠で直しましたとさ。

String::Diff の RT は残り debian 対策のみになったけど、まだ放置しとこう。

Posted by Yappo at 12:49 | Comments (0) | TrackBack

2012年06月12日

DeNA のノウハウが12個も馬鹿正直に書いてある「Mobageを支える技術 ~ソーシャルゲームの舞台裏~」を読んだ

先週末くらいに届いて週末うっかり読むの忘れて昨日の夜にだいたい読み終わりました。
実際の発売日は明日からなので、今すぐアマゾンで予約するか明日本屋に並ぶといいよ!

なんていうか書評書くのが凄い難しいん素よねこの本、高層ビルの上層階のレストラン街のような感じで、それぞれの著者がそれぞれの業務に関して得た知見を惜しげもなくこれでもかって書いてるので、本全体としてはまとまり感が凄いないっていうw

ガラゲーの話とかサービス終わってるDoCoMoのPDC端末の判定方法とか Flash とか FastCGI とか2012年に出る本らしからぬトピックスがあったりしますが、それが本当に今の DeNA/Mobage を支えている技術である事には間違いないので本当に馬鹿正直に、包み隠さず書籍化したな。というのが第一印象ですね。バカにしてる風ですが賞賛してます。

本書の特徴としては、全Mobage関係の技術者が関わる技術を網羅して解説しているという所が特徴です。
そういうコンセプトなので必然的に多数の著者によって書かれているので、DeNAがその技術分野で何を困っていて、何を考えどう解決したのかという知見がたっぷり入っています。

正直言っておすすめの対象読者選定むずいけど、インフラの面倒を見ている人やサーバサイドのコードを書いているけど下のレイヤも考えてる人、もしくは考えたい人が書くと一番コスパの良い読者かなと思います。
ぶっちゃけ、その層の人達は Part 1 は不要になるし逆に Part 1 が捗る人にとっては、残りの3/4くらいの部分が意味不明になるのかなとも思う。個人的には Part 1 の3章4章は参考になると思うので、さっき書いたのに当てはまる人が一番マッチするかな。と思います。

Part 1

業界背景の説明から入ってるのが、ガチの技術書じゃなくて会社を上げての出版なんだな感あるけど Part0 に入れとけば良いと思ったw

基本的なガラゲーサイトを作る上での最低限のハマりどころ紹介や、ガラゲーソシャゲといえば Flash !なので Perl で Ming を使う方法とかいきなり出てくるのがほんとモバゲーらしくて良かった。
中野人ならでわの知恵も入っていて、今からガラゲーのソシャゲ始める人は読んどいても良いかもしれないけど、そういう人が捗る部分がこの辺だけってのが難点。

がらげの章のあとは、スマホブラウザゲームについててこちらもUIの設計の話やサクサク感出す為の知恵がふんだんにある感じですね。SWFをJS/HTML5に変換するツールの性能比較なんかもよかった。

そして Part 1 さいごは、アプリのゲームにからめて ngCore desu!

Part 2

こっからは、インフラと松信夢想のターンですね。5章8章が離れてたのが意味わかんなかった。

35億PVのほうでは、 FastCGI での運用テクニックならびに OS のファイルキャッシュの制御方法を C のコード付きで詳細に解説 CoW もあるよ。や、 DB への接続はホスト名ベースで MyDNS を使ってるよ、 lvs 挟むともっさりだから生に近い薄さじゃないとトラフィック支えられないよな話を丁寧に書いてありました。

そして松信夢想なんだけど、パラパラしか読んでない。なぜならば俺はWebエンジニアのための データベース技術[実践]入門 (Software Design plus)を全部読んだからだ!でも、Moobage本の松信章には新ネタ/Mobageというコンテキストならでわのネタもちょいちょい入ってたから安心して良いです。

次が数千台のサーバを管理する章。500台とかカジュアルすぎる感じですね。
いわゆるヤビツのDeNA版の内製サーバ管理ツールの話やPXEブートの環境構築方法まで結構濃いです。
ツールにサーバの登録が終わると同時に監視が走るってのはだいぶよいんじゃないかな?真似しないのかな?

このツールも3階層だなーとか思った、GrowthForecastも3階層なんだけど3はマジックナンバーだというのと3くらいの階層で分けないと意味不明になるからって理由で3にしてたけど、どういう理由で3にしたんだろうなー

Part 3

ここは、アプリ開発者のターン。

ZIGOROu章は、シャーディング環境でのDBプログラミング方法や、お得意のニッチ機能のMySQL版解説と、MySQLとの付き合い方って書いてあるのに全然関係無いRESTfulの設計考え方REST厨すぎるとアプリの設計無理あるわーな話となってます。
松信章でもシャーディングの話あったけど気のせい。というか、こっちではDBA的アプローチではなく、アプリでどうするかって話ですね。

次はnekokak章でQUEUE workerあれこれ。実際QUEUEとか使ってみないとわからん感じなんですが、苦労と対応についてあるあるネタを網羅してます。個人的には worker でのシグナル処理入ってて欲しかった。

さいころんの章では、気合い入りまくりでチューニングの考え方の参考にすっごいなるんでちゃんと買って読むべき。個人的には MyDNS のおさらいがあったのと、いままで用途がというか何で作られたのか意味不明モジュールになってる Iterator::GroupedRange の誕生秘話がわかったのが良かった。

そしてまたnekokak章ですが、何を考えてどうやってログを監視して行くかの話と、デプロイをどうするかって話、デプロイはだいぶ前のほうで FastCGI でのデプロイの話が出てた気がするけど、やってる事が違う人だからそれはそれこれはこれで、こっちはモダンよりなプロダクトでのデプロイの話ってみとくといいかな。
あとは daemontools Web UI を作ってるらしいけど、おれもステージング環境用の似たツール作ってて Web UI で特定のブランチを選んでステージング環境つくったり git pull するのとかやってる。これは去年の YAPC で話す予定で資料だけ上がってる。

Part 4

個人的にはこの章はばっさり切ったほうが良かったとおもいました。
概要では

その舞台裏を「ソーシャルゲーム(フィーチャーフォン/スマートフォン)」「大規模Webインフラ」「プラットフォーム」「ビッグデータ分析」といったテーマに分け,DeNAの実践的ノウハウを解説しています。
とかいてあり、表紙には「開発、運用、効率化、分析」と四台柱にしてあってセクションも別れているのにですよ、ページ数は全体の1/10以下。いやページ数はどうでも良いんです濃厚なら、でもクラスタリングの必要性と何をする物なのかという解説を少しして後は Mahout の使い方で終わってしまうのは、あまりに味気ないんじゃないでしょうか。

とくに DeNA らしい知見も一切含まれていないので実質的にはドキュメントを見れば事足りるし、ここまで大きくフィーチャリングするのは間違いだとおもう。もし僕がビッグデータ分析目当てで通販で本書を買ってたらマジ切れするレベルなので、せめて3章の後半にくっ付ける感じの扱いで良かったと思う。

まとめ

みんな好き勝手に書いてある感があって「この話題別の章ででてたよ!」な所も多くて普通の書籍としては統一感ないですがwいつかのアップデートで構成まとめ直されるとより使いやすくなる気がしたりするような。
そのかわり執筆陣それぞれの主張したい事が全面に出てて役に立つ情報が満載で、読むと確実に将来捗る内容になってるので「まるごと Perl」てきに「まるごと Mobage」的な本を買うんだ感で買って読むと良いと思います!

最初は次世代版[24時間365日] サーバ/インフラを支える技術 ‾スケーラビリティ、ハイパフォーマンス、省力運用になり得る本かとも思ってたけど、見事に言及する技術分野を変えてあって、未だにオワコンにならない本だなと思いましたw

PS: 変だと思ってた所はメモしてあるので、中野人はこちらをごりようください。

Posted by Yappo at 19:55 | Comments (0) | TrackBack

2012年06月04日

Perl 5.16 の面白そうな新機能を厳選して5つ紹介

日本人が金環日食で騒いでる待っただかにリリースされた事で有名な Perl 5.16 ですが、ちょっとまえに僕が Hokkaido.PM Casual で新機能の見所プレゼンしてて、折角なのでブログにも書いとこうと思いまして転載仕様かなーと。

More CORE subs are callable through references

コア関数のコードリファレンスを取れるるようになります。たとえば文字列フィルタリングをユーザが差し替え可能なモジュールとか作る時に捗るって jsx が言ってました。

use strict;
use warnings;
use 5.016;

# ここの関数テーブルをユーザの好みに差し替える
# 基本はコア関数を使う
my %func_map = (
    index  => \&CORE::index,
    splice => \&CORE::splice,
    ...
);

Unicode Symbol Names

シンボル名を処理する時に utf8 フラグを無視して処理するバグが治りました、日本語関数とか作ってる人に影響があります。

use strict;
use warnings;
use 5.016;
use utf8;

sub 弾 { say('小飼') }
# utf8 フラグ付きだから問題無く呼べる
my $dankogai = \&{"弾"};
$dankogai->();
do {
    no utf8;

    # utf8 フラグ立ってないのでシンボル名解決出来ない
    # ただし 5.14以前だと utf8 フラグ無視してるので動く
    my $dankogai = \&{"弾"};
    $dankogai->();
};

Support for Embedded Nulls

今まで文字列変数に \0 が入ってると、様々な場面で文字列が \0 以前で終端に達していたが、その挙動が無くなった。 \0 は \0 として内部的に扱われるようになった。
何かって言うと、今まで LL なのに \0 を文字列終端子として処理するバグが Perl の一部の機能に入ってたって事。

use strict;
use warnings;
use 5.016;

sub foo { say('bar') }
main->foo;

my $baz = "foo\0hoge";
{
    no strict 'refs';
    *{$baz} = sub { say($baz) } ;}

    # 以下は 5.14 以前では foo が呼ばれ、 5.16 以降では foo\0hoge が呼ばれる
    main->$baz;

Autoloaded sort Subroutines

sort の第一引数に関数をそのまま渡せる仕様があるんだけど、そこの関数を AUTOLOAD で処理出来るようになった。何に使うかよーわからん。けど ORM で捗るのかな?

use strict;
use warnings;
use 5.016;
use Test::More;
our $AUTOLOAD;
sub AUTOLOAD {
    my($key) = $AUTOLOAD =~ /([^:]+)$/;
    return 0 if $a eq $b;
    return -1 if $a eq $key;
    return 1 if $b eq $key;
    return 0;
}

my @list = qw/ foo bar baz /;

# foo を一番最初に持ってくるソート
my @foo = sort foo @list;
is($foo[0], 'foo');

# bar を一番最初に持ってくるソート
my @bar = sort bar @list;
is($bar[0], 'bar');

# baz を一番最初に持ってくるソート
my @baz = sort baz @list;
is($baz[0], 'baz');
done_testing;

__SUB__

いわゆる arguments.callee。どっかのサンプルコードで無限ループするのが乗ってて恐いと思ってこのエントリ書こうと思ったんだった。

use strict;
use warnings;
use 5.015;
use Path::Class;

# 主に無名関数で使う。名前がついてるなら __SUB__ とか使う意味ない
my $walker = sub {
    my $dir = shift;
    for my $path ($dir->children) {
        if ($path->is_dir) {
            __SUB__->($path);
        } else {
            say $path;
        }
    }
};

sub runner {
    my($caller, @args) = @_;
    $caller->(@args);
}

runner $walker, dir('/');

まとめ

Perl 5.16 の新要素で僕がちょっと興味引いた物の紹介をしました。5.10から5.14の間のトピックスを知りたい人は、来週出る Web+DB PRESS の Perl 連載で cho45 先生が言及してるので読むとよいでしょう。

WEB+DB PRESS Vol.68
WEB+DB PRESS Vol.68
posted with amazlet at 12.06.04
名村 卓 三宅 陽一郎 小野 修司 中島 聡 森田 創 小飼 弾 田籠 聡 天野 祐介 cho45 大和田 純 白土 慧 勝間 亮 石田 忠司 牧本 慎平 A-Listers 近藤 宇智朗 はまちや2 mala じゅんいち☆かとう
技術評論社
売り上げランキング: 4256

第1部

かのんとすれ違い用の3DS発掘してたらまさかの10分遅れではいれづ。。。

第2部

「こんばんわー」
あんにん「わぁー」
「岐阜の公演いったよ、よかったよ!」
あんにん「ありがとうございますー」
「えっと、あっと」
あんにん「またきてくださいね」
「またくるよー」

時間配分間違えて何言いたいかわからなくなった。。。

「こんにちわー岐阜の公演いったよー」
みゆ「えーほんとですか?」
「うん、とってもよかったよー」
みゆ「わーうれしいありがとうございます」
「うんまたいくよー」
「またきてくださいねー」
ばいばいー

公演で見た時よりもおとなっぽくなっておった。

「岐阜公演行ったよー」
島田「来てくれたんですね」
「ブルーローズかっこよかったよ」
島田「ほんとですか?!嬉しいです」
「あとね、ドラムちゃんと叩けてて最後まで叩いてて感動した!」
島田「ありがとうございます!」
「またいくねー」
島田「またきてくださいー」

やっぱり、カッコいいって褒めたら喜んでくれてよかった

1部2部は岐阜の公演の直後急遽ぶっ込み入れたけど、こうして感想を直接伝えられる機会があるのは良いなと思う。

第3部

ゆうこす「こんにちわー」
「こんにちわー雑誌でしか見たことなかったんだけどね」
ゆうこす「なにかなーヤンアニ?ヤンガン?それともプレイボーイかなぁー」
「や、、ヤンジャ。。 案内「じかんでーす「本物やっぱり可愛いね
ゆうこす「ほんとにぃーー?ばいばーい」

完全にやられた。。。

ゆうこすはもうちょっとゆるふわな感じかと思ったけど、だいぶ釣り師だったぞw

あきちゃ「こんにちわー」
「こんにちわ、えっとねえぎぶみーふぁいぶの時は当たらなくてこれなかったんだけどねぇ、今回当たったからこれたよー」
あきちゃ「よかったぁーありがとー」
時間ですー
「。。。」
あきちゃ「。。。」
あきちゃ「またきてね!」
「うん、またくるよー」

すっかり何話すか考えてなくて自己紹介でおわったぱてぃーん。。。

第4部

あいり「こんにちわ」
「こんにちわー22位おめでとうー」
あいり「ありがとうごさいます」
「本番ではもっと上いけるように
あいり「なれるといいですね
「おうえんしてるよー」
あいり「ありがとうございます」
「またくるねー」
あいり「またきてください」

喉擦り切れるほど調子悪いのに礼儀正しくてええこや

4部はだいぶタイトすぎてて余裕無くて「パパウ!パウパウ!波紋カッター!」って言うの忘れてしまったのが悔やまれるけど、やっぱり実物かわいかった。

あきちゃ「きてくれてありがとー」
「えっ?!」
あきちゃ「きてくれてありがとうーだよ」
「13位おめでとうー」
あきちゃ「ありがとうー」
「来週表たくさんいれるねー」
あきちゃ「(指で三を作りながら)三日後だよ!三日!」
「あっー!」

隣のたかみながテカってなくて可愛くて気が抜けて雑になって怒らせた。。。
帰りに見えた麻里子様もフランス人形で可愛かったなー

また、なんか適当すぎて自分でもどん引きしたけど、怒ってるあきちゃよかった。

「(上のスクリーン見てるな、あこっち気づいた)」
「あっちゃんが引退ってきいてから野菜シスターずの(以下略)トマト」
あつちゃん「たかみなやってるよ」
「そうなんだ」

時間短かった!

あっちゃん素っ気なさすぎて目から潮吹きそうになったくらいだったw
つまんないのか、最後の握手会だからか、自分だけ選挙関係ないか良くわからないけど、ずっと上のスクリーンみててこっち気づかないあっちゃんが印象的だった。

あっちゃんの列に知り合い並んでたから、出てくるの待ってたら「出口に泣きそうになるのを堪えながらむかったら Yappo が立ってたので全部消えてなくなった」とか言われて、その消えた涙が全部こっちに来たのがこちらのブログになります。

夕方の部A

かのん「ありがとうこざいますー」
「44位おめでとうございますわ」
かのん「ありがとうございますー!」
「本番だともっと上の順位絶対行けるよ!」
かのん「はい、頑張ります!絶対選抜入ります!」
「うん、頑張って!おうえんしてるよー!」
かのん「またきてくださいねー」
「うん、くるよー」

やっぱりSKEの子の対応良いなー

かのんとすれ違うために3DS持ってきて遅刻したけど、結局すれ違えなくてしょんぼり。。。

やっぱりSKEの子はどのこも握手会の対応がすっごい良いすな、ちょっとまえにしゃわこの対応がやばいっていうから、何も言わないでしゃわこからなんか言ってくるの待ってたけど見つめられるだけで終わりそうになってあわてて宝塚の話したら凄い食いついて来たけど時間切れって反省があるから、ちゃんと話振らなきゃだめだけど!

第5部A

あきちゃ「んっ、あーあどうも!」
「三日後だよね、まつがえてたよ」
あきちゃ「??」
「今日帰ったら速攻票入れるから安心して!」
あきちゃ「よろしくね、心配になっちゃうよー本当は入れてくれてないんじゃないかって」
「大丈夫、頑張ってね!」

あきちゃにきおくりょくがある事が実証された(俺調べ通算二度め

ほんとは、あきちゃって寿司屋における最後のお茶ポジションだよね。って言いたかったけど記憶力が存外あった影響で計画狂ったけど、一日鍛えられたお陰で美味く切り返した。
ちなみに、うっかり寝ちゃって票はまだ入れてない。

まとめ

朝10時から19時30分までの9時間半の長丁場は流石に体中に答えるので、もうやらないでおこうと思った。
夕方の部が始まる直前に握手できると、裏道に私服の研究生集団がいてだいぶ捗った。

なんにせよ勉強不足がだいぶ仇となった感があるので、僕ももう少しは偉い人達を見習いたいとおもった。

あと、ゆうこすの隣のレーンの江藤彩也香がすっごい可愛いのに列が出来てなくて、暇そうに机直してたり席に座ってたり水飲んだりしてるんだけど、ヲタがきた瞬間にすっごい笑顔で立ち上がるので皆推したら良いと思います。

Posted by Yappo at 12:35 | Comments (0) | TrackBack

2012年05月31日

Perl の循環依存ではまった

こんなコードでハマってしまいましたとさ。
$ cat Hidek.pm
package Hidek;
use strict;
use warnings;
use 5.010;
BEGIN { say 'ふぁいやー' }
use Hidek48;
BEGIN { say 'ファイバー' }

sub mix { say 'はーーーよっしゃいくぞー' }

1;
$ cat Hidek48.pm
package Hidek48;
use strict;
use warnings;
use 5.010;
BEGIN { say 'たいがー' }
use Hidek; # Hidek から呼ばれてて %INC のなかに入ってるからスルーされる
BEGIN { say 'さいばー' }

#Hidek::mix(); # Hidek 読み込ちゅうで、まだ mix ができてない

1;
$ perl -MHidek -e ''
ふぁいやー
たいがー
さいばー
ファイバー
$ 

Hidek::mix を呼ぼうとしても、 Hidek.pm の中身をロードしてる最中に Hidek48.pm のロードを行ってて、 Hidek48.pm のなかでも Hidek.pm をロードしてるんだけど、すでにロードが始まっててロード処理スキップされるから、うっかり mix 呼んでもそんな関数が無い!って怒られるわけ。

うっかりさんこわい。
Posted by Yappo at 17:07 | Comments (0) | TrackBack

2012年04月23日

Hokkaudi.PM Casual #0 参加と全国ツアーした話

去る 4/18 から 4/21 にかけて全国ツアーして来ました。「そうだ干され、てみよう」って水曜の深夜ぐらいに思ったので。

ツアー1日目

とりあえず MBA とナイフとランプをかばんに詰めこんでいざ羽田空港へ。まず、京急蒲田で乗り換える久々過ぎて「どっち?はねだっくうこう?」ってなってたら、なぜか別の階から発射してました親切な駅員さんがいませんでした。ありがとう

で、やっぱり飛行機と言えば寿司ですね。

「横山や!」って叫びたい所でしたが逮捕が恐くて出来ませんでした。こういう事書くから「第三の mattn」とか言われるんですね。心外です。
で、1時間半ぐらい飛行機に乗ってたら新千歳空港に着きました。さて、最初はどこに行こうかなと思ってたら、どうやら Hokkaido.pm Casual #0 がやっていたみたいですね!

第1ツアー会場: 札幌時計台


日本三大がっかりスポットとして有名でしたが、がっかりするとかそういう土台に上がってない感じでした。

第2ツアー会場: サッポロビール博物館


ちょうどいいバスがなくて、時計台から8丁目先くらいで、信号8個さき位だから余裕で歩けると思ってたら、中心から外れるにつれて1丁目の幅がどんどん増えてくという北海道の洗礼を受けました。


500円で、この写真のチーズと左から、黒ラベル、クラッシック、開拓時のやつが飲めたんですが、黒ラベルとクラッシックの違いわからないし、会社の先輩に恵比寿にあるやつなら安くて種類飲めるってアドバイス頂きました。

第3ツアー会場: さっぽろテレビ塔


寒くて観光どころじゃなかった。てか凄い雪詰んであるし試されまくった。

第4ツアー会場: Hokkaido.PM Casual #0

Hokkaido.PM 言った事無くて、平日にやるなら1万円代で行って泊まって帰れるならいこうと思ってたら、16,000円くらいのチケットが本当に取れてこれました。実際は3000円多く払って帰りの便変えてるけど。
Kyoto.PM #1 の時に JPA スポンサードされた分の余裕をこっちに回したっていう体なので、 JPA が無ければこれませんでしたね。

カジュアルな会という事で、来月出るって噂の Perl5.16 に搭載される新機能をカジュアルな感じで紹介しました
http://yappo.github.com/talks/20120418-hokkaidopm_casual1-perl516/

参加者全員が何でもいいから話すという感じの、ゆるふわカジュアルな会でした。
impress.js hack が印象深かった。ほっかいどうは音楽系の比率おおかった。
あと casual じゃない高校生 Perl Monger が AnyEvent::SkypeKit っていうのを作ってるそうなんで期待大ですね。

あと追加で tora の紹介して!って言われたので、簡単な話とmy $hash = { foo => 1};say($hash['bar'])で簡単にコアを吐くという紹介をしました。ついでに北海道の住所正規化のコード出しながらこんな事やってるって言いました。

第5ツアー会場: ジンギスカン


特に懇談会の予定なかったんですが、近所の誰も行った事ないジンギスカン屋につれてってもらえました(^q^
メインもうまかったけど、行者にんにくと何かのタイが美味かった。

YAPC::Asia Hokkaido の話と、 JPA の講師出張のやつは東京から行くだけじゃなくて、福岡から北海道とか、東京絡まない形で派遣制度使って派遣し合えたらいいなとか話した。
あとキモトタクミについて質問されました。

第6ツアー会場: すすきの

路上のお兄さんにダウンタイムに付いて質問したら、逆セクキャバってのが希少価値あるって教えてくれました。
プラプラしてたら Facebook で神席あたった報告を受けたので「会社の人に相談して行けそうだったらいく!」とだけ残して、山頭火たべてホテルでねました。

ツアー2日目


僕はイビキの煩いおっさんの部屋の鍵がたまたま開いてて助かると言った事も無く、普通にねれました!

第7ツアー会場: 村上カレー店 プルプル


前日の懇談会で Hokkaido.PM Casual のリーダーから、ここの納豆カレーめちゃおすすめ!って教えてもらったので行ってきました。
北海道素人には入るのむづかったけど、納豆味こくてすごいうまかった。

第8ツアー会場: 小樽駅


本当は車窓みたかったんですが、札幌からの車中は神席対応してたので楽しめませんでしたが、駅付いたら写真の通り雪が積んであって北海道やばかったですね。

第9ツアー会場: 小樽市内


北海道で最初の鉄道だそうです。


あてもなく地図も見ないで歩いてたら、観光っぽくなかったんですが、この場所付いてやっと観光っぽくなりました。


すしざんまいですねー小樽まできてすしざんまいとかだいぶ無い感じが半端無いんですが、どうなんでしょね。


メルヘン交差点って名前だそうです、メンヘルっぽさがよくわからないけど、オルゴール屋がいっぱいある所が総なのかな。


ロケタッチガイドみてたら、三角市場で食えって書いてあったのでここまで頑張って歩いて食べに来ました。
店でたら目の前の店で毛蟹が仲間になりたい感じしてたので二匹お供にしました、前日に今の毛蟹はOKって言われてたし、ついでに行者ににんいんにくも買った。
三角市場の前に中央市場ってとこもあるいたけど、あっちは地元用っぽかった。

第10ツアー会場: 小樽天然温泉湯の花

風呂入ってなかったので、温泉探していってきましたね。北海道ってあんまり温泉ないっぽい
露天風呂にテレビ付いてるからずっとみてたら、飛行機間に合わない感じになって慌ててでてバス停いったら、さっき出たばっからしいから、走って駅に向かおうとしててバス停から200mくらい移動して後ろ振り返ったらバスが何故かいて、慌ててもどったらバスも待ってくれたんだけど、全然ドア開けてくれなくて騒いでたら開けてくれて、お金払おうとしたら後で出いいです!って怒られてたんですが、後ろ乗り後払いのばすでした!東京のバスは前が好きなので勘違いしてたよ!

第11ツアー会場: MySQL Casual


小樽から70分書けて千歳ついて、1時間まって離陸して22時くらいに羽田ついたら、渋谷で MySQL Casual 反省会してるって事だったので、マークシティ行きのバスに飛び乗って参加してきました。
Hokkaido.PM Casual のカジュアルさが身にしみてわかりました。

ツアー3日目

第12ツアー会場: オフィス

地方ツアーの合間の東京のスタジオ的な感じで、朝早めに行ってジャムセッションしてた。

第13ツアー会場: 新幹線


とりあえず MBA とナイフとランプをかばんに詰めこんでいざ品川駅へ。その後名古屋でJR岐阜駅にいって、小一時間待ち人を待つ。

第14ツアー会場: AKB48全国ツアー2012「野中美郷、動く」チーム4岐阜


と言う事でやってきました。


この画像で言うと上から2番目の真ん中当りと言う神席だったので、気づいたら小樽から岐阜にきていました。

よく考えたら公演きたのは初めてで、はじめてでこんな神席でごめんなさいと思いつつ会場ついてよく考えたら、チーム4の昇格メンバーが揃ってフルメンバーの初お披露目という事で盛り上がってた。
セトリはこんな感じ

  • ヘビーローテーション
  • Everyday、カチューシャ
  • High school days
  • 走れ!ペンギン
  • 初めてのジェリービーンズ
  • Blue rose
  • わがままな流れ星
  • 口移しのチョコレート
  • ごめんね、ジュエル
  • Seventeen
  • ポニーテールとシュシュ
  • 君のこと好きだから
  • BINGO!
  • 夕陽を見ているか?
  • 10年桜
  • 大声ダイヤモンド
  • 言い訳Maybe
  • Beginner
  • RIVER
  • 風は吹いている
  • フライングゲット
  • 僕の太陽
  • 初恋は実らない
  • 少女たちよ
  • GIVE ME FIVE!

最初はヘビロテ、エビカツという流れで始まったわけですが、あまりの目の前さ加減に照れてしまって集中出来なかったのが残念。走れ!ペンギンはぱるるがだいぶ可愛かった。
自己紹介MCだと、レモンが本当に観客にあれやらせてて一体感してて吹いた。

MC 終わってユニット特集だと Blue rose で島田がだいぶ頑張っておったのと、口移しのチョコレートのらんらんがだいぶイケナイ感じになって気を失いかけた。あとのMCでゆきりんを研究してコピーしてたとかとか。

ユニット終わった後の MC は岐阜県クイズ始まってて「みなさんにあいにきましたー!」とか言ってたけど、俺のが小樽からあいに来たよとか思った。あと岐阜クイズ殆どわからんかった。

で、 SKE っぽい衣装きてたからもしかしてとおもったけど、普通に Sevnteen はじまったけど、君好きもやっててだいぶ良かった。

で、初めてだしほぼ目の前だから光る棒の振り方とか良くわからないから、 BINGO! とか適当に踊ってたんだけどね、何か視線感じるんだよね、よくみたらさステージの上のじゅりがなんかこっち見てるわけさ。じゅりが。だいたいの「目が合った」とかは勘違いも甚だしいんだけど1mくらいしか離れてないような距離だとそんなことないんだよね、それに後ろ確認したけど視線の先に俺しか居ないし。
で、 BINGO! って曲はサビの所の振り付けが、手をグワシみたいにして前後に手を動かす感じなんだけどさ、じゅりが俺のほうにやってくるんだよ、視線だけなら勘違いかもしれないけど腕の直線運動とかだとさ三角法とか持ち出す事もなく俺のほうじゃん、で俺も良くわからないから同じ踊り踊ってたから、もうなに?シンクロ?すごいよね軽く三途の川渡ってたし。しかもさ、普段から目が死んでる事で有名なじゅりがその日は死んでなかったから目が笑ってるんだよ、それも俺見ながらだよ。むしろ俺が死ぬわって。

そして、最後の着替えのMCは、ツアータイトルにもなった野中美郷がドレス来て登場。
チーム4の平均年齢よりも年上だったから、ちょっと大人のおねーちゃんみたいで可哀想だったけど、ジェスチャーゲームのジェスチャー頑張ってました。
第一問が「ハート型ウイルス歌ってる秋元才加」って簡単なのだったので、ハート型ウィルス踊ってゴリラのまねしてて正解だしてました。
「会場を爆笑の渦にさせてる高梁みなみ」って酷いのが出題されて、うっかり「できねーだろw」とか突っ込みいれたけど、普通に声が届く位置なの忘れてた。
で、お誕生日サプライズやって、 MC 後半だけどすっかり記憶が無い。。。
最後のぱるるのMCの〆で、それまで大丈夫だったのに急にポンコツでてきてかみかみで吹いたけど、本人に聞こえちゃうからギリギリこらえた。。。

そしてラストに向けたSingleラッシュで、いわゆるダンス曲を3連続やってたけど、さすがに皆スタミナきれてて衣装はだけながらだいぶ酷い顔になってたw

アンコール二回目でぎぶみーふぁいぶだったんだけど、すごかった、すごい、何が凄いって、演奏が一瞬止まってたり、みなるんのギターソロが単音引けてなくて全部弦引いてたり、レモンのシンセフレーズ殆ど引けてなかったり、アベマのベースライン動いてなかったりしてて終わってかららんらんに慰めてもらってたりwすごかったwけど島田がドラムキープ頑張ってたから何とかなってた、あと、僕らの前ではらんらんとかじゅりとかぱるるが楽しそうに踊って歌ってたのがよかった。興味ない人が見たら宗教儀式にしか見えない感じで終わった。

レモンは本当に細くてちっちゃくてビックリするなー、ぱるるは大部見た目が初期のゆきりんっぽくなってた、らんらんも俺の知ってる感じからだいぶ進化してて可愛くなってたし、じゅり名前と顔わからなかったけど大部可愛かった。それにしても島田はごつい。サシで見る時はだいぶ小さいんだけどなw
全体的には凄く満足できたので、頑張って岐阜きたかいがありました!

ちなみに支配人がとったこの写真のどっかに僕居る

第15ツアー会場: 名古屋駅の飲み屋

閉店まで反省会してました。

第16ツアー会場: 東横イン


僕はXなんとかさんと違うので、ロケタッチで近くのホテル探して止まりました。23時以降にはいると4000円台でとまれたけど、チェックインしてから2時間くらいは興奮して寝れなかったけど、気づいたら朝でした。

ツアー3日目

第17ツアー会場: 名古屋テレビ塔


otsune さんが反応するのでノーコメント。

第18ツアー会場: 三越 東洋軒


黒かれーおいしかった。ワインは今ヨンくらい。

第19ツアー会場: SKE48劇場

ショップも劇場もすっげーならんでて良くわからなかった。

第20ツアー会場: 名古屋城



観光らしい事もしとこうかとおもって。戦争でアメリカに燃やされちゃったらしいですね。だから中身は古ビル風味。本丸を再建中らしい。

第21ツアー会場: 伊勢神宮


名古屋城から駅に向かうバスに乗ったら、50分くらいかかる観光バスで切れながら途中下車して、ぎりぎり空いてる時間に到達した。
伊勢市駅からバスのったんだけど「伊勢神宮ってまだはいれますか?」って運転手にきいたら「ひろいからどこだかいってくんないとわかんないよ!」っていわれて、内宮ってとこいきたかったから「そとみやじゃなくてうちみやです」って言ったら「げくう?うちくう?」とか良くわからないこと言われて遠いほう!っていって教えてもらた。
良くわからない事言ってたの僕なんですけどね!

で、現地ついたら急に雨強くなった。傘持ってないのに。我慢して本宮ってとこまで頑張ってあるいてたら、女神様が「風邪引くでしょ!」って言って傘を分けてくれた。で、ここまではいい話なんだけどお参りするまえに傘たたもうとしたら閉じられなくて、力入れたら骨が全部おれたw
「天下布武に引き続き協力してね」ってお願いしたら、さらに雨が強くなったけど敷地からでたら雨やんだから神って居るとおもいました。

で、バス待ってる間に赤福買おうとしたら、土産やのひとが赤福の営業おわるから全部回収されちゃったとか言われたので、赤福なにさま?って思った。

第21ツアー会場: 伊勢うどん屋


伊勢市駅前何もなかったから、バスで宇治山田駅前に降りたんだけど、これも何も無くて伊勢市駅前まで歩いて、東京に変える為の終電ちかかったから18:54分発の特急券買って、名物食いたくて駅前案内の看板みて見つけて入った。

「あと20分で特急来るけど大丈夫?」って聞いたらうどんだったらすぐ出せるって教えてくれて、急いでだしてくれた。伊勢市で唯一の良い思いで。
つゆが美味しい感じなのと、めんがおふっぽい柔らかめんで食感も味もとても良かったから又食いたい。

第22ツアー会場: きしめん屋


名古屋ついて新幹線の指定席チケット(僕はXなんとかさんとちがうから)買って、お土産かって伊勢そばだけだと腹減ったので「そうだ、きしめん食べよう」って事で駅の中のみせ入ったんだけど、注文してから気づいたんだけど新幹線が10分後にくるらしいから、猛ダッシュでやけどしそうになりながら全部食った。
美味しかったんだけど味よくわかんなかった。。。。

第23ツアー会場: 東京の飲み屋

22:30ごろに東京ついてたんだけど、岐阜の自慢を延々としてたら帰宅したの4時前でした。。。(LINE調べ)

まとめ

Hokkaido.PM Casual #0 面白かったです。じゅりにやられました。ロケタッチやってると、旅の思い出が下の画像の用に視覚化されるのでおすすめです。


Posted by Yappo at 17:32 | Comments (0) | TrackBack

2012年03月19日

Kyoto.PM #1 で発表してきました

と言う事で Kyoto.PM #1 は JPA 講師派遣制度として発表してきました。
京都素人すぎてランチの時間をみすってご迷惑おかけして申し訳ありませんでした。

なんか、関連ブログを見ると懐石料理で遅刻って文字がいっぱいあってもう泣きそうです。
京都らしい地域性を特色にした PM って懐石料理くってて遅刻するってことじゃねーだろ。。。


最初は捗るシリーズの話を考えていたのですが、 Atnd 見たら Perl にあまり触れてない方の参加が多そうだったので、 Perl の面白さや仕事に活かせる話等を中心にした発表に切り替えました。

LT4本分の時間構成のつもりが、発表枠10分おおかったってのに直前で気づいて、 Acme の話をゆっくり丁寧に Perl 知らない人でも興味持ってもらえそうな事喋ってたら、 Acme の話だけで20分つかって、あとだいぶ駆け足だった。。。

http://yappo.github.com/talks/20120317-kyotopm1/

clouder さん作の markdown2impress.pl は、簡単な書式で凄いプレゼン作れた感満載のレンダリングできるのでマジおススメです。

感想的なのを

nitoyon さんの文章の相似を調べる為の特徴語抽出のロジックで、句読点やてにをはを使って分割して文字数の数列を使うってアイデアは面白かった。

azumakuniyuki さんが、 $x=1; $y=1; の時に、 $x == $y より $x ~~ $y の方がはやいよ!って行ってたけど、そんなわけないだろうと手元の 5.15.1 でベンチとったら $x == $y のが速かった。


あと、京都の色んな話を聞いたら通り名を処理出来る仕組み作ったほうが良いなと思った。
たぶん wedata 的な仕組みを使って皆でデータを作れて自由に使えるような感じでやると良さそうかなって所まで思ってる。

Posted by Yappo at 14:23 | Comments (0) | TrackBack

2012年03月02日

Kyoto.pm Tech Talks #01 に JPA の 地域PM向け 講師派遣支援プログラム で参加してきます!

Kyoto.pm Tech Talks #01 (2012/3/17) 開催のお知らせ - Japan Perl Association運営ブログ

[以下Kyoto.pmよりのお知らせです] === こんにちは、柴崎(shiba_yu36)です。 今回はKyoto.pmの立ち上げとKyoto.pm Tech Talks #01開催のお知らせです。

去年のYAPC::Asiaから、京都にもPerl Mongersが欲しいと思って構想を進めてきたKyoto.pmが、ついに3月から活動を開始できることになりました。
そこで最初の活動としてKyoto.pm Tech Talks #01を3/17(土)に開催します!

今回、初の活動にもかかわらずJPA様の支援を頂いて、なんと!! App::Ikachanなどの様々なCPANモジュールの作者であり、WEB+DB PRESS での Perl 連載枠の立ち上げなども行なっているYappoさん(http://blog.yappo.jp/)に、特別講師として京都まで来てもらえることになりました!ありがとうございます!

と言う事で ikachan で著名な私が地域PM向け 講師派遣支援プログラムにより Kyoto.PM に行って参ります。

支援していただける JPA さん 、リーダーの shiba_yu36 さん、会場提供して頂ける はてな さんありがとうございます!

JPAでは各地域のPerl Mongerグループ(PM)間での交流および情報交換を支援してもらうと言う事で、 Kamakura.PM に参加した話、業務で捗る話や #LDeNA で話足りなかった話や kazeburo ware の話とかやりきれたらいいなと考えとります。

まだまだ発表枠が余ってるようなので、近隣の方は発表しにいって Perl Life を捗らせましょう!京都近隣に在住して、京都近隣の会社で働いている nekokak さんも参加されるようですし nekokak さんところの近所の方々も是非是非参加しましょう!

再来週になってしまいましたが、Fukuoka.PM さんかの時は激しく迷子で遅刻しかけた反省を生かして、金曜日の夕方くらいに京都に向かって日曜日の終電とかで帰ってこようかなと思っとります(はてなはもう地図見なくて歩いてけるけど)。大阪とか神戸とか足伸ばせるといいな。。。
まだ宿とってないけど二週間前だから今日中に宿決めないとどうしよう泣きそう。

支援2回目なので、なるべく安く済ませて他の人に回せるように注意する所存でございます。

Posted by Yappo at 17:01 | Comments (0) | TrackBack

2012年02月24日

Perl Hackers Hub 2nd season side story

Kamakura.PM 会場からこんにちわ。


本日発売の Web+DB PRESS Vol.67 にて Perl 連載の2クール目が無事感想したので2クール目の覚え書きでも書いておこうかと思う。

2クール目は、連載開始前〜開始当初に想定していたミッションを結構消化出来たと思っている。
1クール目はどちらかと言うと安定盤石路線っぽい感じでしたが、2クール目はだいぶチャレンジングな取り組みが多かったと思う。
それは、一つの言語をテーマとした時にみたチャレンジさという意味になりますね。

1クール目は、読者がPerlプログラミングをする為の基本やスタンダード、基礎力向上出来る内容と題材そして執筆陣を持ってして素晴らしい記事が量産出来たのが良かった。
最後は Perl Hacker と毛色が違うカジュアル目線のエンジニアにカジュアルなテーマでお願いしたところ、これも評判は良かったようで何よりでした。

前クール目のあらましはこれまでとして、連載全体でやりたい事として「YAPCを絡めたい」「danさんには出て欲しい」「いわゆる日本人以外の人に書いて欲しい」「大規模環境のテーマが欲しい」「首都圏以外の人間に書いて欲しい」といった目標と言ったものは持っていました。
たぶん一人で連載枠廻してたら結構結構死ねるテーマ目標だと思います。というか、僕一人じゃ無理ですね。

大規模環境に関してはお願いする先がだいたい検討ついていて、いつだったかの yokohama.pm やら perl の集まりの時に「mixiのいい人に書いてもらいたい!」「DeNAのいい人に書いてもらいたい!」とお願いしたら、快く候補者を教えてくれてあれよあれよと決まってしまって「mixiの大規模チーム開発」と「DeNAの高トラフィックを支える方法」という、それぞれ大規模だけどもテーマがバッティングしないミラクルがおきたのでした。
それぞれの社内の事情はわからないけど、各社の特色が一番出やすいテーマになってだいぶ濃厚でした。

と、2回連続で特定のプログラミングのテーマに特化した回がなかったので、特定のテーマをという事で、前シーズンでやりたいなーと話に出てた job/queue 周りの話をお願いしました。
job/queueとか大規模開発の一部だろー!とかいう声があったとしたら、それは間違いですね。
裏テーマとしては、1つの会社につき1人しかバトン回らないようにって考えていたのですが、この回で目論みが崩れさってしまって、どうでもいいモードに突入するきっかけになりました(DIS じゃないですよ!)。

で、ここまでで全10回になるんですが、大規模環境の話もしてそういえばインフラよりの話が無かったよねっていう事で、空前の CloudForecast ブームだったので CloudForecast をテーマにお願いしようかと思ったんですが、CloudForecast はそもそも言語枠でやるよりも別枠が良いよねって事で、インフラのプロフェッショナルによるログによって捗る方法を指南してもらいました。

YAPC をテーマにするという事は去年やりたかったんですが、連載枠で YAPC の取り上げ方が難しいというのと手一杯だったので断念したのですが、この年は Shibuya.PM だか何かの時に相談をしてた時に「小飼弾のアルファギークに逢いたい♥」で一度やってるのでそのフォーマットだったら編集で対応できるかもという話になっていて、丁度その場に dan さんが居たので dan さんにお願いしてもらったら快く快諾して頂いて「今年はやるぞ!」っていうノリで YAPC 開催直前まで話題に出ないで時が経過しました。

正確には誰も何もしていないわけでも無くて「YAPCの回 = 海外ゲストと日本人 hacker 交えての座談会」というテーマがあったので、海外からのゲストへの出演交渉を会長が行ったり、英語まじりの座談会だから英語を聞きながらテキストの書起ししなければ行けないから出来る人にお願いしたりとか、実際の開催日程やら座談会の場所抑えやらが行われておりました。
場所抑えとかは明らかにどたばたすぎて、会場の枠ずらし交渉をしたのとかが記憶に新しい限りです。

実際の座談会の side story 的なのは公開収録だったのであんまりないですが、Perl Hacker Hubに tokuhirom 出したいけど原稿書いてくれないだろうから、どさくさで出て来てもらおうと思って直前まで「来てね!出てね!」ってステマしてて、予定通り出演してもらえたのが side story ですかね。
この回については一個言及するときりが無いのでこのあたりで。

2シーズンのトリは海外からの寄稿となりました。誰にお願いするかはだいぶギリギリまでノーアイディアだったんですが、丁度 YAPC の前夜祭で目の前に sartak が居たので、点と点がつながって思わず「sartak日本の雑誌でPerlの記事かかない?」的な事を日本語でお願いしました。実際には周りの人にサポートしてもらって意図が伝わって快諾してもらえて Web+DB PRESS vol.66 の後半に続くわけなんだけども。。。

sartak は日本語を凄い勉強していて、日本語の読み書きや会話等もあうたびにレベルアップしていてビビるのですが、流石に原稿は英語でお願いして会長に翻訳をお願いするか、、とか思ってたんですが、本人が日本語で入稿する!と言って本当に日本語で入稿してたのでマジビビった。最終的には会長との共著になりました。
sartakの回で未来のPerlで触れられたのは偶然だけども、非常に良かったと思っている。

まとめ

と言う事で Perl Hacker Hub の2年目のサイドストーリーでした。名前を出さなかったりとか、誰が何やった!とか極力書いてないのは意図的なので許して下さい。

次のシーズンも意欲的なテーマが予定されているので乞うご期待ですね。

という、他人のふんどしで相撲取るメソッド。

WEB+DB PRESS Vol.67
WEB+DB PRESS Vol.67
posted with amazlet at 12.02.24
川口 耕介 山本 和彦 大和田 純 白土 慧 太田 昌吾 個々一番 Shawn M Moore 清水 亮 じゅんいち☆かとう 小野 修司 おにたま 神林 飛志 杵渕 朋彦 中島 聡 齋藤 正浩 高橋 征義 ミック みやけん
技術評論社
売り上げランキング: 147
Posted by Yappo at 21:10 | Comments (0) | TrackBack

2011年11月30日

Perl-users.jp創設者 大沢Yappo和宏 からの緊急のお願いをお読み下さい

yappo-onegai.png

http://perl-users.jp/articles/advent-calendar/2011/
http://atnd.org/events/22657

今年もやってきました。アドベントカレンダーの季節が!

アドベントカレンダーは特別なものです。たとえるなら図書館、公園、あるいは知の神殿のようなものです。私たちが考えたり、学んだり、知識を交換しあったりできる場所です。

既に5トラックの応募が始まってます!まだまだ席に余裕がありますので Perl に関わってる方は是非参加しましょう。

アドベントカレンダーを開始したとき、そこに広告バナーを設置し営利企業にすることもできたでしょう。しかし、私は別の道を選びました。私たちは、書き込みシステムのスリム化に努め、小さな組織であり続けています。私たちは使命を果たします。努力の無駄づかいはしません。

もしこれを読んでいる方々全員から1エントリずつの寄稿をいただけるならば、この参加者募集活動は一年に一日で済むでしょう。しかし、寄稿していただけるだけの余裕や心づもりが誰にでもあるとは限りません。それでもいいのです。というのも、充分な数の方々が毎年寄稿を決意してくださるからです。

このアドベントカレンダーを守り、維持していくため、1エントリ、1.5エントリ、2エントリなど、できる範囲でのご寄稿を考えてみていただければと思います。

よろしくお願い申し上げます。

Perl-users.jp創設者 大沢Yappo和宏

Posted by Yappo at 18:04 | Comments (0) | TrackBack

2011年10月17日

YAPC::Asia Tokyo 2011 ぼくのかんそうぶん

かんそうぶろぐかけってことなので、ぶくますうがのびるきょうこのたいみんぐでこうかいします。

ここのついきはげつようあさなんですが、あっとうてきにつかれててしゅっしゃできるかわからないくらいかいふくしてないのです。

なんか、こうしたほうがいいんじゃね?とか書いてるけどスルー推奨です。

発表について

なんか優等生トーク(内容ではなくて枠の使い方そのもの)ばっかりよりも、少し型を崩した時のほうが理解を深める事もあるんじゃないかなーと思ってた所で、makamakaさんのゲームのデモをやってるトークは本当に良かった。(まったくみにいってないけど!)

伝えたい目的によっては、壇上の机の前に突っ立ってるより効率よく伝える方法が他にもあるかもしれないので、ちょっと考えてみるといいかもしれない。資料の朗読をしてるだけだと後でスライド見れば良いやってことになりかねないしね。

そう言った意味では、何かしらのデモンストレーションがあると良い。takesakoさんのLTなんか殆どデモだったけどとても伝わりやすくて面白かった。

僕も大講堂の後ろの方までwiiフィットもって走ってデモしたり、講堂の前席にいるhoriigureiruとかにミサイルぶつけたりするデモをやっておこられましたね。

特にスピーカーがあまりに移動すると録画カメラで追いきれないって言われるw
とはいえ一番重視すべきなのは、リアルに交通費つかって、激安という程でもない程度の参加費を払って、時間をめいっぱいつかって、裏トラックを見るのを諦めて、わざわざ自分のセッションにやって来て頂いた方々を最大限尊重すべきなので、動画撮影班とかはあんまり気にしなくてよいのです。まぁみんな好き勝手にやり過ぎてたら本気で怒られそうだけどw

謝罪しない、最初から言い訳しない。自分の発表に自身が無かったり納得がいかなくても、謝ったり自身ないですとか言っちゃ駄目です。せめて「はじめてなのでやさしくしてね」くらいにしときましょう。これはほうぼうのプレゼン入門テキストに書いてある基本です。ただしネタの一環でやるぶんには除く。

lt

本物の自己紹介は要らない。たかだか5分の枠で自己紹介とか本気で時間の無駄ですやめましょう。もしかしたら知らないかもしれないですが、最近のテクノロジーはすごくて、あなたの名前と発表タイトルがgihyo.jpとかに掲載されます。そしてここからのてくのろじいがもっとすごくて、gihyo.jpに乗ってる名前を検索するとあなたのプロフィールが解ります。

ただし、コミュニティなんかの成果報告とか例外だし、ほかにも例外はあるけど純粋なる技術LTで自己紹介は無駄なのは有名な話ですね。これかいてて気づいたけど僕は本トラックですら自己紹介わすれてました。

あとmayumineさんのLTは自己紹介自体がネタの重要な要素になってて面白かったので、ああいうのも別腹とおもっとります。

短時間だし慣れてないと緊張して頭が飛んでしまうこともあると思うので、一番主張したい事だけ神に書いて、キーボードの上に置いとくと、いざという時たすかるかもしれませんね。

みにいったトークについて

資料作成やDan the dan-kaiとかで忙しくてあんまり見れてませんでした。

obraの話は面白くて割と聞いておりました。

コミュニケーションについて

スピーカーに対してはもっともっと絡んだほうがいいかなーと思いました。基本的に事前に準備終えていないスピーカーは、発表前までは資料作りに忙しくて、発表後は開放感で満載で他の人と積極的に絡んだりすることを忘れ勝ちなので、目当ての人がいたら積極的に話しかけるといいです。

ただしPC開いて寡黙になにかやってたら声かけちゃ駄目、集中途切れさせて嫌われるだけです。PCみないでたたずんでたりぼーっとしてるスピーカーは大抵「来週の晩ご飯ローテーション」「おなかすいた」「YAPC中に取り溜めてたアニメの消化スケジュール」などを考えているだけなので遠慮しないで大丈夫です。

たとえ他の人と談笑している時でも、大抵のケースでは別にYAPCじゃなくても話せる相手と話してるだけなので唐突に混ざりにいってもOKです。
まぁ唐突に混ざりにいっといて単なる自己紹介されてもイラっと来る人とかいそうなので(obraとかは平気だけど)、何かしらの話しかける相手の成果物に対する質問や感想や意見等を考えてから声をかけると、話してる事を中断して真剣に話を聞いてもらえます。

スピーカーは自分の成果物を普及しにやってくる生物なので、そういった話をしてくれる人に対するプライオリティが一番高いのです。

運が良ければ、談笑してた相手の人とかも話に参加してくれるかもしれないしね。

みにいべんととか

突発イベント的なあれはもうちょっといっぱいあったほうが面白いかとおもった。やるほう大変だけど餃子のあれてきなのだったらそんなに大変でもなかろうし、運営の治外法権でかってにやっておけばよいw

ちょっと巻き込む範囲が大きくなりそうだったり、事前にやりたい事があったら予め運営に伝えとくのは鉄の掟。僕も Perl Hackers Hub とかいう取材陣やら、商業誌に乗せる写真をパシャパシャ取りまくるような、とても厄介な事をやろうとしてたので、事前に怪鳥と941さんには情報を押し付けておいたので、トラブルなくおわりました。
なんか余ったうまい棒を入り口に運び出すミッションがあったらしいんですが、待っててくれてました。

そういう事前アナウンスなしに突発でやると大抵炎上するし、やってる途中で「だれの許可得て出店してるんじゃ」的な黒い関係者さんがやって来ちゃうかもしれないですからね。
善行だからいいでしょ。的に放置しとくとそれが悪行になったりもしますよ。この言ってる意味解らない人はUOを100年くらいROMっててください。

スイーツエリア

いままで、スピーカーの資料作成の憩いの場だったので、そのノリでみんな資料書いちゃってたのが結果的に失敗だった。受付の裏のスペースに椅子とか電源タップならべて、作業してるだけの人を押し込むような事が出来てたらスイーツエリアで談笑するひとふえたのかなー

あの黙々と作業してる空気感だと喋ってると悪い気になってしまうw

そのほか

下関.pm で、ふぐとくるまえび食べるやくそくした。仙台.pmによんでアピールした。長屋.pmの偉い人にもあぴった。

総括

二日目とか雨降ったりしてたのに、なんだかんだで天気が持ちこたえてくれて芝生に30人くらいあつまってばか騒ぎしたり飲み会で真面目にエンジニアらしい話してたりRJBS問いつめたりして、お祭り感がちゃんと引き継がれててとてもよかったです。今年は余裕ないだろうと思ってカメラ持ってこなかった。

来年はよくしらんけど、東京とか飽きてるのでどっか他の場所でやったらいいとおもう。多分集客大変だし参加者もだいぶ減るから色々たいへんだろうけど。頑張って!

アイドルに食べ物差し入れても食べてもらえないという現象を疑似体験出来たのも良かった。

あと、買って来たシューマイを食べたおっさんたちは一人100円な。

Posted by Yappo at 12:19 | Comments (0) | TrackBack

2011年10月16日

YAPC::Asia Tokyo 2011 で発表してきましたわよ

前回からPHPとかJavaScriptとかしかやってないから何も無いよなーと思いつつ、とりあえずWeb+DB PRESSの話でもしようと思って応募してたんだけど、急に Perl とかやるようになったので急遽LT二本応募とかしましたとさ。

死霊一覧はこちら http://yappo.github.com/

perl hackers hubの話

どんなにblogが発達しようとも、雑誌が無くなってしまおうとも、プロの編集者を通した技術的な出版物というものは大事です。このセッションは、その間口を広げようとするのを目的としました。

前日まで本当にスライドどうしようか良いアイデアが無かったんだけど、発表として伝えたい事は「誰でもこういう事できるんだよ。みんなもやりなよ。」っていうのだったので、年末に発売される回のサプライズな企画の紹介から始まって軽く背景の説明をしておいて残りの時間で会場内に居る関係者を招集して、何も特別な事なんか無いんだよ感を重視して、それぞれの話をしてもらいました。

セッション(この回はあくまでもトークとは言わない)の性質上、エンジニアが得する成果物の発表は無理ゲーなのですが、執筆する事に二の足を踏んでいる人の背中を押せたらいいなと思って、だいぶゆるふわざっくばらんに進行しました。

無茶ぶりで前に出て来てもらった人には、本当に事前に何も話していなかったのでgdgdっていた模様ですが(僕はinaoさんにマイク渡したらdanさんを呼びに外出てて、様子を知らない)、僕は事前に様々なパターンを入念にシミュレーションしてから挑んでいたので上手くまとめられたんじゃないかと思っています。

YAPC - Yet Anthor Perl Conference - Conference - 会議

「会議のはずなのに、授業のように一方通行のセッションだけってのもあんまり面白くないよなー」、「海外のカンファレンス(osdc.twしかいってないけど)、プレゼン中に観衆から発言が飛び出してきて、そこから議論が始まっていって最終的にスピーカーがまとめてオチをつけたりするよなー」「日本ってそういうのやってないよなー」って言うもやもやが頭に合った所に、前夜祭の帰りにロックスターが「日本人ってスライド詰めすぎだよね。もっとゆったりしてもいいのに」的な事を言っていたので、こういう方向性に決まりました。

本当はBOFっぽい感じにもってくつもりだったんだけど、時間が足りなかったのであきらめました。

xaicon-san, nekokak-san, kazeburo-san, dan-san, inao-san無茶ぶり引き受けて頂いて有り難うございました。

ikachan

AnySan, ikachan を遂に shipit しましたよ。の話と、 ikachan の紹介を LT しました。

LT 二日目

うちのプロジェクトのなかで、入社してから皆で作っていた開発環境等が良い感じになったので、他のプロジェクトの同僚向けのプレゼン。

基本的には小さなツールをいっぱい作って UNIX 的に作って行ったら良い感じになったよー。こういうツールがあって便利だよーみたいな話をしました。

LTの割にボリューム多過ぎたのでだいぶ割愛しましたが、要点だけ話せたかなと思います。

続きは社内でやると、僕ぺーぺーで色々ししょうありそうなんで、soozyconとかshibuya.pmで発表したいなーと思います。

その他特殊イベント

唐突にスイーツエリアを占拠して、12月に発売される予定のPerl連載記事用の公開座談会を開催しました。Perl Hackers Hubという名前の通り、折角世界中からPerl Hackerが集まるのでどうにかして出演して欲しいという思いが去年からあったのですが、去年は連載一回目だしlestrratさんもYAPCの運営的に余裕無さそうだから諦めて、今年はなんか行けそうだからxaicronにdanさんに出演交渉依頼を依頼して快諾してもらえたので、開催する運びとなりました。

普段商業誌のインタビューとかって閉じられた空間で開催されるイメージなんですが、今回は会場のタイムテーブル抑えて誰でも参加可能な感じに仕上げてみました。時折野次が入る等なかなか面白い事になったんじゃないかなーと思うのですが、基本僕は裏方でうろちょろしてたので何話してたのか把握してません!

いつかは将来的には海外の方にも参加してもらいたいなーと思っていて、こんなに速く実現するとは夢にもおもいませんでした。
参加者が「obra, rjbs, mlehmann, sartak, gugod, dankogai, tokuhirom, xaicron」と Perl HackerどころかPerl Core Hackerが集まってしまいましたね。
座談会の最後にはサプライズな発表もありました。詳しくは12月末発売のWeb+DB PRESSにて、全ては @mandy_44 の頑張りにかかっている!11乞うご期待。

参加者もろもろの予定の合間を縫った結果、tsucchi-san, motemen-sanの発表枠を直前で移動して頂きました。お二方のご協力、ほんとうに有り難うございました。

Posted by Yappo at 17:03 | Comments (0) | TrackBack

2011年08月18日

Plack::Middleware::ErrorpageRedirectloopDefence

たまたまhttp://twitter.com/kazeburo/status/103842813548040192を見かけたのでネタで作ってみただけのコード。

https://github.com/yappo/p5-Plack-Middleware-ErrorpageRedirectloopDefence

今回のリクエストが前回みてたURLと同じなのに関わらず、エラーページを返しちゃう場合にブラウザ側でのコンテンツの更新を抑止する為のmiddleware。
サンプルはhttps://github.com/yappo/p5-Plack-Middleware-ErrorpageRedirectloopDefence/blob/master/sample.psgiみたいなかんじ。

普通にplackupした時に http://localhost:5000/ok にアクセスすると3秒毎にリロードが発生しますが、 http::/localhost:5000/error とかにアクセスすると、リロードが一回しか行われないのが解るとおもいます。

エラーページを表示しているのに、自分自身をリロードする事になってしまう理由は色々考えられますが、エラーページを何回もリロードする意味は無いよねと思って作ってみただけです。

マジレスすると


  • この仕組みを使わなければいけないケースは、何かが間違っている

  • ライブカメラ等の、同じURLに対してmeta-refreshが必須なページに導入すると、たまたまエラーが発生した時にユーザにエラーであると通知する手段がなくなる


等の理由により使うべきではないです。

Posted by Yappo at 02:00 | Comments (0) | TrackBack

2011年08月16日

App::Ikachan - 様々なサーバのバッチ処理の結果等を IRC のチャンネルに通知するサーバ

皆さんは、日々のお仕事の中で様々なバッチ処理やデプロイツールまたはCIツールを動かすと思います。
一般的なネット系のエンジニアは仕事のコミュニケーション手段として IRC を用いているというのが有名ですが、これらバッチ処理の処理状況等を普段の生活環境である IRC に流せたら便利です。

実際に前の会社では、 deploy tool, ci tool, etc batch script の処理結果を社内 IRC channel に通知するような物を hirose31 さんが作ってくれて、とても便利でございました。

とはいえ、各種スクリプトが独自に IRC server に繋ぎに行く事は大げさですし、バッチが走る都度 join/part されたらうざいです。
そこで前の会社では、 IRC server につながりっぱなしなサーバを立てて置いて、 iDC などのインフラからいつでも何処でも IKC を使ってメッセージを送ると指定したチャンネルにメッセージを投げてくれると言う便利な物がありました。

実際自分が担当していないプロジェクトでも、今現在他のサービスでどんな作業が行われてるかをリアルタイムで把握出来るのは、その会社で働いている上でとても役に立つ事が多いです。

狙いとしては、こうした簡単に通知を行うインフラが整う事で、気軽に各種処理状況が共有出来るようになる事により、今まで何かの処理スクリプトを叩いて IRC とかで手作業で結果報告していたような類いの要件も、全自動化される事により飯が捗るといった事を期待しています。

実際 deploy tool とかに仕込んどくだけでもだいぶ便利ですけどね。

と言うような事をもんもんと思っていたのでさっき作りました。
https://github.com/yappo/p5-App-Ikachan
依存モジュールも、 AnyEvent, Plack, Twigyy, AnySan 程度で且つ、実際は1つの小さいスクリプトファイルなので扱いやすいとは思います。
(とはいえ AnySan が github にしかなくて install 面倒いので、そろそろ CPAN にうpりますが。。。)

使い方もとても簡単で

 $ ikachan -S irc_server_address -N nickname[ -K irc_server_password][ -P irc_server_port]
という形でサーバを立ち上げるだけです。
デフォルトでは http://localhost:4979/ に http server が立ち上がります。
API 仕様などはサーバにブラウザでアクセスした時に表示されます。
http server の address/port が気に食わなければ
$ ikachan -h http_host -p http_port
といったオプションも利用可能です。

チャンネルに入るには

$ curl -F channel=\#catalyst-ja http://localhost:4979/join
が使えます。

チャンネルを抜けるには

$ curl -F channel=\#catalyst-ja http://localhost:4979/leave
が使えます。

チャンネルにポストするには

$ curl -F channel=\#catalyst-ja -F message=こんにちわこんにちわ! http://localhost:4979/notice
が使えます。

ikachan はどのチャンネルに join したか等の情報をストレージに保存しないので、一度プロセスを殺したら、まえ入っていたチャンネルが解らなくなります。( http://localhost:4979/channel_list の内容をバックアップしとけばいいけど )
なので、 notice コマンドを送る時には join コマンドを一緒に送る事をお勧めします。

$ curl -F channel=\#catalyst-ja http://localhost:4979/join
$ curl -F channel=\#catalyst-ja -F message=こんにちわこんにちわ! http://localhost:4979/notice

ikachan を操作するプロトコルは HTTP なので、様々な言語や環境で扱いやすいんじゃないかなと思います。ので、これを機に是非お試し下さい。

作って早々、 kazeburo さんに社内サーバに設置してもらって、作り途中の開発支援ツールに導入して便利になった予定です!

作った後に、まったく同じ事をする kan さんが作った App::donburi の存在に気づいたのですが、ちょっとおおがかりだし founder が irc 使わない会社に転職したりで、やっぱり知ってても使わなかったと思った。

Posted by Yappo at 22:13 | Comments (0) | TrackBack

2011年08月15日

Devel::GlobalDestruction

Perl 終了時のゴミ回収フェーズに入ってるかどうかを調べるモジュール。
くわしくはhttp://perl-users.jp/expert_perl/hentai_modules.htmlでも見ればおk。

一番したに貼付けたサンプルコードを見ると、きっちり END フェーズの後にフラグが立ってるのがわかる。

しかし、 do と normal の実行順序が違うのが気になった。これは do ブロックの中に文を追加すると想定通りの実行順になるので、 perl 側でなんか最適化してるのかなーとかおもた。

ので B::Deparse さんの出番だとおもったけど https://gist.github.com/1145662よーわからん。

あ、 perl 5.14.1

Posted by Yappo at 12:31 | Comments (0) | TrackBack

2011年08月04日

Lion の絵文字を Encode::JP::Mobile で扱う研究会

Mac OS X 10.7 から普通に💩💩💩💩💩などの絵文字が取り扱えるようになりましたので Encode::JP::Mobile で扱えるのかどうか調べたらいいのかなと思ったのでメモ。

このへん kawanet さんが詳しそう。

Posted by Yappo at 11:18 | Comments (0) | TrackBack

2011年04月26日

LWP::UserAgent の HTTPS 対応は LWP::Protocol::https というパッケージに分離されました

最近あたらしい Perl の環境を作って LWP を入れて https なページにアクセスしようとしたら

LWP will support https URLs if the LWP::Protocol::https module is installed.
って言われてビビるかもしれません。

それは https 対応するモジュールが別ですと李に分離されたためです。
そういう時は迷わずLWP::Protocol::httpsを入れればいいです。

Posted by Yappo at 19:24 | Comments (0) | TrackBack

2011年04月22日

iPhoneの移動履歴を再生するiPhone Tracker Stream作ったよ

今話題の、お前のリアルな行動履歴はJobs様に筒抜けの件ですが、sugyan++ するだけでiPhoneのトラッキングファイル抽出作ってもらったので、それつかってiPhoneの移動履歴をGoogle Mapでストリーミングするツール書いたよ。

https://github.com/yappo/iPhoneTracker
適当に動かしてSafariとかで開いてください。
全部再生し終わったらプロセス殺してあげ直すとかそういうので。
s/Wifi/Cell/ にすると基地局をプロットします。デフォルトはWifiアンテナの位置なのでより精密です。

彼女の電話をハックするネタが前の飲み会で話題になっていて、いつかやりたいなーと思っていたのですが、遂に出来てよかった^^

ちなみに私のはこんな感じでした。

Posted by Yappo at 16:20 | Comments (0) | TrackBack

2011年04月13日

yappocall を作った。もしくは inside yappocall

もともとはヌーブラアプリを作るためにiPhoneの開発環境を作ったのですが、ちょっと気が向いてim.kayackみたいなのを作ってみました。
im.kayack使えば良いじゃんって話もありますが、着信音を僕の好きな音とか声とかにしたかったので作ったのです。
通知の時にならす時には、hoge.appを作った時に一緒にコンパイルされてないと駄目なんです。
同時にコンパイルされちゃってさえいれば、通知するサーバ側の都合で音声を選べるという感じ。

yappocallは何かというと、YappoのiPhoneに好きな音声と共に秘密のメッセージを送れる超便利サービスです。
http://seiitaishougun.com/iphone/yappocall.cgi
で、いつでもどこでも好きな時に僕宛に秘密のメッセージを送れます。
人生相談、ピザの注文、プロポーズまで幅広くお使い下さい。

すでに、ランチのお誘い、ワインのお誘い、ごじます、おススメマッサージ店のご紹介、地震速報、新入社員の愚痴、AKBのセンターはtokuhiromがなるべきというご提案、挿入持ってくる、じゃーん!、おごれアピールなど多種多様のcallを受けております。

なんでこのエントリを核期になったかというと

これ仕組みしりたいです・・・

っていうcallをされたからですね。

仕組みはiPhoneのAPIでRemote Push Notifiyとかそういう仕組みが用意されてるので、頑張って実装して下さい。
そんな頑張んなくてもPush通知使いたい!ってAPIを叩くと自動的にappleのサーバに問い合わせて、その端末に紐づいた Device Token を引数にどっかのメソッドが delegate されて呼ばれるので、そこで好きなように device token をサーバ側に持ってくれば良いだけですね。
簡単です。

サーバーの方はとっても簡単で yappocall.cgi を用意して、 worker.pl をローカルで実行させるだけです。
Apple の Server に通知を送りつける専用プロセスが必要なのが面倒ですが、短時間に接続するとbanされる可能性もあるってtypesterのお兄さんが言っていたのでsocketを使い回してbanを防ぐ作戦をしています。
CGI と Worker の間の通信は今大人気の MessagePack を使ってるので安心高速ですね!

残念なのは Net::APNS::Persistent は、 socket 切れたら放置される実装になってるので、直すのも面倒なので前回の通知処理から30分以上たってたら socket 繋ぎ直すようにしてあります。

烏賊ソース

Posted by Yappo at 02:21 | Comments (0) | TrackBack

2011年02月09日

ShipIt::Step::Facebook - モジュールをCPANにうpったらFacebookでお知らせ

おれなんかだいぶ昔からふぇいすぶうkしてるんだけど、皆さんはいまさらブームらしいですね。

いままで真面目にふぇぃすびっくのAPIとかそういうの触ってなかったんですが触ってみたついでに、shipitしたらFacebookにお知らせするやつ書きました。

http://frepan.org/~yappo/ShipIt-Step-Facebook-0.01/
https://github.com/yappo/p5-ShipIt-Step-Facebook

基本的にはhanekomuのShipIt::Step::Twitterのコピーとなっております。
違うのはpostするurlにfrepanを指定できる位。

postするWallとかも変更できるので、CPANおーさーの皆様は自分のファンページにでも向けて通知すると良いんじゃないでしょうかね?
てかレガシーな方のAPIだと、uid変えればファンページに直接投稿できるのにGraph APIだと

kazuhiro osawa => Yappo
みたいな事になって嫌な感じなんだけど誰かしりませんか!?APIリファレンス見ても出来なさそうなんですけど。。。

あと良く判らないのは、access_tokenを取るために僕が作ったアプリケーションのApplication IDをaccess_token作るツールに埋め込んであるんだけど、それってやっていいのかな?という。
この使い方だとapp keyもapp secretも使わないで済むんだけどそれでいいの?とか。

あと、なんかふぁんぺーじに25人以上はいるとパーマリンクつくれるらしいんで入って下さい

Posted by Yappo at 19:49 | Comments (0) | TrackBack

2011年02月03日

HTML5 の Application Cache 用の manifest ファイルを簡単に作れる HTML5::Manifest and Module::Install::HTML5Manifest released

HTML5 から offline application を作るための強力な機能として application cache が追加されています。
これのキャッシュを制御する方法としては、専用の manifest ファイルを書かなければいけないんですが、手で書くのもだるいし専用コマンド作るのも打つのもだるいので

 $ make html5manifest
ってコマンド叩いたら htdocs 以下を勝手に探索して manifest ファイルを作ってくれる物をこしらえました。

http://frepan.org/~yappo/HTML5-Manifest-0.02/
http://frepan.org/~yappo/Module-Install-HTML5Manifest-0.01/ そのうちCPANにも登録されます。

ディレクトリの中から対象となるファイルを集めて来て manifest ファイルを作るための HTML5::Manifest というモジュールと、 HTML5::Manifest と Makefile の繋ぎ込みをしてくれる Module::Install::HTML5Manifest というモジュールの二本立てにしました。

HTML5::Manifest 単体の使い方は、きっとだれかが PSGI な middleware 書くだろうから今回は省略しておいて Makefile.PL での使い方をさらっと説明します。

POD に書いてあるのであんまり言う事ないですが

    html5_manifest
        make_target   => 'hoge',
        htdocs_from   => 'htdocs',
        manifest_skip => 'html5manifest.skip',
        generate_to   => 'example.manifest',
        with_gzfile   => 1, # create .gz file
        network_list  => [qw( /api /foo/bar.cgi )],
        use_digest    => 1,
        ;
とかして使います。

make_target は Makefile のターゲットを変更します。この例だと

 $ make hoge
で manifest ファイルを作るって事。
デフォルト以外の物をしていする事によって、複数種類の manifest ファイルを管理したい需要に応えます。

htdocs_from は、どのパスを起点にしてキャッシュするファイルのリストを作成するかを指定します。
普通に document root を指定するべきですね。

manifest_skip は、 htdocs_from で指定したパスをトラバースする時に、無視するファイルパターンを記述してあるファイルを指定します。
MANIFEST.SKIP と同じ役割です。

generate_to は、実際に作られた manifest ファイルを保存する先です。

with_gzfile は、真の値を渡すと generate_to と共に .gz ファイルも作成します。
manifest ファイルが、そこそこの大きさになったときに .gz 化してサーブする事を想定しています。

network_list は、 manifest ファイルの NETWORK セクションにそのまま書き出されるリストです。 NETWORK セクションについてはググれ。

use_digest は、キャッシュ対象のファイル全部の MD5 チェックサムを manifest ファイルの中に書き込みます。
ファイル構成がかわらなくても、どれかのファイルの内容が変更になったらチェックサムが変わるので「manifestファイルが更新されたら、キャッシュを更新する」という application cache の仕様を満たす事が出来ます。
手で、一々バージョン番号ふったり make html5manifest した日時を自動的にいれるとか面倒ですよね。

HTML5 っていう名前空間は、仕様の名前を使ってるから問題無いという判断。だれだって HTML::HTML5 とかタイプしたいと思う人なんかいないし。

ということで Perl で HTML5 をやっている方はお試しください。

Posted by Yappo at 21:54 | Comments (0) | TrackBack

2011年01月28日

FizzBuzz最短回答 もしくは Yahoo!Japan 入社課題提出エントリ

FizzBuzz問題程度30byte以内で解かないと、今時はYahoo!Japanすら満足に入社できないそうなので、課題提出しておきます。

皆さんご存知の通りPerlを使えば1byteもコードを書かずにFizzBuzz問題が解けてしまいます。
今日現在のバージョンのPerlでは、何かしらの方法でAcme::FizzBuzzモジュールをインストールします。奇遇にも最近新しいバージョンが出ました
インストールしたら、今度は

export PERL5OPT="-MAcme::FizzBuzz"
としておまじないをかけます(bash shellの時)。他の環境でのおまじないについてはTAKESAKO @ Yet another Cybozu Labs: FizzBuzz - Golf Challengeを参考にして下さい。

準備が整ったら0バイトのコードを用意してPerlで処理します。
今回はエディタ起動するのが面倒なのでechoコマンドで代用です。

echo '' | perl

なんということでしょう。30byte未満でFizzBuzzのコードが書けてしまいました。

Perlが駄目なら

やふーの事ですからPerlがだめっていうかもしれません!
そうだったらシェルすくりぷとで30byte未満で書く方法を実装しました!

curl http://bp.to/yahoo.txt
27byteで問題解けましたね!

...

マジレスすると、途方も無い苦労をかけてAcme::FizzBuzzをPerlに標準で添付されるモジュールにしてしまえば

use Acme::FizzBuzz
という18byteのコードで本当に実現してしまうんですけどねー

あーFizzBuzz最短問題飽きたわーーー2年前に飽きたわーーーー

Posted by Yappo at 03:20 | Comments (0) | TrackBack

2011年01月13日

Pikubo の写真投稿をリアルタイムで通知する Pikubo Growler 書いたよ

こっちが本題なんだけど、わざわざブラウザ開いて Pikuboream とか見てるのだるいんで AnySan と Cocoa::Growl つかって pikubo に写真投稿した tweet があったらリアルタイムに growl で表示するやつ書いたし。

https://github.com/yappo/p5-AnySan/blob/master/eg/pikubo-growler.pl

Growl の通知アイコンに撮影した写真を設定して、 growl をクリックすると URL をブラウザで開いてくれる優れもの。growlを見るだけでどんな写真がうpされてるかわかっちゃう。
System Perl に依存して、必要なモジュールを全部詰め込んで PikuboGrowler.app として、出したかったけど全自動で consumer_key とか token を取る方法が良くわからないのでおあずけ中。
FriendFeed に pikubo.me な tweet を全部流してそっちを見ればいいのかなx。。。

コードは以下の感じ。単純ですね!

Posted by Yappo at 17:26 | Comments (0) | TrackBack

2011年01月06日

Groonga for Perl Project

表題の通り Groonga さんの Perl バインディングかき始めてます。
Groonga とは senna の後継検索エンジンで、サーバとかついてるんですが Groonga for Perl では libgroonga のバインディングを作ってく感じになるので、 Groonga のサーバとか叩くような物は提供しません。

https://github.com/yappo/p5-Groongaでやってます。

libgroonga を直接叩く事によって Groonga の Ruby バインディングで提供されてるような特定のキーワードに対してマークアップするフィルタのような事も簡単に作れます。

rroonga での tag_keys を Perl に移植すると以下のような感じになります。

Groonga に対する入出力はバイトストリームにする感じです。
ノーマライズ処理がまだうまく動いてないどうすればいいんだroge.

ちなみに、まだパトリシアトライを弄る部分しか実装されてないので、他の機能が欲しいと言う方は是非パッチ送って下さい。

大昔に Rast の Perl バインディング書いてた時は、 XS 書くのが辛かったんですが今だと Module::Install::XSUtil やら XS::Object::Magic のお陰でめちゃんこ楽に書けるようになってますね。

数少ない優良なバインディング案件ですので、皆さん是非開発に参加してください。

Posted by Yappo at 11:50 | Comments (0) | TrackBack

2010年12月16日

Cocoa::Growl が面白い

なんかの時に、お勧めの growl を扱うモジュールの話をした時に、最近の俺の macbook pro では Mac::Growl が入らなくなって悲しいって話をしてたら typester さんが Cocoa::Growl を作ってくれました。

Objective-C をそのまま XS module 化しててイカすんですが、さらに AnyEvent のイベントループを cocoa のイベントループを使うようにする AnyEvent::Impl::NSRunLoop なんてのまで作っちゃって、
これを使うと growl の通知をクリックしたイベントとかを Perl 側でハンドリング出来ちゃったりして面白そうだけど使いどころ良くわからなかったので、 AnySan で繋いでる irc チャンネルに yappo って含む発言があったら growl で通知して、それをクリックすると irc の方に click って発言する bot を書いてみました。

なんか俺の事を話題にしてるけど返事する暇無いけど、その発言俺みたから!ってのを伝えたい用途に使えると思います!

ちなみに Cocoa::Growl はアイコン画像対応が終わったら shipit されるそうです。

追記:もちっと実用的に friend feed の cpan を流し続ける growler も書いときました。

Posted by Yappo at 13:37 | Comments (0) | TrackBack

2010年12月10日

Fukuoka.PM #18 行ってきました

 Ficia Photo

だいぶ報告が遅れましたが、11月27日に福岡の博多でFUkuoka.PM #18が開催されて、なんと幸運にも招待していただいたので発表しに行ってきました。

事の経緯としてはYAPC::Asia 2010の飲み会でフラグを立てたところ、あれよあれよという真に招待して頂いて何とただで行く事ができました。

JPA++/Fukuoka.PM++

なんでただで行けたかというとJPAの新しい試み第1号に選んで頂けたおかげです。
今後も遠方に派遣するような試みを可能な限りJPAでやっていくそうなので「この地方のPerlの催しに行ってみたい!」「この人を呼んで合いたい!喋りたい!喋らせたい!」という方々はJPAに一声かけるか騒ぐかしてみると良いかと思います。

JPAだけの負担だけでは無くて、参加者の方々からも宿代をカンパしていただく形を取っているので、皆さんに感謝しなければなりません。

所感

想像の通りですが、技術的なトレンドとかは地域のギャップなんかは少なくて、主目的は人と人が顔合わせてわいわい話していける部分が重要だなーとおもいました。
遠距離だからこそ料理屋とかでフリーダムに話すのが大事かなと。
宴会の場でも真面目なディスカッションとかしてたんですが、まー美味しいのを飲み食いして心の壁を無くしておけばいざオンラインとかでガチンコの討論する場面になった時に、遠慮しないで相手の懐に踏み込んだ討論がし易くなるので、そういったのも大事かもなーという

なんか吉岡さんの日記みたいでやになったのでこの辺で割愛。

Fukuoka.PMの全体的な印象は、参加者全員がdankogaiだな。と。
どういう事かというと、皆さんとても良く質問がでる。で、そのままディスカッションに突入する。

斜め上の質問とかもなく的を得たディスカッションになっているので、まるで海外のカンファレンスに来てるかのようでした。
このへんは関東人は真似するべきですね。

まー14時スタートで18時前くらいにおわって、そのまま宴会コースという余裕のありすぎるスケジュールというのも影響してそうですがw
質問のしやすさはカンファレンスのゆったり具合に関係してるかなと思ったのは昨日のshibuya.pmの発表者がshibuya.pmにしては珍しくゆったりしてたというのがヒントになりそうだけど、それは別の話。

プライマリPMはShibuya.PMだと思っていて、セカンダリPMとしては僕はよくYokohama.PMに遊びにいっているのですが、Fukuoka.PMの印象としてはだいぶYokohama.PMよりですね。単純にそれは参加人数が学校のクラスメイトと同等以下の規模感というのと、お互いの参加者同士が何となく皆知り合い感があるからだとおもいます。

前もcanadieさんのOkayama.PM人集まらない問題を書いたけども、規模感と参加者同士の距離感は一つのテーマとしておいておきましょう。

発表資料など

今回の発表は、Web+DB PRESSで連載しているFicia周りのWebUIネタの総編集版とFiciaで気づいたPerl周りの話をしてきました。

Perl周りの話はちょっと古い話題なんですが参考としてどうぞ。

http://yappo.github.com/talks/20101127-fukuoka.pm18-webui/

その他

1次会はもつ鍋を食べていて、遠距離恋愛してる人に言われるまでもつ鍋が博多の名物だとしりませんでした!!!
博多は豚骨ラーメンと高菜と明太子の街だとおもってましたサーセン><

 Ficia Photo

で、ビール飲みながらもつ鍋つついてたんですが、今度は2次会では美味しい焼酎がでるバーに移動して飲み易い焼酎ばっかり飲んでおりました。

 Ficia Photo

で、ホテルのチェックイン時刻を24時に設定してたので、とりあえずチェックインだけしてとんぼ返りで合流して3次会の店へ。
あんまり覚えてないけどわんこそば的に出てくるつけ麺が死ぬ程上手くて無限ラーメンしてました。

で、記憶があやふやなまま26時前にホテルにもどって気づいたらた貴花田親方に激似のおっさんがベットの上で僕の上に乗ってたけど、それは別の話。

で、気づいたら朝10時前で二日酔いでフラフラになりながらホテルから博多駅に行って、地下鉄で呉服町までいって次のルートで博多駅まであるいてきました、


より大きな地図で fukuoka.pm を表示

そして、そのままタクシーで空港まで行って帰宅です。帰りの飛行機で羽田の滑走路が使用禁止になって30分くらい大島の上を旋回したのは良い思いで。

ということで、lestrratさんならびにFukuoka.PMの皆様有り難うございました!本来の目的未達成なのでまた行きます!あとHokkaido.PMでスキーとミョウバンぬきの生ウニ食い放題したいです!

Posted by Yappo at 21:53 | Comments (0) | TrackBack

2010年11月26日

今年も Jperl Advent Calendar の季節になりました。

もう12月まで1週間切っちゃうのでさっさとatnd募集開始しましたよ。


まいどまいどギリギリになってから動き出すんですが、今年は新しく英語でも書いていこう!というトラックも新設されましたね。
今回はさらに25日かけてadvent calendarのシステムも実装していこうという試みも追加されとります。
https://github.com/p5-app-adventcalendar/p5-app-adventcalendar
そしてこのwebアプリはperl 5.14の新機能をふんだんに使った物になる事でしょう。

公開場所はいつも通りのよていで、記事の投稿の仕方はまだ決まってないけど、書きたい事がある人は登録だけしとけば、あとはどうにかなると思います。

今年はadvent calendarのようなものを出版の世界にも持っていったし、良い記事が沢山あつまるので、他の言語や他の業界の人も真似するとよいです!

去年は本編とは別にORMのトラックもありましたが、今年も「Acme Trackやりたい!」「Win32 Track」やりたい!
とかの、特化型のカレンダートラックやりたい人がいれば一緒にやれば良いと思います。
心当たりのある人は、#perl-casual@chant.freenode.net やら twitter あたりで叫びましょう。

個人的には出版関係者トラックとかやってほしいです。

今年はコーヒー一杯でマーケティングしてもらうので、きっと全トラック埋まる事でしょう。

じゃぁはりきってまいりましょう

Posted by Yappo at 13:35 | Comments (0) | TrackBack

2010年11月22日

最新 CPAN モジュールをつぶやく Twitter BOT それAnySanで

ほんっと奇遇なんですけど。ちょうたまたまなんですけど。AnySanにFriendFeed対応した所に。いや本当に偶然なんですけど。

最新 CPAN モジュールをつぶやく Twitter BOT を書いた - punitanのメモっていうエントリを見たので。

ほんと、超偶然なんですけどAnySanでもFriendFeedをリアルタイムで処理出来るようになっちゃってたので、ほんと偶然だけど。
なので、CPAN - FriendFeedからリアルタイムでデータを取ってきてTwitterで呟くbotを書いてみました。

たまたま、AnySan::Provider::Twitterでも、streaming apiを使わないモードとかを実験的に付けたので(偶然ですけど)、無駄なストリーミングAPIの接続もしません。
AnySan使えば、cpan botやりつつperlismてきなボットも1個のプロセスで実現出来そうです。

いや、偶然って恐いですね。


Posted by Yappo at 21:35 | Comments (0) | TrackBack

2010年11月17日

AnySanで日本語の文章をzenrize(全裸化)

日本語の文章をzenrize(全裸化)するAcme::Zenraっていうのを作ったを見たので、折角なのでAnyEvent::IRC::Clientを直で使ってる部分をAnySanで書き換えました。

生で使ってる時と比べると、AnySanを使うとよりbot本体のコードを書くことに注力できる事がわかるとおもいます。(まだまだAnySanでのAPIの洗練は必要だけど)

let's enjoy irc hacking!

Posted by Yappo at 13:11 | Comments (0) | TrackBack

2010年10月20日

YAPC::Asia 2010 を終えて

今年もPerl Monger共の日頃の行いが良いお陰で、天候が悪い中雨は降らずに事故も無く無事に終われてとてもよかった!

YAPCといえばカンファレンスなので講演を聞くだけの会とも思われそうなんですが、YAPCとは国際的なカンファレンスであり日本国内からも遠路はるばる参加している方も沢山います。
って事で、ちょっと座ってるのに疲れちゃったりしたら外に出て知らない人とおしゃべりするのも良いかと思いますね。共通の話題はあるので困る事は無い筈です。

かく言う自分は、二日目とか土曜日だし天気も良い事があって王将でいっぱい餃子買ってきてスーパーでビールしこたま買って餃子カンファレンスしてました。
芝生ではOkayama.PMのcanadieさんと初対面で色々話してたんですが「人が8人しか集まらないのが悩みなんです」って言ってたので「世界中のPerl Mongers見ると多い方だし、活動内容も居酒屋に集まってperlの話してる所いっぱいあるから、なんの問題も無い!むしろOkayama.PMで150人とか集まったら恐いっしょ!なのでマイペースに頑張って下さい!」っていう、ネット越しだと誤解されて炎上しそうなギリギリの話とかも気軽にできたりしました。もちろん酒はいって勢いあるってのもあるけど!

あーあと、芝生以外にも良い場所を見つけて発表前のacotieを捕まえて数千円握らせてビール買ってきてもらって(すっごいキレてたけど)、みんなで飲んでましたね。
acotieの発表後に丁度ビールが切れてたので、また捕まえて買ってきてもらうという(with @sugyan @kyanny)、というお三方はビール買ってきてくれて本当に有り難うございました。とくに刺身さんはビール飲まない人なのに。。。
なんというか、自分の発表が全部終わってフリーダムに無限ビールしてたわけですが、皆さんの感想でもYAPCは祭りだ!って感想が出てる通り祭りを楽しむために延々とみんなにビール渡して盛り上がっとりました。
お祭り騒ぎではあるけども、皆節度守って喧嘩も無く終わられて本当によかったです。

真面目に講演聞きに来た人、真面目に運営してる人に取っては良い迷惑だったかもしれないですが、目くじら立ててる人とかもいなかったっぽいので、こういう物事を本気で楽しめる人達の輪がPerlの魅力なんだと再認識できました。
コードだけではなく人が重要なファクターなんですね。Perlが好きなのはPerlに関わる人込みなんだな。と。

一日目の二次会はdragon3などFukuoka.pmの面々と相席になったくせにグロッキーしててマトモな会話すら出来なくて本当もうしわけ無かったのですが、perlやってればいつかまた合えるので、そんなに気にしない事にしました!
なんかJPA会長が福岡釣れてってくれるフラグ立ててる事ですし!

なんだかんだで嬉しいのは、お前の作ったの使ってるよ!とか言ってくれる事で、@kuzuhaが初日の芝生で使ってるよ!といってくれてました。もちろん初日はグロッキーで(以下略
本編発表後では@monjudohさんが声かけてくれて「連載の最初の話とか良かったよ!」とか言ってくれて嬉しかったですね。とくにWEB+DB PRESSの連載は読んでる人が直接感想を伝えてきてくれる機会がなかなか無いので貴重でした。

そういえば。ごく一部で女性参加者ふやしょう!とかネタで話してた人がいたけど、マジレスするとYAPCが「ガールズ(笑)せっしょん☆」とか「今年のLTからドラ娘がいます!」とかやり出したら参加する気うせるなーと思うしだい。
コードとか書く上で何の訳にもたたない性差を持ち出してうんたらするなんて論理的に考えて意味のない事だし、そんな事で怒るとか青筋の無駄だから、YAPCでは良くわからん事はやらないで欲しいすなーと思っとります。
ちんこついてない人の参加比率が高い所行きたかったり、女としてチヤホヤしてほしいなら合コンでも言ってやがれってこった。「女だから手加減してね☆」とか言う馬鹿は顔も見たくない。※
そのへんは、この界隈の人は良い意味で女の人のエンジニアを特別扱いする事が嫌いな人だらけなので問題無いとおもいますが。

全員の名前を出すと長くなりすぎるので、@941さんそして運営側の皆さん、発表者の皆さん、参加者の皆さん有り難うございました。
そしてすでにhttp://yapc.asia/では来年の計画が動こうとしています。

see you next YAPC

あ、自分の発表について書くの忘れてた。。。

本編の話は、JSTAPdの使い方について話しました。
今まで20分talkばっかりでいっつも時間足りなくて駆け足になってたのを反省して40分にしました。
だいぶ時間が余りそうだからおまけを用意していたんですが、結局おまけなしで40分で終わった感じでした。
誰かが20分とかじゃなくて、せっかくだから40分で応募すべきとか言ってたんですが、すっごい軽い話題でもない限りは40分にしといた方がいいと思った秋。
http://yappo.github.com/talks/20101016-yapcasia2010-jstapd/

AnySanとはAnyEventを使ったメッセージングフレームワークです。
IRC/Twitterを使ったメッセージ系のアプリケンーションを、書くサービスの処理を抽象化して簡単に書くためのフレームワークです。
irc botやらtwitter botなどが簡単にかけます。そしてirc/twitterを組み合わせたbotやら、AnyEvent なので他のネットワーク処理などと組み合わせて夢膨らむ。
http://yappo.github.com/talks/20101015-yapcasia2010-lt/

例えばTwitter IRC Gatewayとかこんなに簡単にかけます。
http://github.com/yappo/p5-AnySan/blob/master/eg/tig-for-anysan.pl
hackathonにて、発表時とちょっと実装変わってしまったんですが、もう少しして落ち着いたらちゃんとアナウンスする予定です。

はっかそんといえば、、、話が長くなるので、hackathonの時の写真込みのアルバムでも見てくださいです。
http://yappo.ficia.com/pl/album/A6E027E6-D9AF-11DF-A14C-378C2C411CC7

じゃ、そういうことでまた!

Posted by Yappo at 02:18 | Comments (0) | TrackBack

2010年10月02日

Shibuya.PM #14 発表資料

Shibuya Perl Mongersテクニカルトーク#14での僕の文の発表資料です。

http://github.com/yappo/shibuyapm-stream
動かすためにはAnySanが必要で、ここから取得出来ます。
http://github.com/yappo/p5-AnySan

当日バグバグだった部分はもろもろ治ってます。

デフォルトではshibuyapmでtwitter searchした結果をストリーミングするんですが、引数を与える事で任意のキーワードでストリーミングできます。

$ perl shibuya-stream.pl perl

背景画像がだいぶグレーな感じなんですが、あそこのプロジェクタの環境でやると、このくらいグレーじゃないと白くなりすぎて文字が見にくくなるんですよね。
IIJのサブスクリーンで出す機会がある人は参考にして下さい。

という事でShibuya.PM #14お疲れさまでした。

Posted by Yappo at 18:01 | Comments (0) | TrackBack

2010年05月02日

osdc.tw 2010 with JSTAPd

報告が遅くなりましたが、OSDC.tw 2010でJSTAPdの発表をしてきました。基本的にスライドは日本語無いですが、本編の方は日本語で発表してきました。やっぱり中文はtypoだらけだったようです。

やっぽてぃ Ficia Photo

一応本編はJSTAPdなんですが、Shibuya.pm in taipeiのラスト発表だったんで、直近のshibuya.pmはperlだけにとらわれない事をやってるよ!的な雰囲気を伝える内容にしました。

http://yappo.github.com/talks/20100424-osdc.tw-2010/

この発表に併せて、JSTAPdももろもろ改善されております。まだCPANの方は古いままですがgithubに上がってる方ではHTTP::EngineからPlack+Twiggyに変更となってます。

既存の仕組みではtestが全て完了されてるかどうかをserverがわに数msec置きに問い合わせまくっているという仕様だったのですが、Twiggyを使ってtestが終了したかどうかを確認するHTTPセッションをlongpollで一つだけ張っておいて、テストが終了しだいresponseを返すという事をするようにしたので余計な負荷をかけないで済んでる感じです。その他のサーバにリクエスト投げつけまくる系の物をlong pollするようにしてあります。

あとは jstapd -n した時に作成されるテストのテンプレートファイルの構造を見直して、デフォルトでは*.t, *.html, *.jsとファイルを別けるようにしてあります。

ちょっと、まだ仕様が変わるかもですが、もうすこし落ち着いてからドキュメントをupdateしてCPANに0.02をあげたいと思ってるところです。

初めて海外で発表するのに、スライド事前準備してないどころか前日に迷子になって深夜徘徊するとかありえないですね!

Posted by Yappo at 10:06 | Comments (0) | TrackBack

2010年03月18日

FiciaがEye-Fiに対応したのでアップロードツール書いてみた

FiciaがEye-Fiからのアップロードに対応したついでに、Eye-Fiからの受け口がGR2プロトコルなんで折角なんでGR2プロトコルしゃべってFiciaにアップロード出来るスクリプト書いてみたよ。

使い方は簡単なんですが、最初にFiciaからEye-Fiアップロード用のトークンを取る必要があるんですが、それは写真アップロードする所

の中に「Eye-Fiでアップロード」ってのが追加されてるので、そこクリックして「次へ」ってやってくと「パスワード」っていうハッシュっぽい文字列が出るので、これをコピーしときます。

そのパスワードをFICIA_EYEFI_PASSWORD環境変数にセットして

$ perl ./ficia-eyefi-uploader.pl アップロードしたい画像ファイル.jpg
ってするとアップロードされるはずです。

一点注意点としては、一度あげたファイルは二度とあげられないくらいです。
この辺は専用クライアントとかだと出来るんですがEye-Fi経由だと出来ないし、そもそもEye-Fiでは二度送信するユースケースが無いのでしょうがないです。
画像削除してもあげられないので注意してください。なんでかっていうといらない写真消したつもりなのにsyncしたら消した画像がまたuploadされてたらイラっとくるでしょ?

この例だと、画像一枚しかあげられないんですが肝心なのはOreOre::FiciaUploadByGR2に処理が入ってるんで、ディレクトリ丸ごとアップロードとか直ぐに作れると思うす。

もっとデーモン的なのがいいよーって人はhirose31さんのdoumekiとか使っとけば良いんじゃないのかなーと思います。

スクリプトは以下の通り。

Posted by Yappo at 14:19 | Comments (0) | TrackBack

2010年03月03日

PHPの関数と同等の実装をPerlでどう書くリファレンスプロジェクト開始のお知らせ

ふとしたきっかけでPHPのリファレンスマニュアルにある関数と同等の機能をPerlで実装するにはどうするか?といったリファレンスを作るプロジェクトを始めました。

PHP使いの人がPerlを弄る時に「PHPのこれPerlでどうやれば良いんだ!」といった要望や、ごく普通のPerl使いの人が「これどうやって書けば良いのかな?」って時に使うcookbook代わりに使える事を想定しています。

ドキュメント管理にはgithubhttp://github.com/yappo/docs-php-funcref-in-perlを使い、ドキュメントのビューワーとしてwikihubWikiHub :: php-funcref-in-perl :: READMEを使っています。

書いて欲しいと思った人にはあらかたコラボレータ入れてるので、ドキュメント充実させたいと思ったらすぐにprivate repoをcloneして書けると思います。「俺入って無いし書きたいよ!」って人が居たら言ってもらえればコラボレータ追加します。
別にforkしてpull requestでもいいんですが、面倒なんでコラボにぶっ込みたい所。

書き方などはREADMEを読んでください。

今のところ書いてる人はPerl側の人間が多いので、もしPHPな人で気になった人が居たら参加してもらったら嬉しいなーとは思う所。なんかそのほうが完成度高くなりそう。

この形に落ち着くまでcodereposにしたりnim+perl-usersとか色々やってたんですが、miyagawa伝説とwikihubでの見た目が奇麗とsyntax highlightした時の組み込み関数にphp.netやperldoc.perl.org等にリンクされて便利ってのがwikihub採用の決め手でした。

とりあえず環境もろもろはいつも通り僕が用意したんですが、4000を越えるPHPの関数群のテンプレートファイルをyusukebeが用意してくれました。

ってことでどうぞよろしくです。

Posted by Yappo at 12:02 | Comments (0) | TrackBack

2010年01月18日

kumofs での Data::Model の使い方

スケート頑張りすぎて足首が痛いYappoですみなさまウインタースポーチュしてますか?

本日kumofsが公開されたので、折角なので Data::Model から kumofs を実際にどうつかっているかを紹介しようかとおもいます。

kumofs については 分散Key-Valueストア「kumofs」を公開しました! - 古橋貞之の日記 を Data::Model::Driver::Memcached については dann さんによる Data::Model::Driver::Memcachedで超効率データ保存 - JPerl Advent Calendar 2009 を別途参照すると良いでしょう。

スキーマ定義

では実際に kumofs をつかった場合のスキーマ定義を下記に貼ります。
ちなみに、それらしいような定義をしてますが全部フィクションです。本当に。

解説 その1

Data::Model::Driver::Memcached のインスタンスを作る所で、 Cache::Memcached::Fast のインスタンスを指定する所で、3つのオプションを渡しています。

一つ目が、 serializer => 'Default', で、 Cache::Memcached 標準の直列化手段をつかわずに Data::Model::Driver::Memcached 標準の直列化手段を利用します。
即ち MessagePack を使った直列化を施します。 Data::Model で必要な MessagePack のコードは Pure Perl で内部的に実装されているのですが、実用的にするには Data::MessagePack をインストールしておくと、そっちを使って高速に直列化してくれます。

二つ目は、strip_keys => 1, です。
通常の方法だと、 primary key も KVS の Value として直列化してストレージに格納しようとするのですが、 KVS だったら既に Key のほうに値が入っているべきで、この重複が無駄なので削除して直列化します。
例えば、上記のコードを使った場合に以下のようなデータ構造だった場合に

{
    file_id    => 'dankogai',
    media_type  => 1,
    client_type => 5,
    is_broken   => undef,
},
file_id の項目を delete して、下記のような構造にしてから直列化します。
{
    media_type  => 1,
    client_type => 5,
    is_broken   => undef,
},

三つ目としては ignore_undef_value です。
これは何をする物かと言うと、カラムの値が undef だった場合は、その項目を DELETE してから直列化します。
そして lookup などで kumofs から Data::Model の Row オブジェクトに戻す時点で、直列化されてるデータにカラムのデータが無ければ value が undef だったと解釈をして復元するのです。
今回の例では、画像が壊れてた時だけ kumofs のストレージサイズが増加します。
上ので書いたデータ例に適用すると下記の用に is_broken が削除されて kumofs に格納されます。

{
    media_type  => 1,
    client_type => 5,
},

ユースケースとしては、稀にフラグを立てる必要があるんだけど、フラグ立って無いレコードに対してもディスク容量を消費するのが嫌だ!という時に使えます。
SQL だと、別途 file_broken 的なテーブルを作って JOIN すれば済む話でしょう。
あいにく kumofs では JOIN 出来ないので、このような時は別の Key-value にデータを突っ込まないといけません。
そうすると GET する時のクエリの数が倍になったりするのでトレードオフしてどっちにするか選ばなきゃいけなくなるんですが、 ignore_undef_value を使っとけば、必要な時に必要なだけストレージを使いつつ GET する時のクエリ数も増えないので良い感じになるんです。

細かいこと言うと SQL で別テーブル使って JOIN するよりかは空間効率やらなんやらは良いと思うすけど。特に比較検証してないんでこれ以上はやめとくす。

解説 その2

今度は model 定義部分をみてみましょう。ポイントは二つあります。

一つ目は schema_options model_name_realname => 'f_m'; です。
これは、 memcached protocol の key の所に入れる model namespace を短縮するのに使います。
例えば key=file_id が 'dankogai' だとして、 schema_options model_name_realname が指定されてない場合は、このコード例では

kumofsfile_meta:dankogai
という key で kumofs に SET します。
そして、今回の例の schema_options model_name_realname を使うと
kumofsf_m:dankogai
と短縮された key になります。

二つ目は schema_options column_name_rename の所です。
これは直列化する直前で Key を任意の値に変換してから直列化をかけます。
Data::Model 標準のシリアライザの MessagePack では、数値をとても効率よく直列化してくれるので、 media_type だとかいう長ったらしい key name を 2 とか言う数値に変換してしまいます。
2 とかという小さい値だと直列化後も1バイトしか容量食わなくて嬉しいんです!

実際、上のほうで書いてるデータ例だと以下の用になります。

{
    2 => 1,
    3 => 5,
},
とんでもなく圧縮出来ている事がお分かり頂けますか。

MessagePack の specをみても解るとおり、15要素以下の HASH に1バイト、 7bit 以下の unsigned int では1バイトの容量しかかからないので、上記の圧縮後の value は5バイトという驚異的なサイズとなって kumofs の value に格納されます。

まとめ

今日は kumofs 公開したということで、 Data::Model からだったらどう使えるか、どう使うかという視点で書いてみました。
Data::Model 側で用意してるオプションを使い切る事により、プログラムコードは書き易く、かつ空間効率を驚異的に高めて利用出来る事が解ったかと思います。
もちろん Data::Model::Driver::Mecached は kumofs 専用という訳でなく Tokyo Tyrant やらなんやらでも利用できますので、機会があればお試しください。

まぁ、もちろんこんなレイヤ介さずに直接使えばいいって話も出てきそうですがね。

あわせて読みたい:YappoLogs: KVSでORマッパーを使うという事

Posted by Yappo at 12:31 | Comments (0) | TrackBack

2010年01月09日

Mooseを使うべきでない理由とMooseを使う理由

twitterにでも書いて終りにしようと思ったけど140文字じゃ無理なんで。
Mooseの欠点やら利点やらMouseがどうだとかは今更感過ぎて割愛するし、下手な抽象的な表現も面倒なんでしない。

Mooseを使うべきでない理由

あなたが、再利用性の高いライブラリを作りたい場合はMooseを使うべきではない。
なぜならMooseはフレームワークだからであるからだ。
たとえ有用な再利用性の高いライブラリを作ったとしても、Mooseというフレームワークに依存してしまっては、あなたの有用なライブラリを選択してもらえない事もあるだろう。
誰かが小さいスクリプトを書くために、あなたが書いた有用なライブラリを使う事で楽が出来るとする、だがMooseというフレームワークに依存したばっかりに、その有用なライブラリの後ろに控えるものの大きさに臆して選択してくれないかもしれない。

もちろんMooseを使わなければ生産性が格段に落ちるだろう。メンテナンスも大変になるだろう。Mooseを使わないことによるペナルティの代わりに誰からも利用されるライブラリの作者になれると言うことだ。素敵だろ。

Mooseを使う理由

じゃぁCPANへ上げるライブラリはMooseを使うなってことか?いいや違う。
何度も言うがMooseは生産性を恐ろしく高める、だがしかし再利用性の高いライブラリでは使うべきでないと言っただけだ。
例えば App::* 名前空間のコードでは積極的に使っても良いだろう、Catalystだってそうだ。
え?Catalystは再利用性の高いライブラリじゃないか!だって?いいや、Catalystはとても有用なフレームワークだ。Catalystの中だけで世界が閉じているのだ。

総論

そう、Mooseを使う場面と使わない場面と言うのは、書こうとしているコードがそのコードの世界で閉じたものなのか、または閉じないものなのか。そういった基準を見るという視点があると良いのではないだろうか。
例えばDBICなんかは閉じた世界でないのでMooseに依存するべきでは無い。
たとえばDBI.pmがMooseに依存してたらどうする?
HTTP::Engineは?うーん微妙だ。
Plack何かは閉じた世界では無いので使うべきでは無い。
じゃぁFeyはどうだ、、、、うーんMooseをたくさん使うという世界に閉じた中で使うと言う点ではありなんじゃないか?

繰り返すがMooseを使わないべきとは言っていない。良く考えて使うべきだと言っているのだ。

Posted by Yappo at 01:07 | Comments (0) | TrackBack

2010年01月05日

Plack::Middleware::Debug のアイコンをどかす Middleware

Plack処女喪失したての金曜日の天使ですおげんきですか。

Plack::Middleware::Debug を使って Debug のメニューを消したときって

みたくなってなんか邪魔なので、端っこにどかすCSSを適用するMiddleware書いてみた。

やりたい事としては、アプリとは関係ないファイルの管理をしないで PM::Debug のcssだけを置換して使いたいって事。
Plack::Middleware::Debug は、必要なjsやらcssをshareディレクトリ以下に入れて自分の好きなように書き換えて使えるんですが、それやるとアプリ以外にファイル管理しなきゃいけないので面倒なのでやりたくないというワケ。

上のコードを app.psgi に入れとくと

な感じになってくれました。
とりあえず目的は達成。

この

builder{
    enable {
        my $app = shift;
        sub { $app->(@_) };
    };
    sub {};
};
するような使い方ってMiddlewareって呼んでもいいものなかしら?
< miyagawa> middleware でいいですよ
との事。

Posted by Yappo at 15:26 | Comments (0) | TrackBack

2009年12月31日

Golang の interface type 風味の duck type する関数を作る Object::InterfaceType っての作った

だいぶ前に作って放置してたんですが、そこそこCPANに上げられる感じにはしてあったので年末の倉庫整理をかねて CPAN にあげました。 http://github.com/yappo/p5-Object-InterfaceType

Goではクラス定義で云々するんじゃなくて、interfaceで定義されてるメソッド群をすべて実装されてたらOKといった感じなんですが、まぁいわゆるduck typingできればおkみたいな感じですね。

Perlの世界では if ($foo->can('bar') && $foo->can('baz')) みたいなコードで duck type可能かを調べるんですが、見た目がごちゃごちゃしがちになるので、Goのinterface type的な感じのものをPerlの世界に持ってきました。

if ($obj->can('read') && $obj->can('seek')  && $obj->can('close')) {
なんてコードを
if ((interface_type [qw/ read seek close /])->($obj)) {
という感じで書き換えられます。

my $is_filehandle = interface_type [qw/ read seek close /];
if ($is_filehandle->($obj)) {
やら
interface_type filehandle =>[qw/ read seek close /];
if (is_filehandle($obj)) {
なんて書き方もできます。

canばっかり呼ばれてるコードって見たこと無いのですが、そういうコードはすっきりとかけるようになるんじゃないでしょうか。

コンセプトは夢の中で思いついて起きて1時間くらいで実装した。

Posted by Yappo at 16:21 | Comments (0) | TrackBack

ajax/javascriptテスト環境の JSTAPd を CPAN にあげました

ちょっと前のacotiethoneの時にlestrrat++さんがドキュメントを英訳してくださったのでCPANにアップロードしました。

http://search.cpan.org/dist/JSTAPd/

それなりに頑張って日本語でもドキュメント書いたので、lestrratさんが気に留めて使う気になって英訳してくださったんだとおもいます。
おかげでCPANへリリースすることもできました。

テストも重要ですがドキュメントも重要ですね。

Posted by Yappo at 16:04 | Comments (0) | TrackBack

2009年12月25日

Module::Requires について hacker track last day を書きました

依存モジュールの管理を実際のコード内で行う為にあったら便利そうなモジュールを思いついたので思いつきのまま CPAN にアップロードして advent calendar に書きました。

http://perl-users.jp/articles/advent-calendar/2009/hacker/25.html

たぶん、 advent calendar で紹介されたモジュールの中で一番新米なんじゃないかと思います。

あとは casual track が完走すれば JPerl Advent Calendar 2009 は全部完走となります。

今から寿司がたのしみです^^

Posted by Yappo at 15:26 | Comments (0) | TrackBack

2009年12月22日

あなたがData::Modelを使う10の理由

前口上

一昨年書いた『あなたがRuby on Railsを使わない10の理由』を書いたら、おおむね好評とともに読んでもらえたみたいで(ほんとかー?)うれしい限り。実際あのあとも記事の影響ってわけじゃないと思うけどRoR使ってくれた人もたくさんいるし、ますます広まってきているみたいでこれも私設営業の人としてはとてもうれしい。


(例によって書きかけなので今後もいろいろ変わったりするかも)

Data::ModelはCPAN Moduleである

まあ上でああいったけどやはりCPAN Moduleであることそのものの価値ということにまずは言及しておく。
いまのPerlはまぎれもないCPAN Moduleベースの言語なのだ。それ自体は実のところ単なる偶然の産物なんだけど。でもさまざまに紆余曲折あってCPAN Moduleベースになったおかげで、Perlが得た恩恵はとても大きい。
Perlはその根幹はCPAN Moduleであるということは、CPAN Moduleの四半世紀の歴史がはぐくんできた膨大な蓄積をPerlも同様に備えているということだ。おかげでプログラマだったらPerlがどんな挙動をするかというのはだいたい想像がつくわけ。

Data::ModelはiPodと相性がいい

この項、あとで書く

いまData::Modelを使い始めると世界で三番目にヘビーなData::Modelユーザになれる

あなたが何かの分野で世界第三位の位置に立つことを考えて欲しい。思った以上に道のりが険しいという事が誰でも想像がつくであろう。
しかし、そんなただの人が世界で三番目の位置に立てる分野がある。そうData::Modelのユーザとしてなら世界第三位のヘビーユーザーになれるチャンスがあるのだ。
現在Data::ModelのヘビーユーザはYappoとtokuhiromしか居ない。ここにあなたの名前が連ねるのだ。
どうだい魅力的ではないか?

え、DBIx::Skinnyがいいって?ありゃ駄目だ。nekokakを始めとしてモバイルファクトリーの全社員が使ってい。あなたはモバイルファクトリーの社員数を数えられるか?
それにyusukebeやnekoyaやnihenやnobuなんとかやmixiの連中まで唾をつけてやがる。
そんな手垢のついたものばっかり使ってるから君は世界三位の位置にいつまでたってもつけないんだよ。

それが、Data::Modelを使えばチャンスが巡ってくる。どうだい?簡単だろう。
それに今ならAdvent Calendar期間中で使い方のドキュメントが揃って来てるしね。
http://perl-users.jp/articles/advent-calendar/2009/data-model/

以下蛇足

この記事を書いている私はもともとCDBIファンだったんだけど、いまのData::Modelは古き良きCDBIが持っていたcultureと、DBICが持っていたcultureの両方を備えたこれ以上はないほど魅力的なORMになっている。ある意味、CDBIよりもCDBIらしいと思う。この業界の先端を走っている人全員ではないけれど、かなり多くの人はData::Modelを使っているし、これからますます増えてくると思う。

Posted by Yappo at 15:54 | Comments (0) | TrackBack

2009年12月21日

JPerl Advent Calendar hacker track で Module::Setup の事書いたよ

ガイアックスさんのご好意で会場提供された hackathone の成果として Module::Setup 0.07 を shipit する事ができたので、当日担当だった Advent Calendar に Module::Setup の紹介と新要素紹介を行いました。
Module::Setup でらくらくモジュール作成 - JPerl Advent Calendar 2009

実に14月ぶりくらいのメジャーリリースで、様々な機能が追加されています。
おもに flavor 開発者にとって便利な物が大量投入されてます。

他にも Ark などの helper script をより便利に作れる Helper support 機能が投入されてます。


一般向けとしては XS flavor が追加されており、多分 id:gfx がよりモダンな flavor にしてくれることでしょう。

そしてようやく GitHub flavor も投入されました。スケルトン作るときに GitHub のリポジトリセットしたり git remote の設定を自動でやってくれたりします。
お望みとあれば、出来立てのスケルトンをそのまま git push してくれますがそんな変態はいないでしょうか。

ということで Module::Setup をご利用ください。

ガイアックス++

# 最初は本気で東小金井に行きかけたのはないしょのつぼみ

Posted by Yappo at 12:48 | Comments (0) | TrackBack

2009年12月15日

goo.gl の API を叩いて goo.gl のショートURLを作る WWW::Shorten::Google ってモジュールかいた

http://goo.gl/ ってのが巷では始まっていますが、まだ勝手に tinyurl を作れないようなので
簡単に http://goo.gl/hoge な tinyurl を作る WWW::Shorten::Google ってモジュールを書きました。

http://github.com/yappo/p5-WWW-Shorten-Google

CPAN には、各種 tinyurl を使って url を短くするための統一インタフェイスとして WWW::Shorten ってのがあるので、それの流儀にしたがって作りました。

Posted by Yappo at 19:54 | Comments (0) | TrackBack

2009年12月02日

JPerl Advent Calendar 2009 はじまりました

という事で始まりました。
http://perl-users.jp/articles/advent-calendar/2009/
gfxさんがまとめてくれたPerl界隈のAdvent Calendarの便利リンク集も有るので便利です!

今回はトラックが二つに別れた事の他にDBIx::SkinnyとData::Modelのトラックが出来てるのに気づくかと思います。
これは、本来予定されていたものでは無くて、今回のJPerl Advent Calendar 2009は結構便利に書ける仕組みだったので、便乗して開始したといういきさつです。
Advent Calendar書く為の準備をする必要が特にないので参入障壁が低いと言う事ですね。

何が言いたいかというと、もし何かのテーマでPerl Advent Calendarをやってみたい!って人は気軽に始めると良いですよ。という事。

$ git clone http://git.coderepos.org/share/websites/jperl-advent-calendar-2009.git/
$ cd jperl-advent-calendar-2009
$ cp -r data/data-model data/anatano-track
# data/anatano-track の中のファイルを諸々書き換える
# s/data-model/anatano-track/ みたいな事とか
# trackの名前変えたりとか
$ $EDITOR data/anatano-track/\d+.txt して、内容書く
$ git add data/anatano-track
# 必要だったら .nim とか data/index.html とか data/base.html も追加しとくと良いよ
$ git push

こんだけで http://perl-users.jp/articles/advent-calendar/2009/anatano-track/ が出来るんで楽ですね!

その他

本当は今回GitHub Pagesを使うとかいう話があったんですが、コラボレータ追加作業が面倒という事で特に手間がないCodeRepos使うと言う話になった。
あとnimいいですね、全トラックのRSSをまとめたRSSとか作るのもPlagger使わないでnimだけで作れる。

Posted by Yappo at 12:44 | Comments (0) | TrackBack

Data::Model Advent Calendar

YAPC 2009 (Yet Anther jPerl advent Calendar 2009) という事で、Data::Mode用のトラックを作りました。

http://perl-users.jp/articles/advent-calendar/2009/data-model/

あまりにも文書としてまとまってない Data::Model のドキュメントを増やすチャンスですね!
ちなみに全部書ききったら、別途kanさんに寿司奢ってもらうつもりです。

Posted by Yappo at 12:14 | Comments (0) | TrackBack

2009年10月29日

Ajax アプリ等の為の JavaScript コードのテストツール JSTAPd を作ってるよ

Data::ObjectDriverをDISってる人の話題が三周目に突入した今日この頃ですが皆さんは何をDISってますか?Yappoです。

JavaScript にもテストツールが色々とあると思うんですが、 Ajax アプリの XHR リクエストとかも含めてラクチンにテストできるツールが見つからなかったので JSTAPd というツールを作りました。

http://github.com/yappo/JSTAPd

名前の通りテスト結果はTAPで出力してるのでproveコマンドとかを使ってPerlの作法でテストできます。
ブラウザの連携の設定をすれば prove -v foo/hoge.t とかをコマンドで打ち込めば勝手にブラウザ立ち上げてテストコード実行してブラウザ閉じて結果をコンソールに吐いてくれます。
もちろんデーモンとして常駐化できるので複数のOS&ブラウザを使って自動的にテストするなんて構成も取れるでしょう。

1テスト1ファイルにまとめて書く事が出来て、実際にテストに関係するJavaScript, HTML, Server APIのコードを書くだけですむようになっています。
JSコードのテストを細かくサクサク量産できる事を目標にしてます。

文章で説明を呼んでもいまいちピンと来ないと思いますので、実際にJSTAPdを使っている所のデモンストレーション動画を撮ったのでご覧下さい。

あと、日本語でチュートリアルも作ったので細かい内容についてはそっちを参照してください。
http://yappo.github.com/JSTAPd/tutorial/ja.html

文法エラーとか補足しきれなかったりまだまだ細かい所がかゆいんですが徐々にまともにしてくつもりなので乞うご期待。

Posted by Yappo at 17:02 | Comments (0) | TrackBack

2009年10月20日

Makefile polyglot (make And perl Makefile)

Careless you doing "perl Makefile", then you take many error messages.
Your trouble will be solved if the polyglot technology is used.

# Example Makefile
irst_labe: length
X;$Y=Z;
dummy_label: length
        0;
        print "perl world\n";
        $x = <<'END_OF_MAKEFILE='
length:
        echo "make world"

END_OF_MAKEFILE=
actually, this code is works on perl and make command.
$ perl Makefile 
perl world
$ make
echo "make world"
make world

Makefile is processible into Makefile.PL polyglot by perl code shown below.

perl Makefile.PLをperl Makefileと打ち込まんでエラーメッセージを出しちゃうドジっ娘さんは沢山いらっしゃるとおもいます。
そんな悩みを解決すべくperl Makefileと打ち込んでもexec $^X, 'Makefile.PL'を実行してくれるMakefileのsnipetを作りました。

規則名をlabelとして扱わせて、その次にperlの構文のlengthをぶち込み、セミコロン必要な所は何故かGNU makeでX;$Y=Z;が通ったので、それでごまかしてlengthの規則名を定義してmakeで実行させる規則を作りつつ。perlで実行された時にはlengthの規則の定義部分は$xにぶち込まれるようにしてあるという具合です。(説明めんどう

ExtUtils::MakeMakerにパッチあてれば良い感じになりますか?

GNU Make 3.81 で確認済み

thanks to tokuhirom and takesako

Posted by Yappo at 14:27 | Comments (0) | TrackBack

2009年10月16日

AUTOLOAD is so crazy

it is useful to what? i don't know.

my $path = 'foo/bar/baz'; Class->$path
とかAUTOLOADで普通に受け取れたから、オブジェクトも送れるんじゃないかと思って書いてみた。反省しない。

Posted by Yappo at 17:31 | Comments (0) | TrackBack

2009年10月15日

HTTP::Engine 0.03001 has streaming response now / multipart/mixedなストリームをHTTP::Engine/Plackでpushする

thanks many ideas from yusukebe, mattn, miyagawa.
I created a streaming response support for HTTP::Engine. it was a too easy hack.
example here

[ゆ]: multipart/mixedなストリームをPlack/PSGIでpushする みて、HTTP::Engineの上で動くかと思ったけど全然動かなかったので、HTTP::Engine側で対応して動くようにしました。
http://github.com/yappo/fast-twitter-stream

IO::Handle::Utilで作った$fhをHTTP::Engine::Response->new( body => io_from_getline sub {} )しただけだと、Content-Lengthが無いとエラーになってしまってbackend interfaceに渡せなかったんですね。
なんで、PSGIみたくバックエンド側でストリーミング的なコンテンツが扱えるinterfaceの時はContent-Length無しでも通るようにしました。

で、出来たのが以下のコードです。オリジナルと殆ど同じです。

use strict;
use warnings;

package FastTwitterStream;
use Coro;
use Coro::Channel;
use Coro::AnyEvent;
use AnyEvent::Twitter::Stream;
use HTTP::Engine::Response;
use IO::Handle::Util qw(io_from_getline);
use Encode;

my $username = $ENV{TWITTER_USERNAME};
my $password = $ENV{TWITTER_PASSWORD};
my $boundary = '|||';

my $streamer;
my %queue;
my $count = 0;
sub request_handler {
    my $req = shift;

    if ( $req->path eq '/push' ) {
        my $now = ++$count;
        $queue{$count} = Coro::Channel->new;
        $streamer ||= AnyEvent::Twitter::Stream->new(
            username => $username,
            password => $password,
            method   => 'filter',
            track => 'twitter',
            on_tweet => sub {
                $_->put(@_) for values %queue;
            },
        );
        my $body = io_from_getline sub {
            my $tweet = $queue{$now}->get;
            if( $tweet->{text} ){
                return "--$boundary¥nContent-Type: text/html¥n" .
                    Encode::encode_utf8( $tweet->{text} );
            }else{
                return '';
            }
        };

        return HTTP::Engine::Response->new(
            headers => {
                'Content-Type' => qq{multipart/mixed; boundary="$boundary"},
            },
            body => $body,
        );
    }
    if ( $req->path eq '/' ) {
        return HTTP::Engine::Response->new( body => html() );
    }
};

sub html {
    my $html = <<'HTML';
<html><head>
<title>Server Push</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/DUI.js"></script>
<script type="text/javascript" src="/js/Stream.js"></script>
<script type="text/javascript">
$(function() {
var s = new DUI.Stream();
s.listen('text/html', function(payload) {
$('#content').prepend('<p>' + payload + '</p>');
});
s.load('/push');
});
</script>
</head>
<body>
<h1>Server Push</h1>
<div id="content"></div>
</body>
</html>
HTML
    return $html;
}

package main;
use HTTP::Engine;
use Plack::Builder;

my $engine; $engine = HTTP::Engine->new(
    interface => {
        module => 'PSGI',
        request_handler => ¥&FastTwitterStream::request_handler,
    },
);

builder {
    enable "Plack::Middleware::Static",
        path => qr{¥.(?:png|jpg|gif|css|txt|js)$},
            root => './static/';
    sub { $engine->run(@_) };
};

ブラウザから"http://localhost:8080/"にアクセスすると、もの凄い勢いでつぶやきが追加されていくのが分かるかと思います。しかも切断していないのでかなり高速です。

お試しの効果には個人差があります。

multipart/mixedとこのDiggライブラリの組み合わせ、いいですね。というわけで、元ネタになったyusukebeさん、Plackでpush配信の仕方を教えてくれたmiyagawaさんありがとうございました。
Enjoy!

Posted by Yappo at 13:20 | Comments (0) | TrackBack

2009年10月13日

HTTP::Engine meets PSGI

I shipped HTTP::Engine 0.03. Interface::PSGI is enclosed from this time.
async server became easy by PSGI.

use strict;
use warnings;

use HTTP::Engine;
use Plack::Loader;

my $he1    = HTTP::Engine->new(
    interface => {
        module => 'PSGI',
        request_handler => sub {
            HTTP::Engine::Response->new( body => 'plack 1' );
        },
    },
);
my $he2    = HTTP::Engine->new(
    interface => {
        module => 'PSGI',
        request_handler => sub {
            HTTP::Engine::Response->new( body => 'plach 2' );
        },
    },
);

Plack::Loader->load('AnyEvent', port => 18081)->register_service(sub { $he1->run(@_) });
Plack::Loader->load('AnyEvent', port => 18082)->register_service(sub { $he2->run(@_) });
AnyEvent->condvar->recv;


Enjoy!

Interface::PSGI を同梱した HTTP::Engine 0.03 をリリースしました。
思う所があって、PSGI対応周り以外にももすこし機能追加しようかなという気分になってきました。

Posted by Yappo at 18:44 | Comments (0) | TrackBack

2009年10月09日

HTTP::Request::StreamingUpload - 省メモリでrequest bodyをupload

Today I created a good wrapper for request body upload HTTP::Request.
this module is use few memory on file upload. also too big file.

http://search.cpan.org/dist/HTTP-Request-StreamingUpload/
http://github.com/yappo/p5-HTTP-Request-StreamingUpload

DESCRIPTION

HTTP::Request::StreamingUpload is streaming upload wrapper for HTTP::Request. It could be alike when $DYNAMIC_FILE_UPLOAD of HTTP::Request::Common was used. However, it is works only for POST method with form-data. HTTP::Request::StreamingUpload works on the all HTTP methods. Of course, you can big file upload using few memory by this wrapper.
SYNOPSIS
  my $req = HTTP::Request::StreamingUpload->new(
      PUT     => 'http://example.com/foo.cgi',
      path    => '/your/upload.jpg',
      headers => HTTP::Headers->new(
          'Content-Type'   => 'image/jpeg',
          'Content-Length' => -s '/your/upload.jpg',
      ),
  );
  my $res = LWP::UserAgent->new->request($req);

LWPとか使って大きなファイルアップロードするときは$HTTP::Request::Common::DYNAMIC_FILE_UPLOAD使ってアップロードするとメモリに優しくアップロードできるってのは有名ですが、あれってform-dataの時しかやってくれないので、例えばPUTメソッドでデッカいファイル送りたい時には使えません。

HTTP::Request->new( PUT => $uri, $headers, sub { read $fh, my $buf, 1978; $buf } )
とか書けば出来るんですが、毎回書くのもうっとおしいので、同じ事を
HTTP::Request::StreamingUpload->new( PUT => $uri, headers => $headers, fh => $fh )
で出来るようにしたんです。

Content-Length を入れない場合は LWP::UserAgent の中で使ってる LWP::Protocol::http が chunked で送ってくれるので、予め送りたいサイズが解らない場合でも安心して使えます。

Posted by Yappo at 12:45 | Comments (0) | TrackBack

2009年10月07日

PSGI Implのsendfileについて

PSGIなServerはsendfileを扱う時にどうするかのメモ。

  • $env->{'psgix.sendfile'}がセットされてれば、そこに書いてあるファイルパスを使う
  • $res->[2]がGLOBだったら fileno($res->[2])して sendfile に fd を渡す
  • $res->[2]->can('fileno') が生えてたら、$res->[2]->filenoからfdを取って使う
  • $res->[2]->can('path') が生えてたら、$res->[2]->pathからファイルパスを取って使う

以上が、基本的なsendfileを使を行うときのパターンになる。
また、response headerにX-Sendfileなどの任意のヘッダが入っていて、その中にファイルパスが入っていれば、そのファイルパスを元にしてsendfileするのはServer実装者の自由である。
が、アプリの設定したヘッダはむやみに弄るべきではないので、後述するMiddleware等が設定したpsgix.sendfileを使うべき。だし、そもそも->pathとかをduck typeして取った方が奇麗だ。
というか、好き勝手にやればよい。と言うのがだいたいのsendfile扱うときの定石かな。

多分psgix.sendfileを最優先に使えば良いと思うけど。
たぶんMiddlewareがX-Sendfileなどをpsgix.sendfileに突っ込む等の方向性になるんじゃないか、まだ良くわかんない。

nginx embed perl は、今のところ $r->sendfile($path) しか提供されてなんだけど$r->sendfile_by_fd($res->[2]->fileno)とか出来るようにするつもりです。

Posted by Yappo at 12:31 | Comments (0) | TrackBack

2009年09月25日

AnyEvent で plagger-ircbot 的なのかいた

AneEvent二日目なので plagger irc bot的に使えるのを書いてみた。
http://github.com/yappo/perl-anyevent-irc-message-proxy

POEってのはIKCっていう便利なRPC的に便利に使えるのが有るんですが、まぁplagger irc bot的なのにはそんな大げさの物も要らないので、jsonでデータ送ったらその中身をirc serverにNOTICEで出してくれるのを書いてみた。
そもそもjsonにしなくても良いんだけど、jsonの中に発言したいchannelとか指定出来るように拡張する時とかのためですね。

このくらいだと別に直でAnyEventのコード書いても良い感じすなー
plaggerのそれとはコードも比べ物にならない程適当なんですが、似たような処理をAnyEventで書くとこんなにすっきりするんだなぁ。と思いましたですね。ハイ

Posted by Yappo at 20:57 | Comments (0) | TrackBack

AnyEvent はじめ

そろそろAnyEventでもやってみようと思ったので

AntEvent::Handle

いわゆるIOまわりの面倒を色々便利にやってくれる君。イベントベースなIOと言うよりかはevent queueなIOみたいな捉え方するとすんなり。
read/writeの処理はqueue的な感じで登録できるの。
->push_read() で、どんどんqueueにreadイベントを登録してく。fhがreadableになったらread queueがどんどん処理されるってわけ。
->unshift_read() だと、queueの先頭に突っ込んでく。
そう、まさしくperlのarrayへのpush/unshiftそのもの。AnyEvent::Introを読むとその辺の命名に関する思いが読める。
->push_write() だと、writeイベントを登録してく。writeできるようになるとどんどんfhにデータが送られる。
もしかしたらこれの対としてunshift_writeが出来るとか出来ないとか。

eventベースなのでpush_readとかしてもfhの都合考えないですぐにレスポンスが帰ってくる。
もしエラーとかタイムアウトをハンドリングしたければon_timeoutやらon_errorなどにハンドラ渡せ。

->on_drain() なんてのもある、排水溝。write bufferが空っぽになったら呼び出されるの。
空っぽの排水溝に汚物という名のdataをpush_writeしまくるか、汚物が無くなったらpush_shutdownしてsocketという排水溝を閉じてしまうかは好きにすれば良い。

こんだけ解ってればPlack::Impl::AnyEvent読むのは苦労しないよ。

つづく

Posted by Yappo at 03:49 | Comments (0) | TrackBack

2009年09月11日

YAPC::Asia 2009 発表資料など

まだ終わってないですが発表資料等。

1日目の Data::Model の資料は
http://yappo.ficia.com/pl/album/1E8DF4EE-9DB6-11DE-B1EE-7BD1A805B909

2日目の LT nginx に突いての資料は
http://yappo.ficia.com/pl/album/9509705E-9EAA-11DE-ADEA-3624873069EA

一応テキスト版を置いてあります。
http://github.com/yappo/talk-yapcasia2009/tree/master

なお LT で発表した nginx with memcached は
http://github.com/yappo/ngninx-ngx_http_memcachep_module/tree/master
にて。

Plack::Impl::Nginx に関しては
http://github.com/yappo/p5-Plack-Impl-Nginx/tree/master
nginx 本体にパッチいります


Yet Another Another Conference として、東工大の中の芝生で
1日目: MySQLカンファレンス
2日目: 画像配信サービスカンファレンス
が開催されました。
特に2日目は、無茶な呼び出しにも関わらずお集りいただきありがとうございました。


詳しい事は後で書く予定かも。。。。


写真等は
前夜祭http://yappo.ficia.com/pl/album/71902ED4-9D5F-11DE-AC2C-90D36E373816
1日目http://yappo.ficia.com/pl/album/BD7137E4-9DF0-11DE-8BEA-3624873069EA
2日目http://yappo.ficia.com/pl/album/850F7D50-9EAB-11DE-8946-7BD1A805B909
でみれます。

ハッカソンが終わって家に帰るまでYAPCなので、まだまだこれから。。。

Posted by Yappo at 18:16 | Comments (0) | TrackBack

2009年09月08日

PSGIの簡易ランチャー作ったよ

HTTP::Engineは、ちょっとした一枚スクリプトをサーバ化する便利な利用方法がありますが、それをPSGI実装向けにやってくれるアプリを昨日の帰りの電車の中で書きました。
http://github.com/yappo/App-Ksk/tree/master

使い方は簡単で、下記のようなスクリプトを書いて

package KskExample::Sample1;
use strict;
use warnings;

sub handler {
    my($class, $ksk, $req) = @_;

    my $body = qq{
<h1>Welcome To Ksk World.</h1>

you request uri is @{ [ $req->uri ] }.<br />
};
    my $res = $ksk->psgi_response_class->new({ status => 200, body => $body });
    $res->header( 'content-type' => 'text/html' );
    $res;
}

1;
$ ksk.pl scriptname.pl
の用に起動すると、サーバが上がるという物です。
デフォルトでPlack::Impl::ServerSimple で 8081 ポートで上がります。

もちろんPSGI実装は差し替え可能で次の用にするとAnyEventを使ってサーバを上げます。

package KskExample::AnyEvent;
use strict;
use warnings;

use Plack::Impl::AnyEvent;

sub ksk_init {
    +{
        psgi_setup => sub {
            my $handler = shift;

            my $ae1 = Plack::Impl::AnyEvent->new(port => 18081);
            $ae1->psgi_app($handler);
            $ae1->run;

            my $ae2 = Plack::Impl::AnyEvent->new(port => 18082);
            $ae2->psgi_app($handler);
            $ae2->run;
        },
        run_finalizer => sub {
            AnyEvent->condvar->recv;
        },
    };
}

sub handler {
    my($class, $ksk, $req) = @_;

    my $body = qq{
<h1>Welcome To Ksk World.</h1>

you request uri is @{ [ $req->uri ] }.<br />
};
    my $res = $ksk->psgi_response_class->new({ status => 200, body => $body });
    $res->header( 'content-type' => 'text/html' );
    $res;
}

1;
PSGI実装の入れ替え可能という事は別にPlackなんか使いたく無いぜ!派の人も psgi_setup をちゃんと書けば実装の選択は可能です。

ちなみにrequest classとしてPlack::Requestを、response は Plack::Response を使っていますが、これも差し替え可能で

Another::Request->new($env);
my $psgi_res = Another::Response->finalize;
という感じのインターフェィス要件を満たしてくれる、他のPSGI対応Req/Resクラスに差し替える事も可能です。

ついでにハンドラー周りのクラスも差し替えられるけどオマケです。

という事で快適なPSGIライフをお過ごしください。

Posted by Yappo at 11:29 | Comments (0) | TrackBack

2009年09月07日

とりあえず

PSGI自体がまだまだ流動的なので、落ち着くまでHTTP::Engine::Interface::PSGIを作ってお茶を濁す事にするよ。

PlackX::Request も HTTP::Engine のそれとは大きく違う感じになったし、そもそもMoose/Mouse/Any::Moose使わなくしちゃったし。

なんか流れ的にもHTTP::Engineはもう使わないでPSGI実装とかを使う流れにもなりそうなんで、あんまやりすぎても無駄な感じだから静観する方向で。

Posted by Yappo at 13:21 | Comments (0) | TrackBack

2009年09月06日

HTTP::Enginについて

昨日のHTTP::Engineは死なないよってのは間違いじゃないけど、プロジェクト的には老後生活に入る方向になってました。
仕様は PSGI になり、 Interface 実装は PSGI 実装に、 Request の実装は PlackX::Request に移る方向性っぽいです。

具体的に言うと PSGI の実装を Interface レイヤで使って、Request部分を PlackX::Request を使うラッパーという形になります。

本来の HTTP::Engine も Interface の部分からデータを受け取って Request オブジェクトを作って、アプリケーションのコールバックを呼んで
アプリケーションから帰って来たResponseオブジェクトを受け取って、それをWebサーバに戻すんですが、これをこれから

PSGI実装からPSIGプロトコルのデータ受け取って、 PlackX::Request を extends した HTTP::Engine::Request でくるんでアプリケーションに渡して、アプリケーションは HTTP::Engine::Response で返すんで、それを PSGIプロトコルに変換してPSGI実装に返す感じになります。

本来のHTTP::Engineのコアとやる事はあまり変わり無いです。

PlackX::Request は、すでに HTTP::Engine を元にして作ってあります。
http://github.com/yappo/p5-PlackX-Request/tree/master

で、PSGIは仕様の名前であって実装は別になるので、エンドユーザはPSGI実装を自由に選ぶ感じになります。
最初の内はPlackを使って行く予定です。

Posted by Yappo at 12:24 | Comments (0) | TrackBack

2009年09月05日

HTTP::EngineとPSGI - HTTP::Engine is died?

HTTP::Engine は元々
・各種Webサーバに依存した処理がWAF毎に分散してるのをまとめたい!
・Request/Responseも共通化したい!
という所からスタートしたプロジェクトな訳ですが、今回PSGIが始まる事によって前段の部分をPSGIに委譲して、Req/Resの共通化は今まで通りありますよと言う話。

今回のPSGIは「HTTP::EngineのInterfaceのレイヤとReq/Resのレイヤが絡み付いてて良く無いんで、良い感じに分離したいよね」という所から始まった感じ。

結局はPSGIは仕様なので、それを実装するのはHTTP::Engineの内部になるかもしくはRack的な物を外に作ってやるかという事になるけど(後者の方向)、HTTP::Engineの内部でPSGIと既存のRequest/Response/handlerの吸収を行うので、利用者側からしたら意識する必要は無いです。


なにが良くなるかというとHTTP::Engineのデペロッパにとってのコードの見通しが良くなるのと、真の意味でのWSGIをPerlが手に入れるという事ですね。

利用者側の視点では、HTTP::EngineがPSGIの実装を選べると言うのも選択肢が広がって良いのではないでしょうか。
例えばmod_psgiとかいうapacheモジュールが出たとしたら、HTTP::Engineが直接mod_psgiと繋げるなんて事が出来る訳ですね。mod_perl強すぎで必要性あんま無いけど。

既存のHTTP::Engineを受け入れにくいプロジェクトでも、良さげなPSGI実装の上でアプリを書けるので嬉しい事も多いでしょう。


ここまで読んで頂ければ解りますが、表題の答えは No ですね。

Posted by Yappo at 18:30 | Comments (0) | TrackBack

2009年08月24日

HTTP::Engine は国産か否か

最近「国産のHTTP::Engine」のような文章を立て続けに見たので、HTTP::Engineは国産なのかどうかを考えてみたけどやっぱり国産じゃないんですよね。
そりゃディストリ作り出してメンテやりだしたのは日本人だけども、コードベースはCatalystだしMoose化の際にはnothingmuchの多大なる貢献があったし、大元のアイデアはPythonからの物だしで、そんなに国産と言う思いは無かったり。

だってさ、Pugsが台湾産だなんて言いかた聞かないでしょ?強いて言えばPerlコミュニティ産ってのがしっくりくるなという感じ。

中の人が日本語ばっかり使うから日本人が使うには気軽で良いという点くらいしかないんだけど、それって全体で見ると利点でなくて英語の情報が余りにも少なすぎてあんま良く無いなと思ってる所なんだけど、日本語ですらドキュメント書けてない困ったちゃん状態。

Ruby(以下省略

Posted by Yappo at 11:27 | Comments (0) | TrackBack

2009年08月14日

iPhotoは取り込んだ写真にExif追加します

eyefiで上げまくる生活をした後にiPhotoに残ってる古い写真も上げようと思ったらeyefiで上げ済みの写真も上がっててバビった今日この頃皆様いかがお過ごしでしょうか。

iPhotoに取り込まれた写真はExif情報を追加するといったことが一般的に知られていますが、実際にどんなデータが追加されてるかを見てみました。

材料:iPhoto通してない写真 1枚
iPhoto通した同じ写真 1枚
下記のスクリプト

use strict;
use warnings;
use Image::ExifTool ':Public';

my $eyefi  = ImageInfo(shift);
my $iphoto = ImageInfo(shift);

while (my($k, $v) = each %{ $eyefi }) {
    my $iphoto_v = delete $iphoto->{$k};
    my $is_changed = 0;
    if (ref($v) eq 'SCALAR') {
        if (ref($iphoto_v) eq 'SCALAR') {
            $is_changed = 1 unless $$v eq $$iphoto_v;
        } else {
            $is_changed = 1;
        }
    } elsif ($v ne $iphoto_v) {
        $is_changed = 1;
    }
    next unless $is_changed;

    printf "key: %s¥n  eyefi: %s¥n iphoto: %s¥n", $k, $v, $iphoto_v;
}

print "¥niPhoto's append data¥n";
while (my($k, $v) = each %{ $iphoto }) {
    printf " %s => %s¥n", $k, $v;
}

さぁ実行しましょう

key: FileName
  eyefi: eKHPjLGE3hGDx7EShzBp6g.jpg
 iphoto: DLQpgnuI3hGrj3qvqAW5CQ.jpg
key: FileModifyDate
  eyefi: 2009:08:09 15:54:57+09:00
 iphoto: 2009:08:14 11:38:11+09:00

iPhoto's append data
 CMMFlags => Not Embedded, Independent
 ConnectionSpaceIlluminant => 0.9642 1 0.82491
 ProfileCMMType => appl
 ProfileDescription => Camera RGB Profile
 ProfileID => 0
 DeviceModel => 
 GreenMatrixColumn => 0.35332 0.67441 0.09042
 ChromaticAdaptation => 1.04788 0.02292 -0.0502 0.02957 0.99049 -0.01706 -0.00923 0.01508 0.75165
 BlueTRC => SCALAR(0x8356ec)
 RedTRC => SCALAR(0x8d5f84)
 ProfileClass => Input Device Profile
 BlueMatrixColumn => 0.15662 0.08336 0.71953
 PrimaryPlatform => Apple Computer Inc.
 RedMatrixColumn => 0.45427 0.24263 0.01482
 ProfileDescriptionML => Camera RGB Profile
 ProfileVersion => 2.2.0
 RenderingIntent => Perceptual
 ProfileCreator => appl
 ProfileFileSignature => acsp
 DeviceManufacturer => appl
 ProfileCopyright => Copyright 2003 Apple Computer Inc., all rights reserved.
 ProfileDateTime => 2003:07:01 00:00:00
 GreenTRC => SCALAR(0x8d60c8)
 DeviceAttributes => Reflective, Glossy, Positive, Color
 ColorSpaceData => RGB 
 MediaWhitePoint => 0.95047 1 1.0891
 ProfileConnectionSpace => XYZ 
ファイル名が違うのはImage::ExifToolの都合ですが、最終変更日が変更されてプロファイルやら何やらが追加されましたね。

メタデータ変わったら違う画像になるのか、それとも画像自体が同じなら同じファイルなのかとかそういう話もありますが今日はこの辺で。

ちなみに元画像はここから落とせます

Posted by Yappo at 12:22 | Comments (0) | TrackBack

2009年08月07日

YAPC::Asia 2009 で「Key Value Store と ORM」について話します

このところ、MySQL と KVS と ORM 関連のエントリをいろいろ書いていますが、それは、スケールアウト可能で、かつ、インフラの人に怒られないアプリケーションを、今まさに作っている、という理由があるからです。

ただ、ブログエントリだとどうしても細切れになるので、一連のモジュールやプログラムを組み合わせて、どうやってスケールするインフラと繋げる部分を作るのかという話を YAPC::Asia 2009 でさせていただくことにしました。

YAPC::Asia 2009 は9月10日(木)と11日(金)の2日間、東京工業大学大岡山キャンパスで開催されます。今日からチケット販売も始まったので、興味のある方はお越しいただければ、と思います。

YAPC::Asia 2009
Key Value Store with O/R Mapper: YAPC::Asia 2009 - Sep 10-11 in Tokyo, JAPAN

【参考文献】
http://d.hatena.ne.jp/hirose31/20090807/1249611130

Posted by Yappo at 11:18 | Comments (0) | TrackBack

2009年07月24日

Data::Model with mysql's reconnection

DBD::mysql は mysqld との接続が切れたら自動的に繋ぎ直す機能があるのですが、 Data::Model の reuse_dbh 機能を作るにあたりとてもはまりました。というようなエントリの建設予定地です。

Posted by Yappo at 21:08 | Comments (0) | TrackBack

2009年07月14日

Tasks for my cpan module projects

The task which I have about cpan modules is as follows

HTTP::Engine
HTTP::Engine::Interface::AnyEvent is taken in. created by miyagawa.
async support for HTTP::Engine::Interface::POE. patches by miyagawa.
Data::Model
add Driver::PostgreSQL. patches by sfujiwara.
few relationship support.
Module::Setup
release to 0.07

The project into which I am putting power now.

Posted by Yappo at 14:24 | Comments (0) | TrackBack

2009年07月05日

KVSでORマッパーを使うという事

ケイレキ.jpの中でケイレキ.jpに招待して欲しい人を呼びかけても絶賛スルーされてるYappoです。さて今回は今巷で大人気のKey Value StorageでORマッパーを使う事についてお話するのじゃ。

一般的にORマッパーとはオブジェクトとリレーショナルデータベースをマッピングする為の仕組みの呼び名だと言うのは知られている所です。はい、そうするとKVSってのはハッシュデータベースであるわけなのでおかしいですね。今回の話はData::Model::Driver::Memcachedを使う事を前提としてるので問題が無いのです。なぜなら「data/object mapper」とか書いてあるから。

いわゆるPerlなORマッパーってのは行データをHASHで管理します。それはRDBが一般的に表形式でデータを管理しているからなんだと思います。なんでKVSをオブジェクトにマッピングするなら他の方法でも良いかもしれませんが、Data::Modelは異種ストレージでも同じインターフェィスで使えるようにする。例えば最初はSQLiteで動かすけどあとあとTokyoTyrantに乗せ替えるみたいな事をやる時にアプリケーションをほぼ変更無しで乗せ替えを可能にするといった事を考えて作ってあります。
厳密に言うとwhereとかindexとか使うクエリ使ってしまったら今のところ駄目ですけども。。。

本題に入るけども、先ほどリリースしたData::ModelからDriver::Memcachedを大幅に強化して各種KVSへデータを保存するのに有利な仕組みをいくつか追加しました。Driver::Memcachedはmemcached protocolに対応したサーバもしくは、Cache::Memcachedと互換なインターフェィスをストレージとして利用します。素のmemcached以外の物で使ってもらう事を考えてますが、データの生存期間に合わせてそのへんは選べば良いと思います。僕も特定のデータだったらmemcachedの方に突っ込んでるし。

テーブル名変換

Data::Modelはmemcachedのkeyにテーブルを含めます。
またinstall_modelでkeyとして定義されたkeyの値もふくまれます。
例えば「test_table」 という名前のテーブルで、keyに「1」があるレコードだとmemcachedのkeyとして「test_table:1」というkeyになります。

ただし、これだとtest_tableという名前は人間にはわかり易いけどスペース効率的によろしく無いケースもあるでしょう。
そういった時は

  install_model test_table => schema {
      schema_options model_name_realname => 't';
};
という設定を仕込む事で、$model->set( test_table => { k => 1 } )という書き方のままで、memcachedのkeyには「t:1」という省スペースなkeyが使われます。

カラム名変換

これも、思想としてはテーブル名変換と同じで、memcachedのvalueにはカラム名を含むハッシュを保存するため、カラム名を短縮形式に変換すると省スペースになります。

  install_model simple => schema {
      schema_options model_name_realname => 's';
      key 'id';
      column 'id';
      column 'name';
      column 'nickname';
      schema_options column_name_rename => {
          id       => 1,
          name     => 2,
          nickname => 3,
      };
  };
数値にすると、後述するMessagePackでのシリアライズで有利になるのですし、ここのカラム名の所はとにかく小さくしとかないと大量のレコードを保存した時のコストが馬鹿にならないのです。

key data strip

KVSはたいがい行データのkeyカラムをkey/valueのkeyとして保存しておくので、シリアライズされたvalueのなかにkeyの値が入ってると重複して無駄なので、シリアライズするハッシュ要素からkeyのデータを取り除きます。
lookup/getした時は、検索するのに使ったkeyから行データを復元する感じです。

シリアライズ

普通にmemcached使ってるなら$memcached->add( $key, { k => 'v' })みたいにしてオブジェクト突っ込めば良いんだけど、この場合サーバがあるFLAGを保存するようにしないとgetする時に上手く動かなかったりします。風の噂でTokyoTyrantがそのまんまだと使えないとか聞きました。
こういった事を解消する為に、シリアライザを自由に変更出来るようにしました。Cache::Memcached::Fastでもシリアライザ変更出来るけども、全然別のモジュール使うときを考えてData::Modelのレイヤでシリアライズする感じです。

  my $driver = Data::Model::Driver::Memcached->new(                                                                                                                                             
      memcached  => Cache::Memcached::Fast->new({ servers => [ { address => "localhost:11211" }, ], }),                                                                                         
      serializer => 'Default', # default is L<Data::MessagePack> or messagepack minimum set for Data::Model                                                                                     
  );
という感じでデフォルトでMessagePackのフォーマットを使って直列化しています。
なお Data::MessagePackが入っていなくても組み込みのシリアライザを使います。Data::MessagePackの0.05以上がインストールされた環境では、Data::MessagePackを利用します。これにより3倍程度のシリアライズの高速化が可能です。

MessagePackはサイズ効率よくシリアライズができるようで、上記のカラム名変換機能で数値カラム名に変換するとMessagePackのFixNumという超省スペースなデータが使われるため、とても効率が良くなります。

Cache::Memcached::Fast標準で使われるStorableだとバージョンの差異でデシリアライズとか出来なくなってはまるときもあるのですが、MessagePackだと当面そういった事も無いでしょう。

全部組み合わせると。。。

実装のし易さやユーザの選択が出来るように、これらの要素はバラバラに設定するようになってますが、基本的に全てのオプションを全部使う事でKVSにとっても嬉しいデータを作り出すようになっています。
シリアライズ以外の要素は、その効果がとてもわかり易いですが、シリアライズの部分もStorableを使ったよりもサイズがコンパクトになります。

例えば

install_model bookmark => schema {
      schema_options model_name_realname => 'b';
      key 'id';
      column 'id' => int => { unsigned => auto_increment => 1 };
      column 'user_id';
      column 'url_id';
      column 'bookmark_at';
      schema_options column_name_rename => {
          id          => 1,
          user_id     => 2,
          url_id      => 3,
          bookmark_at => 4,
      };
  };
という定義で
$model->set( bookmark => {
    user_id     => 1,
    url_id      => 1,
    bookmark_id => time(),
}
といった形でsetすると、keyの部分で(idの文字数)+2バイト、valueで(Mapの定義が1バイト+カラム名の部分のサイズ合計3バイト+user_idがFixNumなので1バイト+user_idも1バイト+bookmark_atはuint32なので5バイト)バイトの計11バイトで格納出来ます。
user_idとurl_idの値のサイズは最小な値になってるですが、0x7fまでだと1バイト、0x80から0xffまでだと2バイト、2バイトの数値は3バイト、32bit整数までなら5バイトで表現可能です。

Driver::Memcachedの利点

と、これまでに紹介してない利点としては、KVSに保存するのはシリアライズされたハッシュオブジェクトなので、カラムの追加とかを自由に出来ると言う事ですね。ALTER TABLEなんかやらないでもアプリケーションのコードを変更するだけでカラムが増やせたり減らせるので簡単です!(減らしてもデータは消されないけど。)
特定のカラムの値でしかlookupしないのであれば、KVSをストレージとして選択してしまうというのもありかもしれませんね。
あんまり良くわかってないけどRemedieとかもそういう使い方をSQLiteでやってる?

特定のkey以外でもKVSを使ってデータの取得をするインターフェィスも作りたいとは思ってるので、それなりにRDBMSの置き換えとかできるかもしれないです。

まとめ

KVSで簡単にORM風なインターフェィスを使うのにはData::Modelが最高というお話でした。

sfujiwaraさんがPostgreSQL用のDBDドライバも作ってくださってるようなので、ますます広がるData::Modelの可能性にご期待下さい!

Posted by Yappo at 14:33 | Comments (0) | TrackBack

2009年07月01日

Test::系モジュールを書いてたので注意した

Test::系のモジュールを書いている人は要注意 - Charsbar::Note
注意に気づいたので Test::PPPort を直してshipitしました。

ちなみに何する物かと言うと、XS用のppport.hはperl ppport.hとするとXSなコードを色々検査してくれるという事で有名ですが、このテストをあなたのテストスイートに組み込んで快適なXSライフが実現出来るというとても素敵なTest moduleなのですよ旦那さん!

Posted by Yappo at 12:23 | Comments (0) | TrackBack

2009年06月27日

YAPC::Asia 2009

そういえば、今年から SHIBUYA PERL MONGERS から JPA 名義のイベントになるんだなーと去年のパンフみて思い出した。

Posted by Yappo at 18:03 | Comments (0) | TrackBack

2009年06月17日

Imager::ExifOrientation - Exifの情報を元にして画像を回転するよ

全国的にみんな真面目だな〜。勉強会の目的なんてないよ。楽しいからやっている。それで何が悪いのかな?の実況中継、その勉強会への 参加そのものについてちょっと考えなおした方がいいかもしれない。

Imager::ExifOrientationをCPANにうpりました。
Exif の Orientation というパラメータを元にして回転済みのImagerオブジェクトを返します。
一緒に Imager::Filter::ExifOrientation もバンドルしてるので、filterとしても利用出来ます。
Orientationは何かと言うと、カメラに縦方向センサーが入ってる機種で、画像に対してカメラの上方向はどちらかというような情報が入っている所です。
わかり易い説明は500で見れないのでgoogleのキャッシュを見てみてください。

使い方は簡単で、exif入りの画像のパスをrotateメソッドに渡すとexif情報に基づいて回転したimager objectが帰ってきます。

my $image = Imager::ExifOrientation->rotate(
      file => 'foo.jpg'
  );
もしくは、適当に読み込んだ画像データを渡す事も出来ます。
my $data = do {
      open my $fh, '<', 'foo.jpg';
      local $/;
      <$fh>;
  };
  my $image = Imager::ExifOrientation->rotate(
      data => $data
  );

カメラで撮ったオリジナルのjpegファイル自体を回転させるのもいいですが、Imagerのフィルターとしても使えるようにしました。

 use Imager;
  use Imager::ExifOrientation;

  my $img = Imager->new;
  $img->filter(
      type => 'exif_orientation',
      path => 'foo.jpg',
  );
こんな感じで、 foo.jpg に入ってるexif情報を元に$imgの画像を回転させます。
他にもImage::ExifToolで抜き出したHASHを元にしたり、Orientationの数値を直接指定する方法も使えます。Orientationを指定する形で使えばlibjpegとか入ってなくても使えます(libjpeg入ってないとテストが全部skipされてたのを0.02で直してshipitた)。詳しくはPODを見てください。

試しにfilterを使ってacotieを回転させてみましょう。
以下ソース

use strict;
use warnings;
use Imager;
use Imager::Filter::ExifOrientation;

for my $i (1..8) {
    my $img = Imager->new;
    $img->read( file => 'acotie.png' );
    $img->filter( type => 'exif_orientation', orientation => $i );
    $img->write( file => "おうっふ_$i.jpg" );
    `open おうっふ$i.jpg`;
}
acotie.png は
これです。
実行結果は以下の通り。

Orientation の 3 は、単純に180度回転なのですが、Imagerのrotateを使うと汚くなるのでclip( dir => 'hv' )して、左右上下反転しました。
rotateは計算して頑張って画像を回転させるというのと、flipは単純にピクセルを並び替えるという差が奇麗さの差になってると思います。rotateはデータをコピーして計算するし。
90度やら270度回転は、流石にrotate使うしか無いけど。

追記:
そもそも90度づつの回転の場合は $img->rotate( right => 90 * $x );使うべきなので、書き換えて0.03をshipiしました。 90度やら270度の回転した画像も奇麗になた!

Posted by Yappo at 11:18 | Comments (1) | TrackBack

2009年06月10日

Data::Model っていう ORM みたいの CPAN にあげたよ

あざーす。循環参照しすぎるとバターになる。。なんでそんなに人の目を気にするのだろうと、マジレス。

早速ですが Data::Model っていう O/Rマッパー 的な物を CPAN にあげました。
Data::Model
http://github.com/yappo/p5-Data-Model/tree/master
元来は MVC モデルで言う所の Model を一括でまかなえるつもりで実装していますが、ロジック処理は普通の Perl のクラスで書いちゃった方が潰しが聞くため、主にストレージを Perl のオブジェクトにマッピングする ORM 的な使い方が主流となっています。
そして、 Data::Model の多くの実装や設計などは Data::ObjectDriver を参考にして開発しました。
他にも後述してる ORM の実装を参考にしています。
あ、あとは tokuhirom 先生による日本語チュートリアルがあります。

現在の所の情報源は CPAN に上がってるドキュメントの他に http://d.hatena.ne.jp/tokuhirom/searchdiary?word=Data%3a%3aModelとかhttp://d.hatena.ne.jp/yappo/searchdiary?word=Data%3a%3aModelぐらいですね。
あと、Hatetterのコードも結構参考になると思います。

Perl の ORM といえば、 Class::DBI をはじめに DBIx::Class, Data::ObjectDriver, Fey::ORM, Rose::DB, Jifty::DBI, DBIx::MoCo など( DBIx::Skinny も github にあるよ )があり、再実装する必要が無いようにも思います。
しかしながら既存の物は、 Inflate/Deflate まわりが貧弱で ForuceUTF8 的な事をやるのもちょっと大変だったり不安定だったり、 cache させるのが面倒だったり、 Moose 使ってたり、 社内の最新リポジトリと CPAN のバージョンが乖離していたりと「こいつと一緒にやりたい!」的な物が見つかりませんでした。確かに DBIC なんかは良いものだとは思いますが、複雑な事が出来てしまうがためにgdgdしてしまう事もあったりしたのです。
Data::ObjectDriver がだいぶ希望に近かったのですが、ドキュメントや利用事例が少なくてユーザになるのに二の足を踏みました。

という現状の ORM に持っていた不満点もあったのですが、それ以外の要因としては RBDMS を kvs 的なインターフェィスで使いたいな。そもそも Web アプリケーションだったら RDBMS の R の要素って使わなくても、やってけてるんじゃないか? だったら kvs 的に使えるように下ほうがさっくり DB の処理書けるんじゃないかな? という観点で作り始めました。
そういったスタンスなので Data::Model::Driver::Memcached という memcached protocol を喋るストレージサーバをバックエンドストレージとして使えるようになってます。

あまり長文はアレなので軽く特徴を

column sugar

user テーブルの id というカラムと同じ役割のカラムを別のテーブルに持つ。それも沢山のテーブルで user id なんかを持ってたいと言うケースは多々あると思います。
そんな時は column sugar を使うと、カラムの詳細定義は一度だけ書いて、後は column sugar を呼ぶだけですみます。

# 定義する
column_sugar 'user.id'
    => int => {
        required => 1,
        unsigned => 1,
    };

# user テーブルでの定義
column 'user.id' => { # ここではカラム名が id になる
    auto_increment => 1, # auto_increment 属性だけ追加する
};

# bookmark テーブルでの定義
column 'user.id'; # ここではカラム名が user_id になる
user id だと当てはまらないですが、 複数のテーブルで定義するカラムで char がた見たいな仕様が代わり安いカラムだと、文字長の仕様変更が入っても一ヶ所だけ size を書き直せば良いので、楽でミスも減ります。

CREATE TABLE 構文を出力する

他の ORM でもよくあるですが、 Data::Model 使って定義したスキーマを CREATE TABLE の SQL に出力します。
そして column sugar が強力にいかせるのは、スキーマ定義に変更が入ったら as_sqls してしまって、そのまま RDBMS 側の DDL も一緒に変えると言う事です。
DB 側のスキーマ情報を自動的に読み込んで ORM のスキーマとしてやるのもありますが、それだとスキーマを二ヶ所で変えなきゃいけなくて面倒なので ORM 側のスキーマのみ変更すれば良いように考えています。
rails のようはマイグレーションも自動的にやりたい所だがまだ未実装です。DB と ORM 側の差分を自動的に反映したいな。

DBI だけでなく kvs にも保存できる

Tokyo Tyrant や groonga や kai などの memcached protocol を使える kvs 等を DBI の代わりに利用する事が出来ます。決定的な制限として primary key でしかデータが引けません。がこれは別の driver と組み合わせる事で対応可能にする方向性です。

透過的なキャッシュ

Data::ObjectDriver インスパイアですが、 cache driver の failback driver を設定した driver object を使う時は、 cache にデータが無ければ、自動的に fallback driver にリクエストする用になります。

cache は Data::Model の Row object その物を渡す感じですが、 DBIC とは違って必要最低限の情報しか入ってないので、あまり問題にならない予定です。

また failback driver には Driver::Memcached を使う事も出来ますが、いわゆる memcached protocol しゃべる kvs は、それ単体での高速性を売りにしているためやる意味が分からんすね。

index に対する検索を簡素化に

Data::Model の get method では index を特別に扱います。
例えば index post (user_id, post_at) の用な index を張っていたら

my $iterator = $model->get( tweet => { index => { post => [ 1, 1281729102 ] } } );
といった形でクエリを引けます。

Q4M 対応

Data::Model では標準で Q4M が扱えます。
以下の例は SELECT queue_wait('smtp', 'pop', 10); を発行して、 queue が帰ってきたらそれぞれのクロージャを呼び出します。
第一引数には dequeue された queue の row object が渡されますので、改めて query を発行せずに、 queue の処理が行えます。

my $retval = $model->queue_running(
    smtp => sub {
        my $row = shift;
        is($row->id, 'foo');
        is($row->data, 1);
    },
    pop => sub {
        my $row = shift;
    },
    timeout => 10,
);

column_aliase

カラムにエイリアスを張ります。
バイナリデータをデータベースに格納するカラムがあるとして、利用する時には文字列形式とバイナリ形式を使いたい場合に、カラムにエイリアスを張ると両方の形式で利用出来ます。

  columns qw( name nickname );
  alias_column name     => 'name_name';
  alias_column nickname => 'nickname_name'
      => {
          inflate => sub {
              my $value = shift;
              Name->new( name => $value );
# Name は name っていうメソッドを持ってるよ
          },
          deflate => sub {
              my $obj = shift;
              $obj->name;
          },
      };
こんな風にしておくと
$row->nickname;      # 普通に文字列が返る
$row->nickname_name; # Name オブジェクトが返る

$row->nickname('test');    # 文字列をセット
$row->nickname_name->name; # test が返る

$row->nickname_name(Name->new( name => 'おうっふ' ));    # オブジェクトをセット
$row->name; # おうっふ が返る
とエイリアス張る前と張った後のメソッドでも保持するデータを相互的に補完し合います。

MySQL の master - slave

当然対応しています。 Driver::DBI::MasterSlave です。
今どきのモダンなウェブアプリは slave の mysql は lvs 噛ましてると思うので、 slave は一個しか指定出来ません。このあたり Data::ObjectDriver 弄った事ある人なら、いかようにも read dbh 分散する仕組み作れると思います。

add_method, mixin

row object に メソッドを生やせる為の add_method って DSL がついてます。
同じ method をいっぱいの table に生やしたい時は mixin 機構があるので、サクサクメソッド生やせます。
DBIx::Class::ResultSet 的な所にメソッド生やしたい場合は、普通に use base 'Data::Model' してるクラスにメソッド生やせばおkです。

transaction

最近実装しました、 DBIx::Class::Storage::TxnScopeGuard インスパイアで以下のように書けます。

  sub foo {
      my $is_die = shift;
 
      my $model = Your::Model->new;
      my $txn = $model->txn_scope; # トランザクション開始
 
      # トランザクション中は $txn からしか DB の操作出来なくなりますよっと
      my $row = $txn->lookup( user => 1 );
      $row->name('transaction name');
      $txn->update( $row ); # update
      return if $is_die; # スコープ抜けて commit されてないのでロールバックされる
      if ($is_die) {
          $txn->rollback; # 明示的にロールバック
          return;
      }

      $txn->commit; # commit する
  }

  foo(1); # rollback されてる
  foo(0); # commit できる
eval {}; if ($@) {} みたいなトランザクションの実行だと、例外があってメソッドをそのままreturnして抜ける事が出来ないので、こっちのが簡潔で気持ちいいと思ってます。
もし die で抜ける事があったとしても DESTROY のタイミングで rollback するので、問題は起こりえない筈ですね。

一つのスキーマクラスに複数のテーブル定義ができる

ORM だと、よく1テーブル/1クラスファイルみたいな感じになっちゃいますが(普通にそうならなく出来るけど)、 Data::Model だと、1クラス=1データベース みたいな感じにする方向性なので、1つのクラスファイルに沢山テーブルの定義をやっちゃいます。

リレーション未実装

なんとリレーション周りを標準でサポートしてません!
add_method 使えば has_a くらいは楽に書けるよ。
よい実装手法があれば作りたい所。

Driver::Pacific

kazuho ware の新作 Pacificに対応予定。
リゾルバとのやり取りを Data::Model 側でやるかどうするかは考えてないけども、結構簡単にラッピング出来るイメージ。

予定つながりだと FriendFeedのアレとかも入れたいですね。

まとめ

まだ特徴はあるですが、面倒なのでまとめる。

作り始めてから半年以上経ってようやくリリースできました。
現在自分がバリバリのユーザですが、使ってみた感じだと徐々に良い感じにもなってるし、テストも充実させている、ドキュメントもそこそこ使い方がわかる程度には書いてあるので是非ともお試しください。

あ、あと重要な事ですが、何でも自分で作りたい病だから作った訳ではないです。

Posted by Yappo at 23:09 | Comments (1) | TrackBack

2009年05月28日

Hash::Merge 活用術

「全裸は違法だということを言われた。ええええ、そんな法律があるのか?Debugはできるようになるかもしれない。」と思っておセンチなyappoです。

hashを簡単にmergeするCPAN moduleとしてHash::Mergeがあるのは有名ですが、デフォルトだと色々頑張ってマージしちゃうので、例えばHTTP::Engine::Middlewareの使いたいMiddlewareをARRAY refで書いちゃったりして、base.yamlとproduction.yamlでmergeした時に、以下のような混ざりかたでとんでも無い目にあいます。

use strict;
use warnings;
use YAML;
use Hash::Merge;

my $base = {
    Middlewares  => [
        { module => 'HTTPSession', config => { name => '開発やらステージング用の設定だよ' } },
        { module => 'MethodOverride' }, # 全部で共通して使いたいよ
    ],
    name => 'base',
    base => 1,
};

my $production = {
    Middlewares  => [
        { module => 'HTTPSession', config => { name => '本番用の設定だよ' } },
    ],
    name => 'production',
    production => 1,
};

my $config = Hash::Merge::merge($base, $production);
print Dump($config);
---
Middlewares:
  - config:
      name: 開発やらステージング用の設定だよ
    module: HTTPSession
  - module: MethodOverride
  - config:
      name: 本番用の設定だよ
    module: HTTPSession
base: 1
name: base
production: 1

これは、マズいですね、HTTPSessionの設定を開発と本番で別けたいのにARRAYだから全部混ざっちゃいます。

そんな時はspecify_behaviorでmergeのルールを弄れるのです。左のreftype => 右のreftypeみたいな形で、左の要素がSCALARで右の要素がARRAYだったどうこうするみたいな事が出来ます。
ぶっちゃけ左の要素がHASHで右の要素がARRAYとかだいぶあり得ないので、そういった組み合わせになったらdieするとかすると混乱無いと思います。

こんかいは左右でreftypeが違うと混乱するし、ARRAY同士でmergeしないで右要素だけを生かしたいと言う要望でbehaviorを作ったです。あと、behavior作っちゃうとデフォルトの振る舞いが上書きされるのでget_behaviorで今の振る舞いを取っておいて用が済んだらset_behaviorすると良いと思います。

use strict;
use warnings;
use YAML;

use Carp;
use Hash::Merge;

my $base = {
    Middlewares  => [
        { module => 'HTTPSession', config => { name => '開発やらステージング用の設定だよ' } },
        { module => 'MethodOverride' }, # 全部で共通して使いたいよ
    ],
    name => 'base',
    base => 1,
};

my $production = {
    Middlewares  => [
        { module => 'HTTPSession', config => { name => '本番用の設定だよ' } },
        { module => 'MethodOverride' }, # array は上書きされるので、こっちにもかく
    ],
    name => 'production',
    production => 1,
};

my $old_behavior =  Hash::Merge::get_behavior;
Hash::Merge::specify_behavior({
    SCALAR => {
        SCALAR => sub { $_[1] },
        ARRAY  => sub { Carp::croak 'SCALAR and ARRAY cannot merge in config file.' },
        HASH   => sub { Carp::croak 'SCALAR and HASH cannot merge in config file.' },
    },
    ARRAY  => {
        SCALAR => sub { Carp::croak 'ARRAY and SCALAR cannot merge in config file.' },
        ARRAY  => sub { $_[1] },
        HASH   => sub { Carp::croak 'ARRAY and HASH cannot merge in config file.' },
    },
    HASH   => {
        SCALAR => sub { Carp::croak 'HASH and SCALAR cannot merge in config file.' },
        ARRAY  => sub { Carp::croak 'HASH and ARRAY cannot merge in config file.' },
        HASH   => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
    },
}, 'MY_CONFIG_STRICT_MODE' );

my $config = Hash::Merge::merge($base, $production);
Hash::Merge::set_behavior( $old_behavior );

print Dump($config);
---
Middlewares:
  - config:
      name: 本番用の設定だよ
    module: HTTPSession
  - module: MethodOverride
base: 1
name: production
production: 1
素敵にマージされましたね。

Posted by Yappo at 15:26 | Comments (1) | TrackBack

2009年05月19日

HTTP::Engine is moved to GitHub

こんにちわ!gitがむづかしすぎてgitなんか滅んでしまえば良いのにと思ってる金曜日の天使ことyappoです。

表題の通り HTTP::Engine 関連のプロジェクトを github に引っ越しました。
http://github.com/http-engine
http://twitter.com/httpengine
http-engineアカウントを取ってそっちで管理する感じです。
必要な方にはコラボレータ追加したりとか良い感じで運用しようと思います。

なおHTTP::Engine 0.1.8 をshipitしました。
Any::Moose 0.08 での変更の追随や
http://example.com/?aco=tie でリクエストたときに $req->uri の中身が http://example.com?aco=tie になってしまうバグが解決されています。

次は、$req->uri->baseがInterfaceによって取れる値が違うのでこれを共通化する方向にしたりとか、良い感じでapplicationのroot pathを取れる仕組みを追加したい所ですが何校中です。

ちなみに移行にはperl製のsvn2gitをforkしてhttp://github.com/yappo/svn2git/tree/master使いました。

$ mkdir hoge
$ cd hoge
$ git init
$ svn2git --strip-tag-prefix 'release-' http://svn.example.com/some-project
$ # git remote ついか
$ git push origin master
$ git push --all
$ git push --tag
な感じで、branches/tagsも含めて全部移行できました。authorsとかのコンバートは面倒いのでやらんす。

Posted by Yappo at 17:47 | Comments (0) | TrackBack

2009年05月09日

Iron Man Blogging Challengeに参加するよ、日本のPerlな人も参加しようよ

Perlをもっとブログの表舞台に - Iron ManコンテストとかPM 05:36 Iron Man Blogging Challengeとか見て僕も応募してみたよ!

エスペラント語だろうが地球語だろうが言語は何でも良いそうなので日本のPerl書きの皆も申し込めば良いよ!
ironman@shadowcat.co.ukにblogのurlとそのblogの詳細を送れば参加出来るみたいだよ!
僕はURLと日本の諺を添えて送っただけだけどちゃんと受理されるかな?

上手くすればmstの髪の毛の色を好きに変える権利も持てるみたいだし損する事は無いので日本のPerlの盛り上がりぶりを世界に知らしめるチャンスだから皆応募しようぜ!

Posted by Yappo at 12:41 | Comments (1) | TrackBack

2009年05月08日

Log::Dispatch::Screen::Color - ログに色付けるよ

Log::Dispatch::Screen::Color を shipit しました。(りぽじとりはこっち)
昨年末に空前のlog colorブームがあったのですが、最近僕もようやくLog::Dispatchをまともに使うようになったので、Log::Dispatch::Screenに色付けたくなって付けました。
うそです。hirose31さんが呟いてたので作りました。

こんなコードと

use strict;
use warnings;
use Log::Dispatch::Config;

Log::Dispatch::Config->configure('test.cfg');
my $log = Log::Dispatch::Config->instance();

$log->info('いんふぉー');
$log->error('えらーーーーーだよ');
$log->warning('warningwarningwarning');
こんなconfigで
dispatchers = screen

screen.class = Log::Dispatch::Screen::Color
screen.min_level = debug
screen.stderr = 1
screen.format = [%d] [%p] %m at %F line %L%n
こうなります

もちろんLog::Dispatch::Colorfulは知っているのですが、これを使うとLog::Dispatchのメソッドを書き換えちゃうので、やや微妙という所もありすっきり仕上げてみたしだいです。
パッチ送れって話もあるですが、$foo->debug({ foo => 'bar' })みたいな事したらDumpしてくれるようにvalidateとか変えてあって、ちょっと僕の欲しい物の方向性じゃ無さそうだという所で新たに作ったのでした。

Log::Dispatch::Colorfulとの互換性はあるので安心です。

とか書いてるうちにcharsbarさんがWin32対応書いてくれたす charsbar++

Posted by Yappo at 14:44 | Comments (0) | TrackBack

2009年05月01日

良い子のMacなPerlユーザーに送る、あなたのPerlアプリをMacアプリにする方法 (Mac版的PAR)

こんにちは!近頃咳と痰と鼻水と鼻づまりがすごく多い、金曜日の天使ことYappoです。

ちょっとしたツールをPerlで書いて、お友達に使ってもらいたいときってありますよね?普通は常識的にgithubとかのurlを教えれば良いのですが、それも出来ない人とかもいた場合が非常に面倒です。
そんな時の便利ツールとしてPlatypusがあるのは有名ですね。
Platyputsを使えば簡単にXSを含めたアプリが配布出来ますんです。

XSとかはアーキテクチャ等によって違うバイナリが吐かれてる事が知られますが、今回はあなたと同じMacOSのバージョンが入ってる事を前提にしちゃって問題無いです。
Macユーザ同士なんだからCPUのアーキテクチャは、殆どの場合は一緒だろうしOSのバージョンもLeopard使ってる前提にしちゃいましょう。

準備するもの

  • Platyputs
  • local::lib
  • あなたのアプリ

手順

まずは作業用ディレクトリでも、作りましょう。mkdir ~/yourappname-work/とかで良いでしょう。

cd ~/yourappname-work/ してから mkdir extlib します。
あなたのアプリで使ってるCPANモジュールを突っ込むのです。

mkdir -p lib/local して local::lib の lib.pm を lib/local ディレクトリの中に入れます。

以下のextlib install用のスクリプトを~/yourappname-work/の中において実行します。

use strict;
use warnings;
use lib 'lib';
use local::lib '--self-contained', 'extlib'; # miyagawaさんのアドバイスで書き換えました
use CPAN;
CPAN->shell;
もしくはlocal::libを普通にインストールして、miyagawaさんが書いたhttp://gist.github.com/104823使うのがいいかなと。

あまり良くわかってないけど、/System/Library/Perl/5.8.8以下にMacOSが添付してるモジュールが入ってるようなので、@INCをいじって標準モジュール以外はキッチリインストール出来るようにしておきますね。
で、このスクリプトはCPAN Shellになってるので、頑張ってあなたのアプリを実行するのに必要なCPANモジュールをインストールしてください。XSでも大丈夫ですが、外部ライブラリに依存するような物(TokyoCabinetなど)はちょっとやり方解らないので誰か教えてください。

今度はPlatypusがkick startするscriptを用意します。#!/usr/bin/env perl とかshebangしとくと良いでしょう。ちなみにこのスクリプトの中では@ISAを弄る必要は特に無いですが

use FindBin;
use lib ("$FindBin::Bin/remedie-git/lib", "$FindBin::Bin/remedie-git/extlib", "$FindBin::Bin/extlib/lib/perl5");
とかしてextlibへのパスを通す必要はあります。

もし、あなたのアプリが$ENV{HOME}を使うようなら

BEGIN {
    $ENV{HOME} = "$FindBin::Bin/home";
}
use Remedie::CLI::Server;

Remedie::CLI::Server->new_with_options(
    root => "$FindBin::Bin/remedie-git/root",
)->run();
とかして、使用するPATHには気を使う必要があります。 $FindBin::Binは YourApp.app/Contents/Resources が該当するため、あなたのスクリプトの使うディレクトリはアプリの外のディレクトリを使わないように気を使いましょう。

.app作る

Platypusを起動して必要な項目とか埋めたり選択して下さい。ここでは詳しく書きません。
Script Pathは、上で書いた.app用のscriptでを選択して下さい。
重要なのは左下の「Show Advanced Options」をクリックして出てくる

でして、右側の+をクリックして頑張ってCPANインストールしたextlibのパスを指定して下さい。
配布アプリの中にそのままコピーされて含まれるのです。

extlib以外の物を配布アプリに含めたい時は任意に好きなだけ追加してください。僕はremedieをgit cloneしたディレクトリを丸っと入れたりしました。

あとは「Create」して、アプリが出来るのを待ちます。

僕の場合は YourApp.app/Contents/script に実行bitが立ってなかったので、 chmod ugo+x YourApp.app/Contents/script しました。
それをやればあっという間に普通のMacのアプリで実行出来る筈です。

まとめ

MacでPARみたいにする手順をずらずら書きました。

Platypus、 local::lib、scriptで使うファイルは$FindBin::Binの中に入れるとアプリケーションの外を汚さなくてすむ。という簡単な要素で作れます。

僕もこれでRemedia.app作ったら他の人のMacでも動きました(最近のmacはlibxml2はいってるっぽ)

さぁ皆さんもPerl使って素敵なMacアプリ開発ライフを過ごしてください。Enjoy!

Posted by Yappo at 10:06 | Comments (1) | TrackBack

2009年04月24日

TokyoCabinetがPerlのHASHより遅いわけがない!

こんにちわ!金曜日担当・Shibuya内フェアリーことYappoです。

mixi Engineers’ Blog » PerlとRubyで省メモリなハッシュを使おうにて

100万件のレコードを格納した場合のメモリ使用量と処理時間を測ってみましょう。Perl(5.8.8)でテストコードを動かしたところ、以下の改善が確認できました。標準のハッシュに比べて、メモリ使用量がTCのオンメモリハッシュだと約61%、TCのオンメモリツリーだと約37%になることがわかります。処理時間に関しては157%ほどになっていますが、まあ許容範囲ですよね。
といった事が書かれており、その文面の上の解説で、tieしたので、tieしてるからおせーんじゃねーの?とテストコードも見ないで呟いてたらmikioさんからtie使わないでやってるよ!とつっこんでいただきました

でもまぁ腑に落ちない所もあり「mikio wareがperlのhashより遅いわけが無い!」と思いながらもshibuya.pmとかあって放置してたのですが、OpenFrepaカンファレンスも終わったのでTokyoCabinet.pmの実装を見てみたら、引数の値チェックをpure perlでやりつつXSのコードを呼んでいる実装でした。
引数の値チェックは置いといて、Perlと言うのは関数呼び出しのコストが馬鹿に出来ないので、試しにXSの関数を直接呼ぶように書き換えてベンチマークを取ってみました。

以下結果で、hashが元のテストコードで言う所のPerlのハッシュの実装で、tc_mikioがmikioさんのTCを使った実装で、tc_yappoが今回XSを直接呼ぶようにしてみた実装です。

$ perl ./benchmark.pl 
             Rate tc_mikio     hash tc_yappo
tc_mikio 333333/s       --     -29%     -52%
hash     469484/s      41%       --     -32%
tc_yappo 694444/s     108%      48%       --
=== ちゃんとkey/valueが入ってるか見るよ at ./benchmark.pl line 41.
hash : 00222791 => h00222791 at ./benchmark.pl line 43.
mikio: 00222791 => m00222791 at ./benchmark.pl line 44.
yappo: 00222791 => y00222791 at ./benchmark.pl line 45.
やっぱりTokyoCabinetの方が断然高速ですね!mikio++

以下ベンチマークスクリプトです

#!/usr/bin/perl
use strict;
use warnings;
use blib;
use Benchmark 'cmpthese';

use TokyoCabinet;

my $runnum = 1000000;
my $tc_args = sprintf('*#bnum=%d#mode=wct#xmsiz=0', $runnum);

my %hash;

my $mikio_db = TokyoCabinet::ADB->new;
$mikio_db->open($tc_args) || die 'mikio open failed';

my $yappo_db = TokyoCabinet::adb_new();
TokyoCabinet::adb_open($yappo_db, $tc_args) or die 'yappo open failed';

my($hash_i, $mikio_i, $yappo_i) = (0, 0, 0);
cmpthese(
    $runnum, {
        hash => sub {
            my $buf = sprintf('%08d', $hash_i);
            $hash{$buf} = 'h'.$buf;
            $hash_i++;
        },
        tc_mikio => sub {
            my $buf = sprintf('%08d', $mikio_i);
            $mikio_db->put($buf, 'm'.$buf);
            $mikio_i++;
        },
        tc_yappo => sub {
            my $buf = sprintf('%08d', $yappo_i);
            TokyoCabinet::adb_put($yappo_db, $buf, 'y'.$buf);
            $yappo_i++;
        }
    }
);

warn "=== ちゃんとkey/valueが入ってるか見るよ";
my $key = sprintf('%08d', int(rand($runnum)));
warn "hash : $key => " . $hash{$key};
warn "mikio: $key => " . $mikio_db->get($key);
warn "yappo: $key => " . TokyoCabinet::adb_get($yappo_db, $key);

$mikio_db->close;
TokyoCabinet::adb_close($yappo_db);

結論としてはTokyoCabinet.xsにid:gfxパワーが加わると(xsの中で引数チェックとかするの意)とんでもない速度になりそうです。

Posted by Yappo at 14:02 | Comments (1) | TrackBack

2009年04月23日

Shibuya.pm #11で発表しました

こんにちは、本日のHOTEL担当、素敵なレディーことYappoです。3人の荷物が家族のオモチャにされないか心配だけどもう寝るぞ!話は変わるけど、acotieさんはアクメアクメ言っててどんだけアクメ好きなんだよ!と思ったのは内緒だぞ!

という訳でShibuya.pmで発表してきました。二本立てです。

一本目は、一般的なperl userの作法のBやらDevel::Peekの紹介に加えて、新しく作ったDevel::RunOpsAnalizeを使ってOPCODEの実行単位でPerlの動作を覗き見る方法の紹介をしました。

二本目はLTで、dan the eval botの作り方を説明する為のCentOSのインストールをするというのを口実にHatetterのアーキテクチャや、なぜこれらの要素を採用したかを紹介しました。
もちろんCentOSのインストールもCobblerとKoanのお陰で完了して、local::libでdan the eval botに必要なperlモジュールも楽々installできるとか嘘つきながら、3分クッキングメソッドで無事にirc botもirc serverにjoinする所までLTの限られた時間の中でデモできました。
LTの中で二つの題材を同時進行で発表するメソッドは案外使えるんだなと思いましたね。30秒オーバするポカやらかしたけど。

ちなみにnon-blockingとか言いましたが、実際にはmemcachedやらQ4Mの処理でblockは発生します。が、気にしなくても良い程度のblockです。maybe

資料は、http://svn.coderepos.org/share/docs/yappo/20090422-shibuyapm11から適当に辿って下さい。VMのサンプルスクリプトもありますよ。
Devel::RunOpsAnalizeはhttp://github.com/yappo/p5-devel-runopsanalyze/tree/masterから
LTのサイトのソースコード一式はhttp://github.com/yappo/website-hatetter/tree/masterからどうぞ。

関係無いけど、英語が出来ない,OCamlがわからない,etc etc etcなどと言ったくだらない理由で、そういう自分が苦手だとかいうのから遠ざかるのは馬鹿だなーと思ったなー。僕なんて相変わらず英語でコミュニケーション取るのがXS書くのより大変だけど、なぜか俺の横で海外組の二人が寝てるよ。起こしかたとか朝飯とかどうすりゃいいんだかわからんけど。

あーあとhidekさんのスター画像作んなきゃ

Posted by Yappo at 02:26 | Comments (0) | TrackBack

2009年03月27日

CPUの気持ちは大事だけど、VMの気持ちも考えようよ

CPUの気持ちになってプログラムを書くということ Kansai.pm#11 参加記その1 - プログラマになりたい

 ちなみに、下記のコードはデータハザードを解消する為のコーディング例です。データハザードは、命令が利用するデータ間に依存関係がある場合に発生します。前の命令が終わらないと後ろの命令が実行できないとか。ですので、それを解きほぐしてやれば、並列で処理が出来るようになります。
という感じでnaoyaさんもぶこめで
loop unrolling は perl でもちゃんと効果がある
って書いてるけど、それforブロック(スコープ)が一段増えてる事で差が出てるんじゃないかと思うわけです。はい。

以下検証コード

use strict;
use warnings;
use Benchmark qw(:all);

cmpthese(5000000, {
    'pseudo loop unrolling' => sub {
        my $sum = 10;
        my $i   = 1;
        $sum = $sum + ($i + 0);
        $sum = $sum + ($i + 1);
        $sum = $sum + ($i + 2);
    },
    'scope 1' => sub {
        {
            my $sum = 10;
            my $i   = 1;
            $sum = $sum + ($i + 0);
            $sum = $sum + ($i + 1);
            $sum = $sum + ($i + 2);
        };
    },
});
そして結果
$ perl ./loop.pl 
                           Rate               scope 1 pseudo loop unrolling
scope 1               1524390/s                    --                  -25%
pseudo loop unrolling 2040816/s                   34%                    --
なぜかブロックを1つ増やしただけなのに、こんなに差がでちゃいましたね!不思議!

まとめ

ブロックがあるという事は、スコープがあると同義なのは当たり前ですが、スコープが変わるという事はレキシカル変数の処理などをやらなきゃいけないわけで、{}があるだけでもPerlは処理をいっぱいするわけです。
別にブロック増やすなというわけではないですが、ベンチマークを取る時にはこういう所にも気をつけたい所ですね。

追記

!hyoshiokさんが、そもそもloop unrollingがperlで意味あるか?というのを気にしていたようなので、効果あるよって言うベンチマークしたす。

forしたコードと、for文だと3回scopeの出入りがあるので、それにあわせるコードも追記して、さらにmy $jのコストも加算するようにした。

use strict;
use warnings;
use Benchmark qw(:all);

cmpthese(5000000, {
    'pseudo loop unrolling' => sub {
        my $sum = 10;
        my $i   = 1;
        $sum = $sum + ($i + 0);
        $sum = $sum + ($i + 1);
        $sum = $sum + ($i + 2);
    },
    'scope 1' => sub {
        {
            my $sum = 10;
            my $i   = 1;
            $sum = $sum + ($i + 0);
            $sum = $sum + ($i + 1);
            $sum = $sum + ($i + 2);
        }
    },
    'scope 3' => sub {
        {
            my $sum = 10;
            my $i   = 1;
            {
                $sum = $sum + ($i + 0);
            }
            {
                $sum = $sum + ($i + 1);
            }
            {
                $sum = $sum + ($i + 2);
            }
        }
    },
    'scope 3 and my $j' => sub {
        {
            my $sum = 10;
            my $i   = 1;
            {
                my $j = 0;
                $sum = $sum + ($i + $j);
            }
            {
                my $j = 1;
                $sum = $sum + ($i + $j);
            }
            {
                my $j = 2;
                $sum = $sum + ($i + $j);
            }
        }
    },
    'loop' => sub {
        my $sum = 10;
        my $i   = 1;
        for my $j (0..2) {
            $sum = $sum + ($i + $j);
        }
    },
});
結果
$ perl ./loop.pl 
                           Rate loop scope 3 and my $j scope 3 scope 1 pseudo loop unrolling
loop                   683995/s   --              -11%    -17%    -48%                  -63%
scope 3 and my $j      772798/s  13%                --     -6%    -42%                  -58%
scope 3                823723/s  20%                7%      --    -38%                  -55%
scope 1               1322751/s  93%               71%     61%      --                  -28%
pseudo loop unrolling 1824818/s 167%              136%    122%     38%                    --
dh004:t ko$ perl ~/bin/htmlescape.pl loop.pl 
やる意義については置いておいて、意味はあるとは思うですよ。

Posted by Yappo at 13:49 | Comments (1) | TrackBack

2009年02月19日

HTTP::Engineの今とこれから

昨年末にHE con #1 が開催されてから久しいですが、あの前後で話題になっていた 「HTTP::Engineは依存が大杉メモリ食いまくり」な件に関しては、Shikaという回答を出し、その後Mouse版の0.1.1をリリースしました、 そして最近Stevanから「Any::Mooseはどうか? lang:en」と言った話も有り、現在Any::Mooseに依存した0.1.4を出すべく0.1.4_xをCPANにあげています。
クラスビルダーにMooseを使うか捨てるか論争は、0.1.4にて妥協出来る所に落ち着いたんじゃないかなと思います。
Any::MooseやMouseが細かい所で挙動が変わるかどうかは今のところわかりませんが、少なくともHTTP::Engineで採用した事により安定する方向になるんじゃないでしょうか?
もちろんより高い互換性の為の変更は入るでしょうが。

0.1.4によってデフォルトはMouseを使い必要とあればMooseで動くようになるので、CatalystのEngineとして使う時はMooseで、Mooseを使うコストが気になる時はMouseが使えるようになりました。
MooseとMouseは細かい所では互換性ありませんが、HTTP::Engineで使ってる内容ではAny::Mooseを噛ますだけで、この差異はほぼ吸収出来ています。
MooseX, MouseXだと互換性が今イチわからない(というか基本的にMouseXはMooseXのが使えるように進める方向性みたい)、これも互換性の高いMo[ou]seX::Typesしか使っていないため問題無いです。

最新のHTTP::EngineではMooseがインストールされた環境でperl ./Makefile.PLするとデフォルトのテストとは別にMoose用のテストを生成して両方テストするようにしています。
cpantestersなどでテスト結果を見るとt/mooseをテストしてるのやテストしてない人が居るとおもいます。(0.1.4_01ではバグってておかしいけど)

Any::Moose

Any::Mooseとは、端的に言ってしまえば「use Any::Mooseほげほげ」した時に、Mooseがloadされていれば「use Any::Mooseほげほげ」が「use Mooseほげほげ」と同等の処理になり、Mooseがloadされていなければ「use Mouseほげほげ」になる感じです。
一度そのクラスでuse Any::Mooseされてれば、次回以降そのクラスの中でuse Any::Moose呼ばれた時には最初に選んだほう(Moose/Mouse)が使われます。
any_mooseに関しても同じ

特に何もしなければ、一番最初にuse Any::Mooseした時に選んだ方が他の時にも使われる。

HTTP::Engine::Middleware

HTTP::EngineはWSGIやRackインスパイアである事は周知の事実ですが、HTTP::Engineが始まった当初からHTTP::Engine::Middlewareという物を作る予定になっていました。
これは a( b( c( handler() ) ) ) のような形で、実際のハンドラ処理にmiddlewareの処理がラッピングされるイメージに近しいイメージで処理をラッピングします。

現在は、様々な方の成果をまとめてDebugScreen/DebugRequest/Encode/Static/HTTPSession/FillInForm/Profil/ReverseProxyなどなど、このレイヤで利用度の高そうな処理を行ってくれるmiddlewareが標準でついてきます。
認証周りを誰か作ってくれないかなぁという所です。OpenIDはzigorouさんだけど。

middlewareは、あくまでもHTTP::Engineとアプリケーションの中間層なのでHTTP::Engineのプラグインでない事に注意が必要です。
plugin的な物が欲しければ、アプリ側にあるべきです。
アプリのプラグインとして、アプリ固有のmiddlewareなんかでもいいです。

ものすっごくベーシックなアプリならHTTP::Engine + HTTP::Engine::MiddlewareだけでもWAFを使わずにかけるかなと言う感じです。
もちろんWAFとかのレイヤがないとMVCやらMVACやら出来ないので大変だけど。

今後の予定

HTTP::Engineは非同期処理とか出来るInterfaceを付けたいなと思ってます。もちろんドキュメントやチュートリアルも。
0.1.x系統で、APIやら基盤はかなり安定してきているためドキュメントを日本語でも良いから増やしたいですね。

HTTP::Engine::Middlewareはパッケージングをどうするか等を詰める感じでしょうか。

0.1.4が出てからは、Mooseな人もMouseな人も使えるようになりますので、是非使ってみて下さい。
参考書籍は無いですが

などがHTTP::Engineを使ったプロダクトとして実在しますので、参考にしてみてくださ。

また、良質の日本語記事としてcharsbarさんのgihyoの記事もあるよ!

Posted by Yappo at 16:11 | Comments (0) | TrackBack

2008年12月03日

MooseX::Typesのしくみ

MouseX::Typesを作るにあたり、あまり使った事のないMooseX::Typesを試していてドはまりした。

普段Mooseのsubtypeとか指定するときは

subtype 'Natural' => where {};
とかやってtype name と定義の間をfat commaで繋げたりする。
で、うかつにもfat commaだからってクオートを外して
subtype Natural => where {};
みたいな事を書いていたわけ。

MooseX::Typeで

use MooseX::Types -declare => [qw/ Natural /]
のような感じで定義しようとした時には、MooseX::TypesがNaturalという関数をexportするんですね。
そして、上記定義をするためのクラスをMyTypesだとした時に
use MyTypes 'Natural'
で、この定義がisaやdoesなどで使えるようになる。
これもNaturalという関数が定義されるので
has foo => ( is => 'rw', isa => Natular );
といったhas定義が書ける。(クオートでくくる必要が無い)

で、MooseX::Typesをきちんと使うためには、subtype/coerce/class_type/role_type/hasのisa/doesなどに、このexportされた関数を渡さなくてはならない。
文字列を渡してはならないのだ。
この関数はMooseX::Types::TypeDecoratorのオブジェクトを返す。このオブジェクトはoverloadされており文字列で評価された時には、typeの名前が返ってくる。
標準で、定義したクラス名+定義名になるので、今回の場合は「MyTypes::Natural」という文字列が変える。
ようするに

subtype 'MyTypes::Natural' => where {};
has foo => ( is => 'rw', isa => 'MyTypes::Natular' );
という定義をしている事と同等なのだ。
これによってユニークな型定義が可能となっている。

さて、冒頭のうかつな

subtype Natural => where {};
は、どうなるというとfat commmaなのでNaturalの部分が文字列として評価されてMyTypes::Naturalの定義がされない事になる。
結果的に、うご書かなくなる。

まとめとしてはMooseX::Typesを使う時には

subtype Natural, where {};
のようにfat commaは絶対使っちゃダメ!

Posted by Yappo at 17:29 | Comments (5) | TrackBack

2008年12月01日

JPerl Advent Calendar 2008

JPerl Advent Calendar 2008が始まりました。Perl に関するちょっとした Tips を、毎日一個とか書いてくのです。
codereposのアカウントがあれば誰でもかけます。

はてなアイデアでadvent calendar ( http://perl-users.jp/articles/advent-calendar/2008/ ) が一ヶ月続いたら、id:precuredaisukiが執筆者全員に雛寿司を奢るというアイデア。codereposのアカウント持ってれば誰でも書けるよ!というアイデアも出されているので、寿司食べたい人は参加するといいよ。

Posted by Yappo at 18:26 | Comments (0) | TrackBack

2008年11月29日

Yakohama.PM で発表した Shika と HTTP::Engine と Data::Model と

流石に3日連ちゃんで発表するのは、どこのYAPC::Asia状態だよ!?と思っていて当初は控えていたのですが、案外体力的にも行けそうだったので当日になって飛び入りで発表させて頂きました。
Yokohama.pm++

本日の発表は、既にtokuhiromが書いてるけど、Shikaについてです。
http://svn.coderepos.org/share/docs/yappo/20081128-yokohamapm3/shika.pl
軽量化MooseなんだったらなぜMouseじゃないのか?Shikaを使う利点は何か?今のステータスはどういう物か?等を話してきました。
前日の昼にスタートしたプロジェクトの事を勉強会で発表するなんて早漏すぎだと思われるかもしれないけれども、Shikaのようなものの需要はだいぶ前から構想されてたのでちょうどいいのです。
必然的にHTTP::EngineをCGIでそこそこ使える時代になってきそう。

ちゃんとフォーローしときますがMooseが駄目だとかそういう話ではないです。あくまでも用途とMooseで出来る事にちょっとしたギャップがあっただけ。

本当はShikaの話は5分で終わってData::Modelのプレゼンしようと思ってたけどShikaだけで時間つかっちゃいましたw
id:nekokakによるDBIx::SkinnyのプレゼンがそのままData::Modelの資料として転用出来そうなので、それをコピペして改変してどっかで発表出来ればなと思っています。
たぶんORMconあたり。
ちなみにDBIx::SkinnyよりData::Modelの方が速いとかとか。

「僕たちはMOPを使いたいんじゃなくて気持ちよくコードを書きたいだけ」という事を再認識しました。

Posted by Yappo at 02:31 | Comments (0) | TrackBack

2008年11月28日

HECon#1 と Shibuya.pm で発表してきたの資料

perl weekという事でHTTP::EngineカンファレンスとShibuya.pmで発表してきました。

http://svn.coderepos.org/share/docs/yappo/20081126-hecon1/hecon1.pl
http://www.nicovideo.jp/mylist/8698529
HEConはhidekさんの絶大な協力によりつつがなく終わる事ができました。Yacafi::Engineに感動しっぱなしでした。
dannさんも切望してるのでHECon#2なんかもあったりするかもしれません。

http://svn.coderepos.org/share/docs/yappo/20081127-shibuyapm10/shibuyapm10.pl
http://www.nicovideo.jp/mylist/9691133
shibuya.pmでは、主に今やってる事の紹介などをしてきました。

なんかしらの勉強会をやると世の中が動くとは孔子もいってましたが、良い感じのプロジェクトも始まりましたが、そのお話は後日ということで。

週末にはSUTEKI hackathonが開催されるので、今回発表したもの周りのコードをぐいっと進めたい所ですね。

Posted by Yappo at 15:05 | Comments (0) | TrackBack

2008年11月26日

HTTP::Engine で進捗表示しつつアップロード

HECon前の前菜に最適だったので。
404 Blog Not Found:perl - LWP::UserAgentで進捗表示しつつダウンロード
というかHECon1は参加条件緩めたしまだあと10名程来れるので是非是非きて下さい。発表枠も1-2枠くらい余ってます。Shibuya.pmの前夜祭的な参加もおkす。

で、何をやったかというとファイルアップロードされるとプログレスバーを表示する。
ServerSimpleやPOE向きの実装。
これを使う事によりアップロードされまくってる感が増大します。しかも簡単なhackで済んでるところも素敵ですね。

こんな感じにコンソール出力されます。

$ perl ./http-engine-progressbar.pl
HTTP::Server::Simple: You can connect to your server at http://localhost:1978/
Upload[15774168]: 100% [=========================================================================================================]D 0h00m04s

use strict;
use warnings;
use HTTP::Engine;
use Term::ProgressBar;

my $engine = HTTP::Engine->new(
    interface => {
        module => 'ServerSimple',
        args   => { port => 1978 },
        request_handler => sub {
            my $req = shift;

            return HTTP::Engine::Response->new(
                body => q|<form method="post" enctype="multipart/form-data">
                          <input type="file" name="upload_file" />
                          <input type="submit" />
                          </form>|
            ) unless $req->param('file');
        },
    }
);

{
    my $progress;
    my $content_length = 0;
    my $read_size      = 0;
    $engine->interface->request_builder->meta->make_mutable;
    $engine->interface->request_builder->meta->add_before_method_modifier(
        _read_init => sub {
            my($self, $args) = @_;
            return unless $content_length = $args->{content_length};
            $read_size = 0;
            $progress = Term::ProgressBar->new({
                count => $content_length,
                name  => "Upload[$content_length]",
                ETA   => 'linear',
            });
        },
    );
    if (1) {
        $engine->interface->request_builder->meta->add_around_method_modifier(
            _read_chunk => sub {
                my $next = shift;
                my $size = $next->(@_);
                $read_size += $size;
                $progress->update($read_size);
                return $size;
            },
        );
    }
    $engine->interface->request_builder->meta->add_after_method_modifier(
        _read_to_end => sub {
            return unless $content_length;
            $content_length = 0;
            $read_size      = 0;
        },
    );
    $engine->interface->request_builder->meta->make_immutable;
}

$engine->run;

Posted by Yappo at 12:04 | Comments (1) | TrackBack

2008年11月19日

Shibuya Perl Mongersテクニカルトーク#10

来る11月27日(水)にShibuya Perl Mongersテクニカルトーク#10が行われます。
具体的に話す内容は決まってませんが大筋のテーマに沿ったものになるます。
Perlを第二言語にしてもらえる予備軍の人向けの話は他の人にゆづるかんじで。

Posted by Yappo at 00:55 | Comments (49) | TrackBack

2008年11月18日

Math::Pari を Mac 環境で入れる方法

Crypt::RSA を Mac で使いたくて Crypt::RSA を install 仕様としたら Math::Pari でこけた。
なにやっても入らない macports しても無駄。fuckfuckfuckfuckだったのですが、ようやく入れる事が出来た。
GCC の インライン最適化を仕様として全オブジェクトファイルに_overfllowというシンボルを作ってリンクできなかったかんじ?

cd /tmp
wget ftp://megrez.math.u-bordeaux.fr/pub/pari/unix/OLD/pari-2.1.7.tgz
pari-2.1.7が必要
tar zxvf pari-2.1.7.tgz
sudo cpan> look Math::Pari
で 2.010800 を入れようとして shell に。
おもむろに vim Makefile.PL して GCC_IN がついてる行をコメントアウト。
vim libPARI/Makefile.PL もして同上。
perl ./Makefile.PL paridir=/tmp/pari-2.1.7 machine=none
make
make test
make install

Crypt::RSAもちゃんとはいった。。。あーつかれた。もう疲れてRT送る気力無い。いつか送る。

Posted by Yappo at 20:31 | Comments (1) | TrackBack

2008年11月14日

HTTP::Engine 0.0.18

色々とbug fixやらがたまってきたので 0.0.18 として shipit しました。
仕様はほぼほぼ固まっているのでドキュメントを充実させて1.0.0を出すために0.9.1_xx系統をやって行きたいとは思ってます。

川崎さんにmod_fastcgi + apach2な環境のテスト作ってもらえたら嬉しいなぁ。なんて。

Posted by Yappo at 19:27 | Comments (2) | TrackBack

update of Yacafi #1

Yacafiが色々と拡張されました。

TemplateはMojo::Templateを改造したMENTA::Templateを移植して使っています。MENTA::Template について - TokuLog 改めB日記も参考にしてください。
Template機能を使わない状態で--packした場合には不要なコードが消えるようになってたりします。

アクションは、今まで./yacafi.cgi?action=fooだったらdo_fooを呼ぶようにしてたんですが、./yacafi.cgi/fooという形をとるようにしました。./yacafi.cgi/foo/bar/bazでdo_foo_bar_bazが呼ばれます。./yacafi.cgi/foo_bar_bazも同様です。

その他実際に動いている様子をhttp://tech.yappo.jp/demo/yacafi/yacafi.cgi/http://tech.yappo.jp/demo/yacafi/yacafi-template.cgi/で確認出来ます。

ファイルアップロードCGIつくるための方法は無いですがおいおい考える事にする。

Posted by Yappo at 16:56 | Comments (1) | TrackBack

HE conference#1開催します

株式会社KDDIウェブコミュニケーションズさんの御好意のお陰でHEconが開催される事となりました。
http://soozy.org/index.cgi?HEcon1
主にHTTP::Engineや、それに類する技術についての勉強会です。(場合によってはHyperEstraierも可)
11月まつのPerlMongers3連日の初日にあたる2008年11月26日(水)20時から麹町で行われます。
定員は30名までなので席のあるうちにお早めにどうぞ。

基本的にHTTP::EngineのAUTHORの方は全員参加という事でひとつ。

Posted by Yappo at 16:19 | Comments (1) | TrackBack

2008年11月12日

Yacafi という軽量CGIフレームワーク書いたよ

MENTA というウェブアプリケーションフレームワークをかいてみた - TokuLog 改めB日記やらNanoA というウェブアプリケーションフレームワークをかいてみた - id:kazuhookuのメモ置き場やらと軽量CGIフレームワーク作りが流行ってるようなので昼飯食った後に20分くらいで書いたよ。

Yacafi(Yet another CGI application framework interface)と言います。
http://svn.coderepos.org/share/lang/perl/Yacafi/trunkからsvn coできるけど、Yacafiはモジュール一個だけあれば動くようにしてあるのでhttp://svn.coderepos.org/share/lang/perl/Yacafi/trunk/lib/Yacafi.pmからwgetとかしてきても使えるよ!

特徴

Yacafi は使い捨て等の軽めのCGIを、いわゆる MVC 的なノリで開発する事が出来ます。
Yacafi.pm と index.cgi 以外のファイルを編集する必要もありません。
いわゆる MVC のノリで開発すると、ディレクトリ掘ったりとかファイルが増えてしまい使い捨てCGIなのに、ちょっと面倒くさくなっちゃうというデメリット(?)が回避できます。
配布する時は 、Yacafi.pm と index.cgi をサーバにアップロードする等することも出来ますし、perl index.cgi --pack というコマンドラインを実行する事によって、 Yacafi.pm と index.cgi を合成したMENTAインスパイアの1つのファイルにまとめて配布する事も可能です。

Yacafi.pm を見れば判りますがblessすら使ってません。全部クラスデータ的なとこに突っ込んでます。

MENTA や NanoA は、いわゆる普通の Web Application Framework を使うかの如く CGI の開発をしつつ軽量性に重点を置いているのに対して、 Yacafi は軽量な使い捨て CGI の開発を行い易くなるような所を重点に置いている違いがあります。

how to

使い方はhttp://svn.coderepos.org/share/lang/perl/Yacafi/trunk/example/index.cgiを参考にして下さい。
といってもとても簡単で

use strict;
use warnings;
use Yacafi;
dispatch;

sub do_index {
    view 'index';
}

sub view_index {
    'hello yacafi!';
}
といったコードだけでディスパッチャ機能付きのCGIが作れます。

ディスパッチする方法としては今の所、index.cgi?action=foo といった形でactionの値を使って、その値に対応するコントローラ関数のdo_*関数を呼び出します。
action=fooならdo_fooとといった感じです。
do_*関数の戻り値は view 'view_name'; と行った感じでViewを呼び出す事を推奨します。
別途

sub do_foo {
    return {
        headers => { 'Content-Type' => 'text/plain' },
        body    => 'hello raw view',
    };
}
のようにして生データも返せます。

viewの定義としてはview_を頭に付けた関数名を書いて下さい。
barというviewを作りたければ sub view_bar { 'hoo' } です。
コントローラ関数等からは view 'bar'; として呼び出せます。
view 'bar', %options といったように引数も渡せ、sub view_bar { my %args = @_; 'aaa' } といった感じで受け取れます。
view関数の戻り値は、ブラウザに返したいコンテンツをそのまま返して下さい。
テンプレート周りが欲しければ別途用意してください。
上記 do_foo のような形式の HASH リファレンスを直接返す事もできます。

modelの定義も出来ますが今の所ノープランでviewと同じ挙動です。

export関数

query('param_name') といった感じでクエリパラメータの取得ができます。MENTAから主にコードをパクっています。

redirect $uri; といった関数を使ってリダイレクト可能です。status codeを変更したければ redirect $uri => 301; のようにして下さい。

サニタイズ目的で filter 関数が使えます。 filter "<script>alert('hello');</script>", => 'html'; の用にお使い下さい。
複数のフィルタを同時に使う事が出来ますが今の所 html しか用意していません。
必要なら

    filter->{uri} = sub {
        my $uri = shift;
        # 処理
        return $uri;
    };
といった感じで拡張して filter "http://", => 'uri'; のように呼び出せます。

TODO

TODOは、せめてファイルアップロード機能くらいはつけたいです。あと、pre_request, post_request的なフックも。

Posted by Yappo at 17:15 | Comments (0) | TrackBack

2008年11月07日

HTTP::Engine And Mojo Benchmarking

Update: Mojo作者のSebastianもベンチマークとってくれたよ! (new benchmark by Sebastian)
Mojo vs. HTTP::Engine - Sebastian Riedel - Perl and the Web
sri++
And if there is time, i make benchmark of FCGI.

本気bar効果でMojoが注目されてるのでHTTP::Engineとの速度差を簡単にとった。
そもそもMojo単体のWeb Serverの使い方が良くわからないので Mojolicious の CLI を見てそれっぽい Mojo::Server::Daemon を使った。

on New MacBook 2.4G

Mojo's source code

use strict;
use warnings;
use Mojo::Server::Daemon;

my $daemon = Mojo::Server::Daemon->new;
$daemon->port(8082);
$daemon->run;

HTTP::Engine's source code

use strict;
use warnings;
use HTTP::Engine;
use HTTP::Engine::Response;

HTTP::Engine->new(
    interface => {
        module          => 'ServerSimple',
        args => { port => 8081 },
        request_handler => sub {
            my $req = shift;
            HTTP::Engine::Response->new(
                body => 'Congratulations, your Mojo is working!',
            );
        },
    }
)->run;

Mojo's Apache Bench Result

bash-3.2$ ab -n 2000 -c 2 http://127.0.0.1:8082/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests


Server Software:
Server Hostname:        127.0.0.1
Server Port:            8082

Document Path:          /
Document Length:        38 bytes

Concurrency Level:      2
Time taken for tests:   4.229 seconds
Complete requests:      2000
Failed requests:        0
Write errors:           0
Total transferred:      318000 bytes
HTML transferred:       76000 bytes
Requests per second:    472.91 [#/sec] (mean)
Time per request:       4.229 [ms] (mean)
Time per request:       2.115 [ms] (mean, across all concurrent requests)
Transfer rate:          73.43 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       3
Processing:     2    4   0.7      4      11
Waiting:        1    3   0.6      3       9
Total:          2    4   0.8      4      11

Percentage of the requests served within a certain time (ms)
  50%      4
  66%      4
  75%      4
  80%      5
  90%      5
  95%      5
  98%      6
  99%      7
 100%     11 (longest request)

HTTP::Engine's Apache Bench Result

$ ab -n 2000 -c 2 http://127.0.0.1:8081/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests


Server Software:
Server Hostname:        127.0.0.1
Server Port:            8081

Document Path:          /
Document Length:        38 bytes

Concurrency Level:      2
Time taken for tests:   1.912 seconds
Complete requests:      2000
Failed requests:        0
Write errors:           0
Total transferred:      230000 bytes
HTML transferred:       76000 bytes
Requests per second:    1045.86 [#/sec] (mean
Time per request:       1.912 [ms] (mean)
Time per request:       0.956 [ms] (mean, across all concurrent requests)
Transfer rate:          117.45 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0      10
Processing:     1    2   0.6      2      12
Waiting:        0    2   0.5      2       7
Total:          1    2   0.7      2      14

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      2
  90%      2
  95%      3
  98%      4
  99%      4
 100%     14 (longest request)     

H::Eはlazy_requestがきいているお陰か、速度が倍くらい違う。
YappoはMojoでのベンチマークの仕方も判ってないから不公平感があるかもしれない。
sriが計測したベンチマークのコードとかどこかに無いかしら?

Posted by Yappo at 19:40 | Comments (1) | TrackBack

2008年10月31日

Term::QRCodeっての作ってみた

QRCode大好きclouderさんがText::QRcodeを作ったのをみたnipotanさんが早速terminal化した物をgyazoにうpしてたので、gazoのコードを見ながら脳内コピペして10分くらいでTerm::QRCodeを作りました。
http://svn.coderepos.org/share/lang/perl/Term-QRCode/


ターミナルで作業してる時に、不意にQRCodeが必要になっても落ち着いてQRCodeを参照できるようになりましたね!

Text::QRCodeはCPANに上がってないけど、ネタでCPANに上げるかな

Posted by Yappo at 13:13 | Comments (1) | TrackBack

2008年10月22日

Module::Collect と List::Rubyish を version++

lopnorさんからpluginファイル中に複数のpackageがあった時に、複数分取り扱えるmultipleサポートをコミットして頂いたのでModule::Collectをversion++してshipitしました。

List::Rubyishはid:hibomaにdelete_ifの挙動が逆!って突っ込みを貰って、どーしよっかと思ってたらid:naoyaにバグッてるからコード差し替えといて!と正しいコードを教えてもらってるうちにid:secondlifeが直してコミットしてくれた!一緒にrejectメソッドも追加してもらったよ!
あとid:walf443からsort_byメソッドも追加してもらって、切りがいいのでshipit!

僕は殆ど何もしてないよ!CodeReposって素晴らしいね!

Posted by Yappo at 23:23 | Comments (1) | TrackBack

2008年10月15日

List::Rubyish をリリースしました

ブクマコメントでnaoyaさんからhttp://github.com/naoya/list-rubylike/tree/master/lib/List/RubyLike.pmがバグも無くていい奴だから、そっちとdiffとって適用したほうがいいよ!とアドバイスいただいて、その差分をmergeしつつList::RubyListのテストコードをコピペするだけの簡単なお仕事をしてテストカバレッジ率も100%になったのでshipitしました。
というかnaoyaさん & secondlife 組の元コードのテストカバレッジ率が90%くらいだったので物凄く楽出来ました^^

http://search.cpan.org/dist/List-Rubyish/にそのうち反映されるはず。

List::RubyLike は use すると list 関数を export してくれるのですが、List:Rubyish では list 関数は export せずに new した時にリストを渡せるようにしました。

my $list = List::Rubyish->new(qw/ foo bar baz /);
が出来る。
その他 delete method の第一引数にコードリファレンス渡せます。
my $list = List::Rubyish->new(qw/ foo bar baz/);
$list->delete(sub { $_ eq 'bar' }); # bar を削除

List::RubyLike では + と >> を overload してるのですが、これを少し拡張して << を unshift に割り当てました。

他にもちょろちょろ本家から変えたりしてますが、基本的な挙動は互換性保ててるとおもいます。

Posted by Yappo at 18:29 | Comments (1) | TrackBack

2008年10月14日

List::Rubyish - hatena の DBIx::MoCo から fork した

DBIx::MoCoというhatena謹製のO/Rマッパは有名ですが、DBIx::MoCo::ListというRubyっぽいリスト操作を行ってくれるモジュールがあります。
概要はPerl のリスト操作を Ruby 風に - naoyaのはてなダイアリーが詳しいです。

DBIx::MoCo::ListはautoboxじゃないのにList::UtilやList::MoreUtilsを活用して実装してあります。
ちょっとしたリスト操作には使い勝手が良さそうなのですが、最大の欠点があります。
それはDBIx::MoCoに含まれるモジュールだという事です。DBIx::MoCoごと入れろと言われたらおしまいですが><

実はDBIx::MoCo::ListはDBIx::MoCoの他のモジュールに依存する箇所がどこにも無く簡単に切り離せるという事実があり、とあるIRCチャンネルでも単独で使いたいケースあるよね的な話が出たので、このたびList::Rubyish(命名 by lopnor++)としてforkさせました。
http://svn.coderepos.org/share/lang/perl/List-Rubyish/trunkにあります。
http://svn.coderepos.org/share/lang/perl/List-Rubyish/trunk/lib/List/Rubyish.pmhttp://search.cpan.org/src/JKONDO/DBIx-MoCo-0.18/lib/DBIx/MoCo/List.pmを見比べても驚く程同じ。
コピーしてs/DBIx::MoCo::List/List::Rubyish/gするだけの簡単なお仕事でした。
原作と違う所は map_* 系のメソッドを抜いたのとgrepメソッドでHASHリファレンスの時は$hash->{$code}するという挙動を追加したくらいです。
test codeもそのままです。

jkondさんかnaoyaさんに怒られなければこのままshipitする予定でございます。

Posted by Yappo at 21:07 | Comments (0) | TrackBack

Method::Signatures's benchmark

Method::SignaturesというPerlのメソッド定義や関数定義を直感的でかつ書き易く行う事が出来るcool moduleがあります。
たとえば

sub lopnor { # DBIx::Class test code style
    my($self, %args) = @_;
    $self->{danjou} = $args{danjou};
}
といったコードを
method lopnor (:$danjou) {
    $self->{danjou} = $danjou;
}
という風に書けます。いいかんじじゃないっすか?

このほどschwernによるプレゼン資料の中にM::S is 1% slowerとか書いてあったのでベンチ取ってみた。

use strict;
use warnings;

package My::Faster;

sub new {
    my($class, %args) = @_;
    bless {%args}, $class;
}
sub get { $_[0]->{$_[1]} }
sub set { $_[0]->{$_[1]} = $_[2] }

package My::Normal;

sub new {
    my($class, %args) = @_;
    bless {%args}, $class;
}
sub get {
    my($self, $key) = @_;
    $self->{$key};
}
sub set {
    my($self, $key, $val) = @_;
    return $self->{$key} = $val;
}

package My::MethodSignatures;
use Method::Signatures;

method new (%args) {
    return bless {%args}, $self;
}
method get ($key) {
    return $self->{$key};
}
method set ($key, $val) {
    return $self->{$key} = $val;
}

package main;
use Benchmark ':all';

cmpthese(
    timethese(
        50000,
        {   
            faster => sub {
                my $obj = My::Faster->new( bar => 'baz' );
                $obj->get( 'bar' );
                $obj->set( foo => 'bar' );
                $obj->get( 'foo' );
            },
            normal => sub {
                my $obj = My::Normal->new( bar => 'baz' );
                $obj->get( 'bar' );
                $obj->set( foo => 'bar' );
                $obj->get( 'foo' );
            },
            MethodSignatures => sub {
                my $obj = My::MethodSignatures->new( bar => 'baz' );
                $obj->get( 'bar' );
                $obj->set( foo => 'bar' );
                $obj->get( 'foo' );
            },
        }
    )
);
こんな感じで。
すごく意地悪な感じでfasterのコードを書いた、なんでかはYappoLogs: Perlで数有る$selfを取る手法をベンチマーク取ったを見てチョ。

平均値っぽい値の結果は下記の通り。

$ perl ./benchmark.pl 
Benchmark: timing 50000 iterations of MethodSignatures, faster, normal...
MethodSignatures:  0 wallclock secs ( 0.49 usr +  0.00 sys =  0.49 CPU) @ 102040.82/s (n=50000)
    faster:  1 wallclock secs ( 0.32 usr +  0.01 sys =  0.33 CPU) @ 151515.15/s (n=50000)
            (warning: too few iterations for a reliable count)
    normal:  0 wallclock secs ( 0.37 usr +  0.00 sys =  0.37 CPU) @ 135135.14/s (n=50000)
            (warning: too few iterations for a reliable count)
                     Rate MethodSignatures           normal           faster
MethodSignatures 102041/s               --             -24%             -33%
normal           135135/s              32%               --             -11%
faster           151515/s              48%              12%               --
激おそでは無いが許容出来そうな感じでもありますな。
まぁPODに
This is ALPHA SOFTWARE which relies on YET MORE ALPHA SOFTWARE. Use at your own risk. Features may change.
とか書いてあるから困りそうな所で使わないけど。

Posted by Yappo at 15:43 | Comments (3) | TrackBack

2008年10月02日

Module::Setup 0.02

Module::Collect 0.03のリリース大失敗してModle::Setup0.01が全く動かないのでversion++した。

Posted by Yappo at 11:43 | Comments (1) | TrackBack

2008年10月01日

Module::Setup - pmsetupをモジュール化した

Perlのモジュールをまず最初に作る時はpmsetupModule::Starterなどを使うのが一般的です。
かく言う余もpmsetupでガリガリ書いてたんですが、はこべさんやらdannさんやらの最近の記事を見て思う所もあってpmsetupをモジュール化してみました。
http://svn.coderepos.org/share/lang/perl/Module-Setup/trunk/

使い方は簡単!cpan Module::Setupでinstallして(まだCPANにあげてないよ!)

 $ module-setup Foo:Bar
を実行するだけ!
ほぼpmsetupと同等の挙動でひな形を作ってくれます。あらべんり!

これだけじゃまったく意味が無いのでModule::Setupらしい所を。。。

flavor

Module::Setup には flavor という概念があり(Module::Startっぽい)module-setupコマンドを叩く時にflavorを切り替える事で、様々なモジュールのひな形を利用出来ます。
現在はDefaultとCodeReposのflavorがあり

 $ module-setup --init --flavor-class=CodeRepos coderepos
 $ module-setup CodeRepos::Module coderepos
という操作で、codereposのflavorを作って、そのflavorをひな形にしたモジュールを作成出来ます。

flavorの編集

flavorは~/.module-setup/flavorの中にflavor別のディレクトリに入っています。
codereposなら ~/.module-setup/flavor/coderepos/template の中身がひな形として使われています。
flavorを使ってひな形を作る時には、このtemplateディレクトリの構成そのまま使われますので、自分の趣味に合うように編集したり必要なファイルとかを追加すると良いでしょう。

このflavor用の設定ファイルは ~/.module-setup/flavor/coderepos/config.yaml にあります。pluginsディレクトリがありますが、この中に適当なファイル名でModule::Setup::Pluginを継承したモジュールを書いてconfig.yamlのpluginsにmodule nameを追加しておくと、このflavorのひな形を作るときにプラグインが読み込まれます。
今の所template処理や新規作成するモジュールの情報を変更するフェーズにフック出来るけど、細かいのはModule::Setup:Plugim::*などのソースを読んで下さい。

subversion用のディレクトリやひな形作成後のperl Makefile.PL make make test などは全部Pluginで行っています。
ちなみに =/.module-setup/plugins には、全flavorでloadされる独自pluginを置いておけます。

flavor を packする

flavorを自分好みに編集したらsvnで管理するにしろtar.gzにするにしろ自由ですが--packオプションでflavorの中身全てを一つのpmファイルにしてくれます。

 $ module-setup --pack MyCodeRepos coderepos > MyCodeRepos.pm
これで作られたファイルを配布するなり好きにすれば良いでしょう。
flavorにするには
 $ module-setup --init --flavor-class=+MyCodeRepos myrepos
とかで出来ます。

packされたflavorを直接使ってひな形つくる

いま作った MyCodeRepos.pm を module-setup --init しないでも直接使う事が出来ます。

 $ module-setup --direct --flavor-class=+MyCodeRepos myrepos
~/.module-setup の変わりに File::Temp で作ったテンポラリディレクトリの中に flavor を展開しているだけです。

おわりに

--pack やら --direct を上手く活用すると catalyst.pl でやってくれるようなヘルパーアプリを作れます。
Module::Setup->run の $options と $argv に適切な値を渡せば、他のモジュールから叩けるはず。
例えばflavor template の lib/____var-module_path-var____.pm の ____var-module_path-var____ は 実際の module の path に書き換えられるので、フレームワークのモジュール追加のヘルパーアプリとかに応用できる。

既存の物とは違ってひな形の元ファイルを、普通のファイル操作で編集出来るって所が便利なんじゃないのかなぁと思ってる所。(Module::Starter::Plugin::CGIApp も似たアプローチだけどキモイというか、Module::Sterter::PBP的だ)
ひとしきり固まれば pack して、自作アプリに組み込んだりも出来るから便利そうだなぁと。

以前からpmsetupをモジュール化するという話は出ていたのですが、「そこまでやるならModule::Sterter使うだろJK」やら「一枚岩のスクリプトで気が変わったらスクリプトを書き換えればひな形が変えられるのがpmsetupの良い所!」という感じで誰も手を付けませんでした。
もちろん僕もそう思っていたのですが、若干必要に迫られた感もあってModuler::Sterterに手を出してみようと思ったら、すこぶるめんどくさくなったのでModule::Setupを作ったのでした。

たぶん他の人のpmsetupも全部カバーできそうかも?

Posted by Yappo at 18:21 | Comments (3) | TrackBack

2008年08月22日

HaikuPodというMacからはてなハイクを快適に使うツールを作ったよ

空前のwassrブームの中皆様いかがおすごしでしょうか。
ついにあのcho45の*ig.rbがまだハイクに対応していなくて面白い感じですが、Mac用のいいツールが無さげです。というかAPIさっき公開したばかりだけど
来週の、MicroblogConにはてなハイクの中の人に参加してもらいたいのですが、「Wassrを末永くお願いします」と言われたので、僕が勝手にTwitterPodをはてなハイク対応しちゃいました。
かいつまむと「はてなハイクをtwitter APIを使うクライアントからアクセスできるコンバータ付きproxy」です。

Macのターミナルとperlが使える環境の人前程ですが、物凄く簡単にエコー対応が出来ます。
TwitterPodをアプリケーションディレクトリに入れておいて下さい。
そして、ここからターミナル操作です。

まずは

svn co http://svn.coderepos.org/share/lang/perl/misc/HaikuPod ~/HaikuPod
とかで、仕組み一式をチェックアウトして
 $ cd /Applications
 $ ~/HaikuPod/install.pl
とするだけでHaikuPodがアプリケーションディレクトリに出来上がります。
これでHaikuPodのインストールは完成です。
何やってるかはinstall.plでも見て下さい。

次に肝心のproxyですが、~/HaikuPod/haikupod.plがそうです。
これを使うには各種CPANモジュールが必要なので

 $ sudo cpan
> install MooseX::Getopt
> install HTTP::Server::Simple
> install HTTP::Engine
> install JSON
> install DateTime
> install DateTime::Format::W3CDTF;
> install XML::Simple
> install MooseX::Types
とかして必要なモジュールを全部入れておきます。
ここまでして入れたら
 $ ~/HaikuPod/mixiechopod.pl --port 8107
で起動します。8107はproxyのサーバポートです。
設定のID,passwordの時にはハイクAPIページを見て適切な物を入れて下さい。

ここまできたらあとはアプリケーションディレクトリのHaikuPodを起動して、設定画面のアカウントは適当なのを入れて、最後が肝心だけど「Enable Proxy」にチェックをいれて「Server」に「127.0.0.1」を入れ「Port」に「8107」を入れればokです。
結構無理栗なhackなのでHaikuPodのアプリケーションが落ちちゃったりする可能性もありますが僕は結構快適に使えてます。

今後の予定ははてなならではの機能をHaikuPodから使えるようにhaikupod.plを拡張してくネタをmixiが実装してくれたらいいですね。
なんでも一から作るのは大変ですが、この程度なら大変じゃなくて良い感じですね。

どうぞご利用下さい。

Posted by Yappo at 15:46 | Comments (1) | TrackBack

2008年08月14日

HTTP::Engine 0.0.13 リリースのお知らせ

昨日HTTP::Engine0.0.13をリリースしました。
今回は大きな変更になっています。

0.0.12までだと

use HTTP::Engine;
HTTP::Engine->new(
    interface => {
        module => 'ServerSimple',
        args   => { port => 9999 },
        request_handler => sub {
            my $c = shift;
            $c->res->body($c->req->uri);
        },
    }
)->run;
と、request_handlerにはcontext($c)を引数と渡して、contextの中にreqやres等があり、Catalystのcontextっぽい感じで使えたのですが、0.0.13からは
use HTTP::Engine;
HTTP::Engine->new(
    interface => {
        module => 'ServerSimple',
        args   => { port => 9999 },
        request_handler => sub {
            my $req = shift;
            return HTTP::Engine::Response->new( body => $req->uri);
        },
    }
)->run;
という風にHTTP::Engine::Responseのオブジェクトを明示的に作って返すようになります。
一見冗長になったように見えますが、HTTP::Engineは基本的に直接利用せずにフレームワーク等で利用される事を想定しているため面倒になるケースは少ないと考えます。

当初はcontext objectを使ってmiddleware等からcontext objectにメソッド生やして便利に仕様という意図があったのですが、mstやnothingmuchからは「contextなんてCatalystで大変になってるからやめようぜ」と提案されたり、実装を進めて行く上でcontextの必要性が少なくなってたり、有用な使い方を思いつかなかったのでcontextを削除しました。
ついでに、折角よりシンプルになるので未だに使い道がはっきりしないmiddlewareサポートも削除しました。

とはいえ、APIの互換性が急に無くなって慌てる人が居たら悪いのでanotherさんに足りないとDISられた公共心をフルに発揮してHTTP::Engine::Compatというのも同時にリリースしました。

use HTTP::Engine::Compat;
HTTP::Engine->new(
    interface => {
        module => 'ServerSimple',
        args   => { port => 9999 },
        request_handler => sub {
            my $c = shift;
            $c->res->body($c->req->uri);
        },
    }
)->run;
とHTTP::EngineじゃなくてHTTP::Engine::Compatをuseするだけで0.0.12までとの互換性を保ちます。
Mooseのお陰で簡潔なコードになってますね。

最後にHTTP::Engineをちっちゃいスクリプトで使いたい時にHTTPEx::Declareもversion upしました(FAIL (4)とか言われてるのであとで直す)。
新たに-Compatモードサポートとresが追加です。

use HTTPEx::Declare;
interface ServerSimple => { port => 9999 };
run {
    my $req = shift;
    res( body => $req->uri );
};
こんな感じで新しいHTTP::Engineに対応したコードが書けます。
resがHTTP::Engine::Response->new(@_);になってるのですね。
-Compatモードは
use HTTPEx::Declare -Compat;
interface ServerSimple => { port => 9999 };
run {
    my $c = shift;
    $c->res->body( $req->uri );
};
と書くだけです。

あともう一つHTTP::Engineには新たな要素があります。
0.0.12までは、request_handlerの中で使わないrequest objectの値(cookieとかrequest bodyとかheaderとか)までも全部作っていたのですが、0.0.13からは必要な時にlazyに作成するようになりました。
使うrequest dataを必要な時にENVやらSTDINから作成するのでアプリケーションによっては効率が良くなるはずです。

もうそろそろHTTP::Engineも要件が固まり来てコンセプト段階を終了しようと思う所ですがどうでしょうね?
仕様をフリーズさせてリファクタリングやらドキュメント作成やらCookbookやらを整備して0.1.0もしくは1.0.0のリリースする感じですかね。

ちなみにあたかも自分が全部やったように書いてるけどcontext削除の作業とHTTP::Engine::Compat作りはtokuhiromがやり、lazyなrequestの作業の大部分はnothingmuchがやりました。
僕はHTTPEx::Declareと全部のテストカバレッジ率を100%にしたのとリリース作業くらいしかしていません。

Posted by Yappo at 09:14 | Comments (0) | TrackBack

2008年07月30日

HTTP::Engine の今後について

trunkのHTTP::Engineのsubカバレッジが100%になった今日この頃皆様いかがおすごしでしょうか。

今現在はtrunkのテストカバレッジを高めた上で、lazy_requestブランチを本格的に採用すべく動いている所です。
nothingmuchによるブランチで、request関連の情報を必要になった時に作り出すような物になっています。
今までは(Catalystもそうだけど)clientからrequestが有るたびに使いもしないデータを最初に作ってたんだけど、そういった事が解消されます。
ただ、今の状態だとPOSTでfile uploadした時が上手く動かない。

lazy_request自体は外部インターフェィスは変わらない予定なので、別に互換性とかの問題は出ないはずなんですが、このブランチが落ち着き次第 HTTP::Engine::Context を無くすブランチを作る予定す。
今までは request や response の情報は $c に生えているメソッド $c->req や $c->res 経由でアクセスする感じでしたが、mstやnothingmuch曰く「context使うなんてCatalystの二の舞になっちゃうyp!(意訳)」といった提案を受けて、「結局 $c ある利点てそんなにないよね」って考えに至ったのでcontextを無くす方向で動こうと思います。
ぶっちゃけWAF側にcontextあったら、どのコンテキストがWAFのなのかHTTP::Engineのなのかわかんなくなって混乱しそうだしね。

sub handle_request {
    my $c = shift;
    $c->res->body($c->req->uri);
}
このコードが
sub handle_request {
    my $req = shift;
    return HTTP::Engine::Response->new( body => $req->uri);
}
になる感じす。

冗長になっちゃうんじゃ無いか?みたいな意見もありそうですが昔のnothingmuchのプランによると

sub handle_request {
    my $req = shift;
    return HTTP::Engine::Response::Redirect->new('http://example.com/');
}
(あ、これも冗長か><)
sub handle_request {
    my $req = shift;
    return HTTP::Engine::Response::JSON->new({ foo => 'bar' });
    # 18:39 < t*kihirom>     return HTTP::Engine::Response::JSON->new({ foo => 'bar' });
    # 18:39 < tokihir*m> HATE HATE HATE
}
みたいに、特定用途によってレスポンスのクラスを変えれるようにしたらどうか的な話になった。

HTTPEx::Declareつかえば

use HTTPEx::Declare qw( res redirect );
interface {
    module => 'ServerSimple',
    args   => {
        host => 'localhost',
        port =>  1978,
    }
};

run {
    my $req = shift;
    return redirect('http://example.com/') if $req->uri =~ /redirect/;
    return res( body => 'hello' );
};
とかになると思う。

HTTP::Engine::Compat的なモジュールを使って、過去のHTTP::Engineアプリと互換性をなるべく保つようにする事も一応考えています。
HTTP::Engine->newするかわりにHTTP::Engine::Compat->newする感じで。

HTTP::Engineはなるべくシンプルであれというのが我々の共通認識であるのでcontextを無くす変更により、よりスマートになるんではないかと思っている次第です。
今まで時間があいた分を取り戻すかのように怒濤に進める予定。

Posted by Yappo at 18:37 | Comments (1) | TrackBack

2008年06月27日

ひどいプラグマ

miyagawaさんに教えてもらったhttp://juerd.nl/files/slides/2006yapceu/undef.htmlこれを見て驚愕したので。

package undef;
use strict;
use warnings;

my $undef = undef;

sub import {
    Internals::SvREADONLY(${\undef}, 0);
}

sub reset {
    Internals::SvREADONLY(${\undef}, 0);
    undef = $undef;
    Internals::SvREADONLY(${\undef}, 1);
}
1;
こんなのを作った。
使い方
use strict;
use warnings;

warn "not" unless undef;

use undef;
warn "not" unless undef;
undef = 1;
warn "not" unless undef;
warn undef;

undef::reset;
warn "not" unless undef;
warn undef;

内部のPL_sv_undefを書き換えちゃうので、色々な物が動かなくなる事間違い無し。
open() or die;も動かなくなる!

Posted by Yappo at 12:26 | Comments (1) | TrackBack

Internals::SvREADONLY

404 Blog Not Found:perl - Const released -- True Readonly

実は、Perl 5.8以降では、Internals::SvREADONLY()という関数がuseなしで使えるようになっていて、Internals::SvREADONLY($scalar, 1)で$scalarをREADONLY flagをonに、Internals::SvREADONLY($scalar, 0)でoffにできます。
知らなかった!
SvREADONLYはwakaponが解説してるよ!

これは universal.c にて実装されていて、使い方は lib/Internals.t を見るべし。
Hash::Utilでも使われてるよ。

danさんの

ただし、これではscalarしかflagをいじれません。というわけで、同様のことをXSでやるようにするモジュールを書いたというわけです。
これは間違いでARRAYもHASHも弄れます。
use strict;
use warnings;
my @values;
Internals::SvREADONLY(@values, 1);
push @values, 1;
これは
Modification of a read-only value attempted at ./ro.pl line 5.
と怒られる。
Internals::SvREADONLY($values[0], 1);
とか局所的にするのも可能。
HASHも同様である。
ちなみにリファレンスの形
Internals::SvREADONLY(¥@values, 1);
では渡せない。

なにが言いたいかというとConstがUNAUTHORIZEDだという事

Posted by Yappo at 11:48 | Comments (1) | TrackBack

2008年06月26日

Shibuya.pm tech talk #9 (XS nite)で発表してきました

Perl本体にパッチをあてる事無く動的に動いてるPerlのコアを書き換えちゃう事が出来るPL_checkやo->op_ppaddrなどについて発表してきました。
資料はそれなりなポインターとして使える風味なので、よろしければご覧下さい。
http://svn.coderepos.org/share/docs/yappo/20080625-shibuyapm9/shibuyapm9-pl_check-hacks.pl

Posted by Yappo at 22:36 | Comments (1) | TrackBack

2008年06月24日

Acme::NabeAtzz - VM崩壊!? ナベアツ人気でPerlプログラマが悲鳴

小学校の算数の授業が崩壊しているというニュースがありますが、昨今のナベアツ人気とPerl VM hackのブームが融合して迷惑なCPANモジュールが誕生しました。

Acme::NabeAtzzをインストールして use Acme::NabeAtzz すると、PerlのVMオペコードの数値が3の倍数になるオペコードを実行する時にPerl VMがアホになってしまう迷惑なモジュールなんです。
例外無く全部の3の倍数のオペコードがアホになるので大変です。
もちろんPerl本体へのパッチは不要です。モジュールインストールするだけです。

興味が有る人はソースでも読んでみて下さい。
このネタは特に明日のShibuya.pmでは言及しません。

Posted by Yappo at 13:04 | Comments (0) | TrackBack

Acme::NabeAtzz - VM崩壊!? ナベアツ人気でPerlプログラマが悲鳴

小学校の算数の授業が崩壊しているというニュースがありますが、昨今のナベアツ人気とPerl VM hackのブームが融合して迷惑なCPANモジュールが誕生しました。

Acme::NabeAtzzをインストールして use Acme::NabeAtzz すると、PerlのVMオペコードの数値が3の倍数になるオペコードを実行する時にPerl VMがアホになってしまう迷惑なモジュールなんです。
例外無く全部の3の倍数のオペコードがアホになるので大変です。
もちろんPerl本体へのパッチは不要です。モジュールインストールするだけです。

興味が有る人はソースでも読んでみて下さい。
このネタは特に明日のShibuya.pmでは言及しません。

Posted by Yappo at 13:04 | Comments (0) | TrackBack

2008年05月20日

perl-users.jp というサイトを立ち上げました

perl-users.jp - 日本のPerlユーザのためのハブサイト

YAPC::Asia 2008 で Michael Schwern は「SEOに有効な独自ドメインを取って、もっとPerl初心者が集まりやすいniceなPerlの情報を集めたサイトを作れ!」といったのでperl- users.jpドメインを取って、ここにperl-users.jpを開始します。 以前よりShibuya.pm界隈では、初心者や複雑なPerlの話題をキャッチアップ出来ないPerl利用者をどうすくい上げるか、という議論を盛んに行って降りました。 Schwern の言う通り perl で検索してもなかなかいい情報にたどり着けなかったりと、それは酷い現状をどうにかしたい思いはYAPC::Asia 2008 のスピーカー陣共通の思いだと思っています。
といった事を目的としたサイトを立ち上げました。

index.html作ってサーバセットアップしただけで中意味は無いですが、SchwernのPerl IS unDeadみて感銘を受けた人は参加してみませんか?
議論は #shibuya.pm #yapc.asia-ja 辺りでやればいいのかなとも思ってます。

あーあとSEOよろしくお願いしますw

Posted by Yappo at 15:48 | Comments (0) | TrackBack

2008年05月16日

YAPC::Asia 2008 and SoozyCon #5 の資料だよ

まずは前夜祭のSoozyCon#5の資料
http://svn.coderepos.org/share/docs/yappo/20080514-soozycon5-yapcasia2008/yapcasia2008-http-engine.pl
HTTP::Engineの概要を話してきたよ。

そして昨日はPerlの%^Hの話だよ。
http://svn.coderepos.org/share/docs/yappo/20080515-yapcasia2008/
danさんの素晴らしさ、danさんを大切にしよう!と説いてきました。
ATの部屋が立ち見が出る程の満員でした、マニアっくすぎる話題なのに驚きです!

そしてさっき終わったのですが、デバイス気持ちいい話。
http://svn.coderepos.org/share/docs/yappo/20080516-yapcasia2008/yapcasia2008-device.pl
楽してデバイスで遊ぼうというお話でした。
X Japanのライブのインスパイアです。

Posted by Yappo at 17:19 | Comments (0) | TrackBack

2008年05月05日

Moose のコードを探索して理解を深めた

本日は Roppongi.PM の第一回 Moose コードリーディングがありました。

Mooseは、単純に使ってる分には分り易いのですが、その実装を見ようとすると途端に複雑さが増します。
とにかくメソッドの呼び出しのスタックが深い。MySQL程では無いにしろ曲者です。
今回はそんなMooseの挙動を把握する手がかりを掴もうという回です。

Moose.pm

Moose.pmは、主にuse Mooseされた時にexportするメソッドの定義をしています。
use Mooseすると、extends,with,has,before,after,around,override,inner,augment,make_immutable($c->meta->make_immutableすべき),confess,blessedがexportされます。
そしてMooseを実用的なパフォーマンスにするmake_immutableを、Moose::*のクラスに対して行ないます。
Mooseのコアクラス自信はimmutableなのです。

importメソッドの中で呼ばれるinit_metaが重要っぽくて、うまくまとめられないからリストだけする。
Moose->import;
- Moose::init_meta;
- $callerのpkgが登録されてるか調べる
-- find_type_constraint($caller_pkg) (実体は Moose::Util::TypeConstraints::find_type_constraint)
-- $caller_pkg が isa("Moose::Meta::TypeConstraint") だったら、$caller_pkgを戻す
-- じゃ無ければ
--- Moose::Meta::TypeConstraint::Registry->newしたインスタンスを Moose::Util::TypeConstraints が保持していて、そのインスタンスの->get_type_constraint($caller_pkg)
--- Moose::Meta::TypeConstraint::Registry のインスタンスの type_constraints が保持してるHASH refに$caller_pkgに対応する値を返す
- 登録なさげだったら登録する
-- Moose::Util::TypeConstraints::class_type($caller_pkg)
--- Moose::Util::TypeConstraints::create_class_type_constraint($caller_pkg)
--- class と name を $caller_pkg にしたhashを作って
---- Moose::Meta::TypeConstraint::Class->new(%hash)
---- ここで use Moose をしたクラスのクラスオブジェクトが作られるのです
---- _create_hand_optimized_type_constraint とか compile_type_constraint とかで、上で作ったオブジェクトの正統性をチェックする為のメソッドを作る。親クラスが居れば、それらの継承順位とかチェックしてるっぽ
--- 上で作ったオブジェクトを Moose::Util::TypeConstraints::register_type_constraint で登録
- Moose::init_metaに戻ってきた
- $caller_pkg->metaの正当性チェックするけど、そもそも meta method が無ければ $metaclass から meta class 作って $caller_pkg に meta method 生やすよ。詳細は下から
-- $metaclass は基本的に Moose::Meta::Class で Moose::Meta::Class->initialize($caller_pkg) で meta object 作る
-- Moose::Meta::Class の実体は Class::MOP::Class で Class::MOP::Class->initialize($caller_pkg, 'attribute_metaclass' => 'Moose::Meta::Attribute', 'method_metaclass' => 'Moose::Meta::Method', 'instance_metaclass' => 'Moose::Meta::Instance', @_) を実際呼んでる。
--- 一度作ったメタクラスは Class::MOP::get_metaclass_by_name($package_name) で取りだせる。 Class::MOP の %METAS に入ってる。
--- 1回も作ってなければ Class::MOP::Class->construct_class_instance して instance 作るよ
--- ちなみに Class::MOP::Class には make_immutable したときに作った anon class の後処理するための DESTROY method もあるよ!
- Moose::init_metaに戻ってきた
-- $meta->add_method で $caller_pkg に meta method を割り当てる
-- 実体は Class::MOP::Class->add_method( method_name, code ) になってるよ
-- code の部分は Class::MOP::Method の派生クラス(Moose::Meta::Method)や CODE リファレンスが指定できるよ。
-- CODE リファレンスの時は Moose::Meta::Method->wrap(code) で Moos::Meta::Method (Class::MOP::Method) オブジェクトを作るけどね
--- で add_package_symbol をするわけだが、これは Class::MOP::Method の親クラスの Class::MOP::Module の親クラスである Class::MOP::Package 樣に実装されている --- Class::MOP::Package->add_package_symbol( '&methodname' => code ) みたいにして登録する。&methodnameのぶぶんのsigilのチェックをしてるので&は必須だ
--- で、あとは一般的な手法の glob で method 生やす事をやっている。生やす対象は meta object が管理している class name (今の場合は $caller_pkg)だ
--- 最期に update_package_cache_flag を呼ぶのだ。add_method したときのおまじないか? Perl 5.10 世代じゃなきゃ Class::MOP の数少ない XS コードを使って PL_sub_generation という値をとって来てる。
--- 良く分らないけど get_method_map の中で使っていて(これはadd_methodするときに meta object に method を登録する部分で利用)を見て perldoc Class::MOP すると module の symbol table が更新されたかどうかが分るものっぽい
- Moose::init_metaに戻ってきた
- そんなこんなで、最期に superclasses がなければ superclasses を設定 (Moose::Object) して init_metaは終る
- superclasses の設定の中味は Class::MOP::Package->get_package_symbol('@ISA') とか使ってるのだ、簡単にいうと push @CLASSNAME::ISA, 'Moose::Object' と変わらないしょりだ

use Moose をするとこんな事になるわけだ。

meta method はどっからくるんだ?

use Mooseした側の meta method が生える仕組みは理解できましたが、その他の Moose::Meta::TypeConstraint::Registry とかにも、いつの間にか meta が生えてますね。
これは一体どこからくるのでしょうか?

答えは Class::MOP::Object にあります。
Moose::Meta::TypeConstraint::Registry の親クラスは Class::MOP::Object です。
Moose::Meta::TypeConstraint::Registry->meta を呼ぶと Class::MOP::Class された Moose::Meta::TypeConstraint::Registry のオブジェクトが帰るのです。

Moose の三賢者

Moose::Meta::Classの

sub initialize {
    my $class = shift;
    my $pkg   = shift;
    $class->SUPER::initialize($pkg,
        'attribute_metaclass' => 'Moose::Meta::Attribute',
        'method_metaclass'    => 'Moose::Meta::Method',
        'instance_metaclass'  => 'Moose::Meta::Instance',
        @_);
}
がそれ。
Moose::Meta::Method は既に出て来たので省いて、Moose::Meta::Instance (実体は Class::MOP::Instance) から。

いわゆる not Moose な時の ClassName->new を Class::MOP->construct_instance が行なっている。
実体は Class::MOP::Instance->new->create_instance あたり。
construct_instance で作った instance に attribute を設定している。

attribute とは、何か? それは Moose::Meta::Attribute まわりの事であり、ざっくり言うと accessor もうちょっと具体的に言うと has の実装にかかわっているもの。

Moose::Meta::Attribute

__PACKAGE__->meta->add_attribute したら引数が Class::MOP::Attribute を継承するオブジェクトだったら Class::MOP::Class->add_attribute に飛ぶ
そうじゃなければ Moose::Meta::Class->_process_attribute に go
attribute name の先頭に + が付いてるときは、親クラスの attribute を継承して部分的に上書き出来て、そうじゃなきゃ全部上書きだよ
そうこうして Moose::Meta::Attribute->new されるんだよ。
実際は Class::MOP::Attribute に処理飛ぶんだけど、 has と Class::MOP::Attribute のオプションって互換性無いから _process_options でオプションを変換してるんだ。

is => 'ro' を reader にして trigger が指定されてないか見たり。

is => 'rw' を accessor にして trigger が指定されていたら CODE リファレンスか確認したり。

とにかく has のオプションの値チェックは _process_options に詰まってるんだ。

それが終ったら Class::MOP::Attribute->new される。
といっても bless するだけで終っちゃうけどね。

で、その new された Moose::Meta::Attribute のオブジェクトが Class::MOP::Class->add_attribute に引数として渡される。
attach_to_class で、 attribute object に attribute を保持してる側の context を渡す。
has_attribute して、既に登録されてる attribute name だったら remove_attribute しちゃう

そして install_accessors Class::MOP::Attribute->install_accessors してから Moose::Meta::Attribute->install_accessors が実行される。
Class::MOP の方は、さらに accessor の種類ごとに process_accessors が呼ばれて、普通の時だと Moose::Meta::Method::Accessor (Class::MOP::Method::Accessor) のオブジェクトが new される。
accessor 用の Moose::Meta::Method だと思えばおk
Moose::Meta::Method::Accessor はすっごい文字列 eval がんばってるけど、あんま気にしないで。普通に使ってる分にはあんまし使われない気がしてる。

Moose::Meta::Attribute の install_accessors は、 handles の処理を行なってる。

has 'name' => ( ... handles => ... )
するときの初期化処理の部分だ。
_canonicalize_handles で delegation するメソッド一覧を作る。
handles の型によって処理内容が変わり、HASH, ARRAY は置いとくと、 Regexp, CODE は _find_delegate_metaclass を使って Moose::Meta::Class なオブジェクト出なければ、なんと Moose::Meta::Class で wrap されたオブジェクトを作るのだ。
あとは、それ以外のリファレンスの他に handles には Moose::Meta::Role を継承しているクラスが利用可能だ。Roleのメソッドをまるごとdelegationしちゃう。

たとえばこんな感じでつかえる。

use strict;
use warnings;
use Base;
use Class;
my $b = Base->new;
$b->foo(Class->new);
warn $b->foo;
warn $b->yappo;
package Base;
use Moose;
use Class;
has 'foo' => (
    is      => 'rw',
    does    => 'Role',
    handles => 'Role',
);
1;
package Role;
use Moose::Role;
requires 'yappo';
1;
package Class;
use Moose;
with 'Role';
sub yappo {
    warn "hoge";
}
1;

handles に Regexp リファレンス と CODE リファレンスを渡すことにより、delegation したいメソッドを指定する自由度が格段にあがる。
そして Role 使えば、 delegation したいメソッドのセットを使いまわせる。便利! でも Role の attributes は delegation できないっぽいす。
っぽいっていうか

        return map { $_ => $_ } (
            $role_meta->get_method_list,
            $role_meta->get_required_method_list
        );
attributeいれる処理ないお。

最期に get_attribute_map に attribute を登録して add_attribute は終了。

Role

Moose を使うなら Role しなきゃモグリってぐらい重要な要素。これは Class::MOP には無く Moose での実装のみです。

Role ってのは、クラスの定義を決めたり前述の handles に指定して delegation をまとめてやっちゃえる実装定義のセットみたいなもんす。

Role する時は use Moose::Role だけでおk、 use Moose したときと同等 (Roleに特化してるけど)なメソッドが提供されます。
Role なクラスの meta object は Moose::Meta::Role が担当してくれます。
Moose::Meta::Role の親クラスは Class::MOP::Module です。
Role は実装本体ではなく実装の定義をあつかうので add_method や add_attribute を呼び出しても glob 操作でメソッド生やすとかはしません。
メソッドの定義とかを追加するだけです。
requires の実装も Moose::Meta::Role の add_required_methods して accessor に情報ため込んでるだけです。

ため込んだ情報はいつ使うのでしょう?
そう Moose.pm で実装されてる with を使ったときだ(あとは has の does や handles でも見られるけど。。。)
with の実体は Moose::Util の apply_all_roles メソッドである。
その後どう処理するかは、 with の引数の内容によりけりだが、単純な with 'Role' の場合だと Moose::Meta::Role->apply が呼ばれる。
さらに with を呼び出した側のクラスが Role なのか何なのかにもよって変わってくる。
要するに Role を何処に適用するかで Moose::Meta::Role::Application::x の x の部分が変わる。

今回は簡単に、Moose なクラスに普通に Role を適用する場合をみる。
実装定義を充たしているかのチェックは Moose::Meta::Role::Application::ToClass と Moose::Meta::Role::Application を読むと良い。
処理内容は

sub apply {
    my $self = shift;

    $self->check_role_exclusions(@_); # role check
    $self->check_required_methods(@_); # method が定義されてるか
    $self->check_required_attributes(@_); # nop

    $self->apply_attributes(@_); # Role で定義されてる attribute を class に install
    $self->apply_methods(@_); # Role で定義されてる method を class に install

    $self->apply_override_method_modifiers(@_); # 以下略

    $self->apply_before_method_modifiers(@_);
    $self->apply_around_method_modifiers(@_);
    $self->apply_after_method_modifiers(@_);
}
こんな感じ。
なんだか check_required_attributes が未実装なんだけど、 attribute の定義も出来るようになるのかしら。

Role の中で has されたり sub foo {} されたり before, after, around, override されたものが全て適用されます。
もちろん with を使ってる側の meta object に、想像どうりのメソッドで追加されてきます。
Moose::Meta::Role::Application::ToRole なんてのもあるですが、それは Role の継承とほぼ等しいです。
ただし with は、 with した瞬間の Role をコピーするというイメージなので注意がいるかも。

before, after, around, override

最期に Moose を method hook する便利メソッドたち。(え? extends そんなの自分で読んで)

実体は Class::MOP::Class->add_(?:before|after|around)_method_modifierなんだ!
$fetch_and_prepare_method に入れられた CODE リファレンス (たぶん外部からどうあがいても弄れない実装にしたかったんだろう)を使って、hook したいメソッドを取りだす。
厳密には Class::MOP::Method::Wrapped のオブジェクトにして返す事をしている。
can を使わずに C3 な継承リストからメソッドを探すのがポイントかな。(これは Class::Component::Component::Moosenize でもやろう)
あとは、hook したいメソッドは Class::MOP::Method::Wrapped のオブジェクトにつつまれてるので、 hook point に対応したメソッドで hook すれば簡単に hook できちゃう。

よしOK、 Class::MOP::Method::Wrapped の中身を見てみよう。
Class::MOP::Method::Wrapped->wrap に、 wrap したいメソッドを入れて使うんだよね。
で、 wrap が呼ばれる度にメソッドの before, after, around のテーブルが書き換わって、 hook されたメソッドがちゃんと動くような anon method を作ってくれるんだ。
add_before_modifier, add_after_modifier なんかはスタック溜めるだけ、 add_around_modifier はちょっと複雑だけど、ちょっとしたくふうで a( b( c( orig() ) ) ) の構造でメソッドをつつんでくれるんだ。
元もとメソッドが定義されていたとしても glob 操作で Class::MOP::Method::Wrapped なメソッドで上書きしてくれるから安心設計だよ。
あと、1回 Class::MOP::Method::Wrapped->wrap されれば add_method されるので、 before, after, around なんかのスタックはちゃんと保持されてる。

ああ、そうだ override を忘れていた。
こいつは Moose::Meta::Class->add_override_method_modifier を使ってる。
そこから Moose::Meta::Method::Overriden を使ってるんだけど
これって使い道よくわからん、 extends したクラスのメソッドを上書きするのに使うみたいだ。
素のメソッド上書きやるよりは Moose 使ってるときは override して上書きしとけだと思うけど。
利点は @Moose::SUPER_ARGS に引数が入っていて $Moose::SUPER_BODY に親クラスのメソッドの CODE リファレンスが入ってる事かな。
と思ったら、 override で上書きしたメソッドの中で super() すると my $self = shift; $self->next::method(@_); と同等になるのか。

augment, inner は、 override, super の逆バージョンって事でおk

そのほか

has の時の値の set/get は Moose::Meta::Attribute の set_value/get_value を見よ。

Immutable

マジックみたいなもんだし、そもそも make_immutable しなくても良いのは小学生までだよねーと mst が言っていたので、ここは書かなくておk

さいごに

いつものように Moose まともに使ってないから、そこんとこよろしく。

Posted by Yappo at 17:57 | Comments (0) | TrackBack

2008年04月30日

HTTP::Engine - Perl版 WSGI のような物、 Catalyst::Engine を抜き出したような物

先週のCatalystConでHTTP::Server::Wrapperというのを発表したのですが、やっぱり名前長いしわかりにくいよねということで、HTTP::Engineという名前でやり直して CPAN に上げました。
http://search.cpan.org/dist/HTTP-Engine/
実は Catalyst の svn repos に HTTP-Engine のディレクトリ掘ってある事は知っていたんだけども、4ヶ月くらい前に作ってからそれっきりっぽいので、DISられ覚悟でうpたわけです。

簡単に説明すると、mod_perlやfastcgiやHTTP::Server::SimpleやPOEやCGIなど様々なWebエンジンを透過的に扱って簡単にフレームワークとか、ちょっとしたオレオレWeb Serverが楽に作れるモジュールです。
PythonでいうとWSGI、RubyでいうとRackのPerlバージョンと考えて下さい。
昔から Catalyst::Engine と Catalyst::Request と Catalyst::Response だけ分離して使いたいよねという話が持ち上がってて、話すだけで実装する所まで行かなかったんですが、CatalystConがあったので Class::Component ベースで作ってみたくなって作りました。

最初のうちは CodeRepos の中でちまちまコンセプト作り上げて YAPC::Asia あたりで外に出して Catalyst::Engine 置き換えようよ!とか Jifty で HTTP::Engine 使おうぜ!とか無茶言おうと思ってたのですが、よく考えたら CodeRepos には Jesse が居たわけで
斜め翻訳すると HTTP::Engine よさげなら Jifty で使ってみたい的な事を言ってた様子。

で、いつの間にか mst の耳にも入っていて、 mst から mail が来たので #catalyst-dev に行ってみたら HTTP::Engine ktkr!状態になってました(かなり意訳)
あちらさんも、まえまえからやろうやろう行ってたけど実行出来なかったよんという感じみたいでした。

なんだか、昨夜から怒濤の展開でようやく今追いついたのでエントリ書いた次第。

とりあえず今は HTTP::Engine というのは、どういった形にすればいいというコンセプトを決めるフェーズなので、安定とかそういうのはほど遠いですが興味有る人は開発参加して下さい。今がチャンス!
irc.perl.org の #http-engine に専用チャンネル作ってますです。
とりあえず今は tokuhirom が Moose 版 の HTTP::Engine を作って盛り上がってる所。

Posted by Yappo at 20:04 | Comments (0) | TrackBack

2008年04月23日

HTTP::Server::Wrapper と CatalystConの発表資料

Cisco Catalystシリーズの勉強会という事で参加したのに、全然違うPerlとか良くわからないやつの勉強会でした。
とりあえずCatalystにログインした所からスタートしたんだけど反応がなくて、enした辺りでようやくhiroseさんが笑ってくれました。
とりあえずshow confしたけど無反応で酷い温度差でしたね。

なんだかサンフランCiscoとかPlugin使わないよJKとかいう言葉が飛び交ったり、発表者全てがCatalystをDISっていましね。
nothingmuchがスペシャルゲストとして来てくれたお陰でプチYAPCというか前々前夜祭くらいのノリになっていました。

しょうがないのでCatalyst::Engineを抜き出して再利用できるようにしたHTTP::Server::Wrapperというのを作ったので、それのプレゼンを行いました。
超簡単に説明するとWSGIのPerlバージョン
ただCatalyst::Engineを抜き出しても拡張性がなさ過ぎでいけてないので、Class::Componentを使ってプラガブルに風味にしてあります。
Session処理とか認証処理なんかは基本的にWAF側じゃなくてエンジン側の仕事じゃないかと思っているので、そのあたりもサクッと作れるようにしたい所です。

資料はhttp://svn.coderepos.org/share/docs/yappo/20080422-catalystcon1/catalystcon.pl
一応Partty.orgで録画してあります。
コードはhttp://svn.coderepos.org/share/lang/perl/HTTP-Server-Wrapper/trunk/から。
もうちょっと形を整えたらCPANします。
ついでにhidekさんが開発してるOkinaというWAFにもHTTP::Server::Wrapper対応しときました。

HTTP::Server::Wrapperを使うと本当に簡単にHTTPサーバを内蔵したアプリが書けます。
もちろんWAFとかをこれベースで作るとEngine処理にからむPluginを使い回せるのでとても良いです。
設定

using_frontend_proxy: 1
plugins:
    - module: Engine::Standalone
      conf:
        host: 0.0.0.0
        port: 14000
を書いて、それを実行するサーバアプリは
use strict;
use warnings;
use lib 'lib';
use HTTP::Server::Wrapper;
use Data::Dumper;
HTTP::Server::Wrapper->new('config.yaml', handle_request => sub {my $e = shift; $e->env('DUMY'); $e->res->body(Dumper($e)) } )->run;
こんな感じでブラウザでアクセスしたら、engineの中身を全部Dumpして表示するようなのが簡単に書けます!

HTTP::Server::Wrapperを使ったサーバを書くのは非常に簡単で、newする時に handle_request メソッドを定義すると、ブラウザからアクセスがあるたびに定義したメソッドが呼ばれます。
引数は今の所Engineのコンテキストです。
$engine->req で Catalyst::Request 相当。
$engine->res で Catalyst::Response 相当。
のオブジェクトにアクセスします。

いまコミットしてあるのはコンセプト的な実装で、とりあえず動かすためにSoozy::(?:Engine::HTTP|Request|Response)からのコピペです。
実際これらの大部分はCatalystからのコピペなので、Catalyst::Engineを切り離した感じ。
というコンセプト実装なので、これからより実用的に使えるように皆で変更していったらいいと思います。
名前もそれっぽいのになるといいよね。

ある程度実用的になったらCatalyst::Engine::Wrapperとか書こうと思う。
どうぞご利用下さい。

Posted by Yappo at 11:44 | Comments (0) | TrackBack

2008年04月22日

CodeReposのコミット時のrule撤廃とか

今までCodeReposにコミットする時はプロジェクトパスを入れろてきなルールが合ったのですが、hanekomuや自分を始めとする皆の不満がつのったし、そもそもそんなの機械的にやればよくね?という話も前からあったのでJesseがCodeReposに来たのを記念してルール撤廃しました。

そもそも何であんな変なのがあったかというと、ircbotやfeedで見た時にプロジェクト名がわかり易い方がいいって理由だけだったはず。
それなので、Commit Pingを受け取ってFeedを吐くサーバを書きました。
サーバのコードはhttp://svn.coderepos.org/share/websites/coderepos.org/feedmaker/
Feedはhttp://coderepos.org/feeds/share.xml

でCodeReposのCommit Pingを便利に扱うためだけにCPANモジュールもこしらえました。
Data::CodeRepos::CommitPingです。
Commit Pingのページの下部に書かれたURLのリストにたいして順番にcommitデータのPOSTをするだけなので。
サーバ側で

my $coderepos = Data::CodeRepos::CommitPing->new(CGI-new);
とかするだけで簡単に取り扱えます。

どうぞご利用ください。

Posted by Yappo at 12:40 | Comments (0) | TrackBack

2008年04月08日

HTML::StickyQuery::DoCoMoGUID - iモードIDを使いたい人に朗報

ふと思い立って、DoCoMoが新しく始めたiモードIDを取得するためのリンクを既存のHTMLにたいして簡単に付与出来るモジュールを書いた。
HTML::StickyQuery::DoCoMoGUIDといいます。
使い方はPOD見てね。

iモードは昔からセッションを維持するにはURLのクエリパラメータやPOSTの値にセッションIDを入れないと駄目だったのですが、先月末からクエリパラメータの中にguid=ONが入っていればRequest HEADにiモードIDを入れてくれるようになったんですね。
HTML::StickyQuery::DoCoMoGUIDは渡されたHTMLの中にAタグがあればクエリパラメータにguid=ONを追加してくれるというフィルタモジュールです。
もちろんAタグだけじゃなくてFORMにたいしてもうまく動きます。
FORMの場合はmethodがget/postでguidを入れる方法が違ってくるのですが、これも考慮してくれます。

名前空間が物語っているように、HTML::StickyQueryのラッパー的な実装なのです。
HTML::StickyQueryだとFORM周りの処理をしてくれないのですが、HTML::StickyQuery::DoCoMoGUID側で処理出来るようにちょっと拡張してたりします。
何故かguidの処理をしないモードが搭載されているのでSledgeの

# XXX we need HTML::StickAny or something ...
な需要を満たせるかもしれません。
つまり、HTML::StickyQueryでやってる特定のセッションIDの埋め込みも出来るようにラッピングしてます。

なんでそうやってるかって言うと、iモードIDはhttpsの時に動かないのでECサイトとか作る時には結局HTML::StickyQueryとかでセッションIDを埋め込む必要が出てくるので、iモードIDを取りつつセッションIDを埋めときたいといった需要が満たせるのですね。
一見いままでと変わらなさそうですけどもiモードIDは契約者に対してユニークな物が割り当てられてるので、どんなURLからサイトに訪問されてもセッションIDが使い回せる利点があるのですね。
セッションID入りのURLをブックマークしてもらう必要とかが無くなる。

正直、今までHTML::StickyQueryとか使ってなかったので、現在は別のべすとぷらくてすがあるかもですが、もし無いようでしたらどうぞご利用下さい。

Posted by Yappo at 23:31 | Comments (0) | TrackBack

2008年04月07日

Class::Component 0.14 でてました

HTTP::MobileAttributeと共に成長期に入っているClass::Componentですが、先週末にバージョンアップしちゃってて今回は二つの機能追加を行ってました。

一つめはregister_methodで、登録するmethodとしてpluginで実際に定義されていないメソッド名を利用出来るようになりました。

package Foo::Plugin::Hoge;
use base 'Foo::Plugin';
sub bar : AliasMethod('baz') {}
みたいな感じで書いておくと
$self->call('baz');
した時にbarメソッドが呼ばれます。
あと、もいっこ大きな事としてコードリファレンス渡しも出来るようになったので無名関数もプラグインメソッドにする事が出来ます。
この辺りの実装のサンプルとしてはhttp://search.cpan.org/src/YAPPO/Class-Component-0.14/t/MyClass/にちゃんと真面目にテストクラス書いてるので、見てみて下さい。

もう一つは、Attributeと実際のpackage名との対応付けを変更出来るためのhook point追加です。
普通は

package Mixi;sub foo: Boofy {}
みたいなattributeを使っていたら。Boofyのattribute処理を行うpackageはMixi::Attribute::BoofyもしくはClass::Component::Attribute::Boofyになるわけですが(@ISAの中身により増える)、新しい仕組みを使うとMixi::Attribute::Bonnnuを使うように変更出来るのです。
上記の変換を実現するサンプルコードは下記の通りです。
package Mixi::Plugin;
use strict;
use warnings;
use base 'Class::Component::Plugin';

sub class_component_load_attribute_resolver {
    my($self, $attr_name) = @_;
    my $new_name = ($attr_name eq 'Boofy') ? 'Bonnu' : $attr_name;
    "Mixi::Attribute::$new_name";
}
1;

どうぞご利用下さい。

Posted by Yappo at 19:41 | Comments (0) | TrackBack

WebService::Simple::Cabinet をリリースしました。

erogeekの処女作のWebService::Simpleが普通過ぎてドン引きしていた所、これを使ったモジュールの実装アイデアを夢の中で思いついたので、起きて速攻で実装しました。

WebService::Simple::Cabinetって言います。
昨日ちょろっと作ってみた所、面白そうとブクマされたのでCPANにうpしたけどindexはまだみたい。
リポジトリはhttp://svn.coderepos.org/share/lang/perl/WebService-Simple-Cabinet/trunk/からどうぞ。

何をする物かというと、miyagawaさんがWSDL/WADLっぽいって言ってたけどWSDLとかの説明が一番しっくりきました。
WebService::Simpleを使って簡単にアクセス出来るようなAPIを更に簡単に使えるような仕組みです。
base_urlや各種パラメータ等を定義しておいて、APIを使う時に定義を読み込んで動的に必要なメソッドを作ってくれるのです。
WebService::Simple自体が非常に単純なんですが、Cabinet使えば更に簡単なメソッドでAPI叩けるようになってグーです。

書き方はmattnさんが書いてくれたlinger.plを見るとわかり易いです。
しかしこれ、一々定義YAMLをscriptに書いてあって無駄っぽいかもしれません。
本来はPlaggerのassets以下に入れられるEFTの設定ファイルみたいなとことに各種APIの定義をおいておいて、newする時に定義名を呼べば済むようにしたかったのですが、具体的に何処におけばいいかのアイデアが出てこなかったので、まだ未実装です。
WebService::Simple::Cabinet::Declare:: 以下にDSLっぽい文法で書いて置いておくアイデアもあったりします。

もともと夢の中で閃いたアイデアなので、どんな所で実用的か説明しろと問いつめられても答えに困りますが、wrapper簡単に書けたり、「なんでPerlにはLDRの購読数をwatcheするためのモジュールが無いんだよ!オレあんましそういうモジュール書けないけど欲しいんだよ!」みたいな人でもYAML書くだけでもオレオレwrapperが作れるのでいいんじゃないかなと思い始めました。

どうか皆さんでコードいじって夢の有るモジュールにしてください。

ちなみに名前の由来はmixiのmikioさんに聞いて下さい。

Posted by Yappo at 19:21 | Comments (0) | TrackBack

2008年04月03日

Class::Component 0.13 リリースのお知らせ

昨日リリースしたばっかりですが、今回はHTTP::MobileAttributeが遅いので何とかしようと色々と最適化していきました。
たとえば前回はattributeの引数を使い易くしたんですが、その解釈に文字列eval使ってて遅いので、なるべくキャッシュするようにしました。
単純にキャッシュしちゃうと不具合がある場合もあって(code ref使うときとか)その場合は、キャッシュさせないようにPlugin単位で制御出来ます。
attributeのキャッシュしないPluginには

sub class_component_plugin_attribute_detect_cache_enable { 0 }
としておいてください。

ボトルネックになっちゃってる所をごっそり書き換えたりしてるわけですが、Class::Componentはそれなりにテストを充実させてるので気楽に書き換える事が出来ました。

Class::Componentの使い方によって単純に比較出来ませんが、HTTP::MobileAttributeでは今回の最適化で6倍くらい速度が上がりました。
HTTP::MobileAttributeはそれ以外にも色々最適化が施されていて、昨日のリリースの時から比べると126倍速になってHTTP::MobileAgentより2倍遅い程度まで速くなってます。

Posted by Yappo at 18:20 | Comments (0) | TrackBack

2008年04月02日

Class::Component 0.11 リリースのお知らせ

Class::Component使ってるアプリはPluginで使える独自のAttributeを簡単に実装できるわけですが、そのときはattributeへの引数的な物が使えるのですね。

sub migi : Karada ('hikisuu') {}
ってやればhikisuuって値が取れます。
しかしこれは、引数が一つのみの場合しか想定していなくて
sub migi : Karada ('hikisuu', 'ippai') {}
ってやるとhikisuu', 'ippaiになってしまってひじょーに悲しいです。

何でかって言うと、この部分はCatalystから略な感じだったので、もうちょっと使い勝手良くしたいよ!という事で、attributeへの引数の使い勝手が良い事で有名なAttribute::Handlerから盗んできました。

こんな感じのコードが書けます。

package MyClass::Plugin::ExtAttribute;

use strict;
use warnings;
use base 'Class::Component::Plugin';


sub args_0 :Method Dump {}
sub args_1 :Method Dump('hoge') {}
sub args_1_2 :Method Dump("hoge") {}
sub args_2 :Method Dump('hoge1', 'hoge2') {}
sub args_2_2 :Method Dump('hoge1', "hoge2") {}
sub args_2_3 :Method Dump("hoge1", 'hoge2') {}
sub args_2_4 :Method Dump("hoge1", "hoge2") {}
sub args_2_5 :Method Dump(qw(hoge1 hoge2)) {}
sub args_2_6 :Method Dump(qw/hoge1 hoge2/) {}

sub ref_array_1 :Method Dump([1,2,3,4]) {}
sub ref_array_2 :Method Dump([qw/1 2 3 4/]) {}
sub ref_array_3 :Method Dump([qw(1 2 3 4)]) {}
sub ref_array_4 :Method Dump(["1",'2','3',"4"]) {}
sub ref_array_5 :Method Dump(['1', '2', '3', '4']) {}
sub ref_array_6 :Method Dump(["1", "2", "3", "4"]) {}

sub hash_1 :Method Dump(key=>'value') {}

sub ref_hash_1 :Method Dump({ key => 'value' }) {}
sub ref_hash_2 :Method Dump({ key => { key => 'value' } }) {}

sub ref_hash_array :Method Dump({ key => [qw/ foo bar baz /] }) {}

sub ref_array_hash_1 :Method Dump([ 'foo', { key => 'value' }, 'baz' ]);
sub ref_array_hash_2 :Method Dump('foo', { key => 'value' }, 'baz');

sub ref_code_1 :Method Dump(sub { return 'code' }->()) {}
sub ref_code_2 :Method Dump(sub { _code }->()) {}
sub ref_code_3 :Method Dump(sub { _code2 4, 5 }->()) {}

sub run_code_1 :Method DumpRun(sub { return 'code' }) {}
sub run_code_2 :Method DumpRun(sub { _code }) {}
sub run_code_3 :Method DumpRun(sub { _code2 4, 5 }) {}

sub _code {
    '_code';
}

sub _code2 {
    $_[0] * $_[1]
}

1;
すごいでしょ?

あとはClass::Component::PluginのPODをちょっと書き換えて、Proj::Plugin::*の各プラグインはuse base 'Class::Component::Plugin';って感じで直接Class::Component::Pluginを継承せずに、一度MyProj::Pluginを被せてから使ってね!
というポリシーに変更しました。
何でかって言うと、各モジュールごとにinitフェーズ書き換えたりとか便利メソッドをMyProj::Pluginの方に書いて便利にして欲しいからですね。
今回からattributeのパースの挙動も変更できるようになったしね。

若干Attributeの挙動を帰るため、自分が把握してる限りの所で影響でないか裏取りした後にリリースしました。
そんなわけでCPANには上げてあるので順次落とせるようになります。

Posted by Yappo at 18:34 | Comments (0) | TrackBack

2008年04月01日

I got the yapc.asia domain

まだ取れる状態だったので、いいですねーの波が来て取ってしまった。
malaに怒られないように

HTTP/1.1 307 Temporary Redirect
Location: http://conferences.yapcasia.org/ya2008/
ってやってある。
けどあとでCNAMEにしておこう。

http://yapc.asia/

Posted by Yappo at 13:03 | Comments (0) | TrackBack

2008年02月15日

デブサミ2008の発表資料、MacでバランスWiiボードのデータを取れるコードとプレゼンツールPlusenの公開

はてなが京都に帰ってしまう発表に盛り上がっている昨今みなさまいかがお過ごしでしょうか。
京都に帰るのははてなと任天堂が提携して、はてなワールドの移動がバランスWiiボードで出来るようになる為だと思い、その可能性を感じられるようなプレゼンをして来たので報告します。

デブサミの資料

早めに資料公開しないと放置してしまうので公開しました。
http://svn.coderepos.org/share/docs/yappo/devsumi2008/
頑張っても動かせない場合はdevsumi2008.plにテキストで文章が書いてあるので読んで下さい。
このディレクトリに置いてある.plファイルは、そのまま下記で紹介するPlusenとMac::WiiRemoteのサンプルにもなってます。

デブサミの動画

今回もcojiさんが動画の録画とニコニコへのうぷぉやって下さいました。
詳細はきっとtakesakoさんのところで書かれるのかもです。
coji++ Yoshiori++

失敗時

リベンジ

発表の様子

今回は、本番でOSが固まってプレゼンが出来ない刑を食らったので皆さんには大部ご迷惑をおかけしました。
なんでトラブったのかというと、物理的な準備に時間がかかるためkoizukaさんのプレゼンの前に全てセットアップしてプレゼンツールを起動していたのですが、CPUに負荷かけまくるプレゼンツールだったので、自分の出番が来る前にOSが超不安定になって制御不能になったわけです。
ぱっと見て動いてるのに実は動かなかったりTermが起動しなかったりvimが動かなかったりして、ようやくPCでプレゼンするのを諦めた頃には時間切れ直前でkazuho methodで発表も出来なくなってました。

せっかく矢印キーが壊れてもwiiリモコンで操作できたり、ブラウザ落ちてもターミナルに直ぐ切り替えたり、VGAとかスクリーンが壊れてもVFDで表示出来るようにプレゼンとしては凄く気の利いた冗長構成を取っていたのに、単一障害点のOSが逝ってしまうなんてプレゼンでは何が起きるかわかりませんね!
次は自分の端末が壊れても瞬時に別の端末でプレゼンする仕組みでも考えます。

大失敗してしまったものの最後の最後に無理矢理割り込みでリベンジ発表をするチャンスを頂けました。
takesakoさん並びに関係者や来場者の方に感謝です。ありがとうございます。
発表の内容も一人だけお題とズレすぎてしまってサーセン。

プレゼンはというと、会社で作ったコミュニケーション可能な検索サイトの紹介をしつつ、最近作り込んでるPlusenの紹介をしようとしてたのですが時間の都合上Plusenの紹介メインになっちゃいました。
内容は、MacBookにWii FitのバランスWiiボードとWiiリモコンとVFD電光掲示板とロケットミサイルランチャーを接続して、Wiiボードの右側に乗るとページが進んだりWiiリモコン振り回すとページが進んだり、ページが進むとミサイルランチャーが動いたりしつつ、スクリーン上ではFirefoxもしくはターミナル上にプレゼン内容が表示され、VFDにも内容が表示されるという、デバイスコミュニケーションをテーマとした発表でした。
Wiiボードを踏まないとページが進みにくいので、時間も足りない事もあって文字通り駆け足でページを捲りつつ発表しました。このへんのおかしさは動画じゃないと伝わらないけど、そのうち発表の様子をニコニコにうpしていただけるという話です。

プレゼンツールPlusen公開

動画でなくても面白い物として、今回発表したプレゼンツールPlusenをようやくCodeReposにコミットしました。
http://svn.coderepos.org/share/lang/perl/Plusen/trunk
SoozyCon#4とかで、はてなワールドにbotをjoinさせて、そのbotにもプレゼンの内容をリアルタイムにさせてたアレです。
Plagger的に様々なデバイスをプラガブルに組み合わせられるプレゼンツールになってます。
Class::Componentを使ってるお陰でメチャクチャコードがシンプルになってますYappo++
目下の目標は、今のPlusenは画像とかの表示やブラウザ側でダイナミックな表現が出来ないのでamachangのS6とかを組み込んでかっこ良くしたい!
色んなプレゼンメソッドを統合していけたら便利になりそうす。

SoozyCon#3では、PlusenのプロトタイプとしてFireVFDという物を使っていました、これはMozReplとVFDデバイスを組み合わせたツールです。
これをClass::Componentでプラガブルにし、プレゼンの内容の出力先をはてなワールドやirc等も追加出来るようにしたのがSoozyCon#4で使ったPlusen初期型です。
これでも納得がいかなくても少し書き直したのが今のPlusenです。
ここ最近のプレゼンは全部Plusen系列でやってたので資料公開が出来ずにいたですが、Plusen公開した事だし過去の出せてない資料を上げてく予定。

今回の目玉

で、一番面白い物としてはWii Fitの板のデータをPerlから取得出来るようにしたMac::WiiRemoteの公開ですね。
http://svn.coderepos.org/share/lang/perl/Mac-WiiRemote/trunk/
WiiRemoteFrameworkとCamelBonesが必要です。
WiiRemoteFrameworkをwii fitに対応させるパッチが入ってます。WiiRemoteFrameworkにパッチをあててxcodeでビルドして下さい。
詳しくはPODにあります。

ちょっと前にWindowsでWii Fit体重計ソフトが出て話題になってましたが、Macから弄る方法が良くわからなかったので、Windowsのソフト作った方の解析結果とかを参考にしながらWiiRemoteFrameworkのコードを書き換えてみました。
MacでWiiリモコンを使えるソフトで有名なDarwinRemoteが利用しているライブラリです。
両方ともコードが公開されているので自分でも作る事が出来ました。すばらしす。
ちなみにperlの実装はRubyとWiiリモコンをつなぐ - urekatのスカンク日記3を参考にしました。

うちのCamelBonesでは何故かオブジェクト通信とかいうやつが上手く動かないので、同梱のパッチではCamelBonesで上手く動くようにするパッチも入ってます。
あとでWiiRemoteFrameworkを作ってる方にもパッチ送らなきゃいけないすね。

CamelBonesが必須という所でピンとくると思いますが、WiiRemoteFrameworkはObjective-CでかかれたCocoaのなんかです。
なのでPerlじゃなくてもRubyCocoaつかったりPythonとかJavaとかからでもMac上のWii Fit弄れるようになれます!PHPもできたっけ?適当にググっても何か出ない。
CocoaだかObjective-Cだか何だかわからないけど、とても簡単で面白いです!空前のCocoaブーム到来してますし皆もCocoaアプリ書けばいいよ!

もっかの悩みはNSRunLoop->currentRunLoop->runを使ってWii FitのをハンドリングしようとするとDanga::Socketとかと連携出来ない所。

そういえば

控え室で機材テストしてたらYoshioriさんに「俺もやろうとして作り始めてたのに先にやられたー!」と大変残念がっていました。
Wiiリモコンプレゼンは速攻でみんながやりだしてて萎えたけど、Wii板は皆一斉にやってなさそうなので一歩先に進めましたね!やりましたね。

とにかく皆様お疲れさまでした。うん本当に疲れた。走りすぎた。

Wiiフィット(「バランスWiiボード」同梱)
任天堂 (2007/12/01)
売り上げランキング: 6
Posted by Yappo at 06:24 | Comments (0) | TrackBack

2008年01月30日

WWW::HatenaLogin - はてなにログインするだけのモジュール作った

はてなのサービスにログインした状態をスクレイピングして利用したい時にや、そういったモジュール(WWW::HatenaDiary)を作りたい時になると気になるのが、毎回毎回https://www.hatena.ne.jp/loginをスクレイピングするのは面倒だなぁと思ったので、WWW::HatenaLoginというログイン処理に関する事しかしないモジュールを作りました。
作ったとはいっても、殆どがWWW::HatenaDiaryからのコピペです。
WWW::HatenaDiaryのログイン部分だけ抜き出してCPANモジュール化した感じですね。

codereposはhttp://coderepos.org/share/browser/lang/perl/WWW-HatenaLogin/trunkです。
CPANにもupload済みで、予定地はhttp://search.cpan.org/dist/WWW-HatenaLogin/ です。
CPANに上げてるテストには含まれてないけど、codereposの方はConfig::Pitを使ってhatenaアカウント情報を取得してテストするコードにしてみました。

やってくれる事はWWW::Mechanizeを使って、はてなにログインとログアウトを行います。
ログイン後のWWW::Mechanizeのオブジェクトがそのまま利用出来るので、簡単にログイン後のはてなをスクレイプできます。
当然cookie_jarも取れるのでLWP::UserAgentで処理を書く事も出来ます。

naoyaさん謹製のHatena::API::Authとの違いですが、naoyaさんのは「はてな認証API」をの為のモジュールで自分のはWebブラウザから使うログインフォームからPerlでログインする為のモジュールという違いです。

早速WWW::HatenaDiaryがWWW::HatenaLoginを使うようにしたブランチを切っりましたので、サンプル的なコードを見たい方は、そちらでどうぞ。

Posted by Yappo at 00:03 | Comments (0) | TrackBack

2008年01月24日

autobox の実装を調べたのと tokuhirom のパッチを発展させた

Perl界隈で熱いと噂のautoboxの実装を調べたりtokuhiromパッチを発展させてみました。
autoboxはsexy。

このエントリのまとめ

本文が長過ぎるので先にまとめを書く。

autoboxはPerlの内部実装をhackして、とてもスマートに実装されたモジュールだというのがわかりました。
一カ所だけアクロバティックな事してますが、それ以外は無理無く実装されていて普通に使う分には十分使えるものっぽいというのが判った。

tokuhiromのパッチの件

tokuhiromのパッチはINTEGERとかFLOATとかSTRINGを別けて扱える様になって良いんだけど、既存のSCALARを拡張したautobox::Encodeとかが動かなくなってとても困るので更にパッチを書いた。
取得はhttp://tech.yappo.jp/tmp/autobox-tokuhirom-yappo-2.patchから。

やっている事としては、オブジェクトがINTEGER,FLOAT.STRINGの時に、それぞれのパッケージにメソッドや変数の定義をしていない場合にSCALARを利用するようになります。
細かく書くとautoboxをimportした時に利用するパッケージにisaとcanのメソッドを生やすので、例えばINTEGERの場合には%INTEGER::にエントリが2個以下しか無い時は、SCALARを使うようにしています。

@ISAにSCALARを突っ込めば良いじゃんという話もありますが、@ISAに突っ込んでしまうと意図しないメソッドまで継承してしまう可能性があるので、INTEGERパッケージにメソッド等が定義されていなければ、利用するパッケージをSCALARパッケージに切り替えるという事をやっています。
もし継承させたいなら、利用者が明示的に

@INTEGER::ISA = qw( SCALAR )
するというポリシーです。

とりあえず既存のautoboxのテストが動く状態になったので、追加された要素のテストを書いてchocolateboyにパッチを送ってみようと思うのですが、いかがでしょうか。
2個以下の時はSCALARってのがad hoc過ぎる気がするのが気がかりですが。

ここから本編

物凄くざっくりとコードを読んだ時にメモしたりしたので、もったいないので公開しときます。
だいぶザックリとしてるので信憑性に問題があるかもしれません。
それでも問題無いよ、という人だけ読んで下さい。

autobox.pm

autobox.pmは、importでレファレンスタイプをどのパッケージに割り当てるのか、hintsを使ってuse autoboxをしている側のローカルスコープの中だけでautoboxされる様に良きにはらってくれる。
unimportも実装されてるけど使いどころを良く知らない。

ではautobox::importの処理を簡単に追っていきましょう。

use autobox SCALAR => 'MySCALAR'
等でuseされた場合には、"hoge"->foo;された場合にはSCALAR::fooを呼ぶのではなくMySCALAR::fooを呼ぶ。

hintsの操作もimportでやっている。
0x20000 だけでいいんだけど %^H 周りのバグがあるらしくて 0x100000 も追加しておかないといけない。
これをやる事により %^H の中身がスコープの中でしか有効にならない。
もっというと use autobox されたスコープの中でのみ有効になる。

$^Hとか%^Hのいわゆるhint情報は、コンパイラが動作する為のヒント情報なのでBEGINフェーズ中でしか意図どおりに動かない。
下記のコードは意図どおりになるが

use strict;
use warnings;
BEGIN {
    $^H |= 0x120000;
    $^H{hoge} = 'start';
}

BEGIN{warn $^H{hoge}}
{
    BEGIN{$^H{hoge} = 'YYY';warn $^H{hoge}}
    BEGIN{warn $^H{hoge}}
}
BEGIN{warn $^H{hoge}}
下記のコードは意図どおりにならない
use strict;
use warnings;
$^H |= 0x120000;
$^H{hoge} = 'start';
warn $^H{hoge}
{
    $^H{hoge} = 'YYY';warn $^H{hoge};
    warn $^H{hoge};
}
warn $^H{hoge}

最後にautobox.xsの中にあるenterscopeを呼び出す。
enterscopeは後述するが、perl内部のフックをautobox用に入れ替える。
遂になる物としてはleavescopeがあり、これはautoboxのスコープが抜けた時に元に戻す処理をしている。
スコープが抜けたという事は0x20000のhint bitsと%^HとScope::Guadを上手く組み合わせて実装している。

Scope::Guadというのは以下のような事をやります。

if (1) {
    my $sg = Scope::Guad->new(sub { } ); # DESTROYした時に呼ばれるコードを登録
    # ... 処理
}# ここで登録したコードが呼ばれる
インスタンスがDESTROYした時にnew時に設定したコードを実行するというシンプルな物です。

use autoboxされたスコープを抜けるとScope::GuadのインスタンスもDESTROYされる事になり、Autobox::leavescopeが呼ばれる事になる。
なんでDESTROYされるかというと、%^Hの中にScope::Guadのインスタンスを入れとくので、スコープ抜けると%^Hのなかがクリアされるので、Scope::GuadのインスタンスがDESTROYされるのである。

importの中に書かれたらimportのスコープを抜けた時点でDESTROYされるじゃないか。という突っ込みもあるかもしれないが、useされた時はどうやら別物らしい。

autobox.xs

次はいよいよautobox.xsの中身だ!
autobox.xsにはAutoboxというpackageに属する、enterscope,leavescope,ENDという3個のメソッドが実装されている。
ENDは、いわゆるENDフェーズのアレだから省略する。

leavescope

autoboxの影響化を抜けた時に後述するenterscopeで入れ替えたメソッドを元に戻す。

enterscope

Autobox::enterscopeは、use autoboxされた時に呼び出される、autobox::importの最後の処理でenterscopeを呼び出している。
何をやっているかというと、PerlのVMのとあるフェーズで実行される処理を差し替えている。
具体的にPerl本体のコードで言うと、opcode.hの

EXT OP *(CPERLscope(*PL_check)[]) (pTHX_ OP *op) = {
が書かれているPL_checkというリストの中にフックテーブルがあって、そのフックテーブルを入れ替えている。
フックテーブル/VMのオペコードにどんなのがあるかはopcode.hとopnames.hを見ること、これはテストにでるよ。
PL_checkが何なのかは調べてない。何となくコンパイルフェーズでチェックするフックポイントテーブルみたいなのだと思ってる。

何を差し替えているかというと、OP_METHOD_NAMEDというOO的なcodeで指定されたmethodが存在するかといったチェックとかをやるフェーズっぽい。
本来はop.cのPerl_ck_nullが登録されてるので、何をやるべきかわかってない。
で、autobox.xsのautobox_ck_method_namedに差し替えられている。

autobox_ck_method_named

use autoboxされたスコープの影響範囲にいなければ本来の処理と同じ挙動になる。
影響範囲にいる時には、$^H{autobox}の中に入っている handler table をPL_hintgvから取り出しておき、autoboxの胆となる処理が走る。

autobox_method_named

このメソッドがautoboxの肝。
ここで呼ばれたメソッドがどういう形("hoge"->foo, 1->foo, []->foo, {}->foo)で呼ばれるのか、何のリファレンスタイプで呼ばれてるのかを調べている、具体的にはtokuhiromのpatchしてる辺り。
そして、リファレンスタイプに対応するhandler tableに登録されてる実際に使われるpackage nameを取り出す。
gv_stashpvnというのは指定されたパッケージ名に紐づけられたhashを取り出すもの、Perlのコードでいう所の%SCALAR::みたいな物。gv.cを見よ。
そしてごにょごにょ処理をする。

gv_fetchmethod(stash ? stash : (HV*)packsv, name);
の所では、パッケージの中にメソッド定義されているかを調べる感じ。

autobox_method_namedでもっとも大事な部分というのはXPUSHsでgvをpushしてる所。
スタックを操作することにより、

1->foo;
といったpackage nameでもなくオブジェクトリファレンスでも無いコードに対して、1という部分がSCALARというオブジェクトレファレンスなんだよと錯覚させてしまうのである。と思う。スタック型なんだなぁというのがわかる。

メソッドが見つからなければ

return PL_ppaddr[OP_METHOD_NAという所にいく。
これはメソッドがねーぞというエラーを出すことと同等。

autobox_ck_subr

OP_ENTERSUBというフェーズも書き換えている、本来はop.cのPerl_ck_subrというメソッドを呼んでおり、処理内容を見るとprototype宣言のパースをやってる。
何となくだけど、autobox_ck_method_namedで変更したフラグを戻すとかやってるのかな?
これといって大げさな処理は行われていない。

おまけ

以前encoding::sourceを5.8で動かそうとして無理だった件で、%^Hの値がレキシカルスコープ担ってないからってのがあったんだけど、autoboxを見たらhint bitsに0x20000を立てとけば同じような挙動になるのが解った。
それなんでdan.pmとかencoding::sourceをdorからdefined or にcallerの10個目のを%^Hに、import/unimportで0x20000の出し入れをやってみたけど、うまく動かなかった。
callerの件が実装されてないので、もしかしたらBEGINフェーズ以外でも%^Hが必要になってるのかもしれない。
こんど改めて調べてみることにする。

ちなみに、まだinstall autoboxしてない。

Posted by Yappo at 20:20 | Comments (1) | TrackBack

2008年01月11日

LvalueなAccessorのベンチマーク

空前のlvalue期に突入したので、lvalueなアクセサを作れるClass::Accessor::LvalueとClass::Accessor::Lvalue::Fastを比較したベンチマーク取ってみました。

package Tied;
use strict;
use warnings;
use base 'Class::Accessor::Lvalue';
__PACKAGE__->mk_accessors(qw/ a b /);
1;

package Tied;
use strict;
use warnings;
use base 'Class::Accessor::Lvalue::Fast';
__PACKAGE__->mk_accessors(qw/ a b /);
1;

bench.pl

use strict;
use warnings;

use Benchmark qw(:all);

use Tied;
use Fast;

my $inst  = {};
my $codes = {};

for my $pkg qw( Tied Fast ) {
    $inst->{$pkg} = $pkg->new;
    $codes->{$pkg} = sub {
        my $a = $inst->{$pkg}->a;
        $inst->{$pkg}->a++;
        $a = $inst->{$pkg}->a;
        my $b = $inst->{$pkg}->b;
        $inst->{$pkg}->b++;
        $b = $inst->{$pkg}->b;
    };
}
cmpthese(100000, $codes);

以下結果

[yappo@stfuawsc lvalue]$ls
Fast.pm  Tied.pm  bench.pl
[yappo@stfuawsc lvalue]$perl ./bench.pl 
         Rate  Tied  Fast
Tied   8285/s    --  -92%
Fast 107527/s 1198%    --
[yappo@stfuawsc lvalue]$perl ./bench.pl 
         Rate  Tied  Fast
Tied   9251/s    --  -91%
Fast 108696/s 1075%    --
[yappo@stfuawsc lvalue]$perl ./bench.pl 
         Rate  Tied  Fast
Tied   9083/s    --  -91%
Fast 106383/s 1071%    --
[yappo@stfuawsc lvalue]$perl ./bench.pl 
         Rate  Tied  Fast
Tied   9066/s    --  -92%
Fast 111111/s 1126%    --
[yappo@stfuawsc lvalue]$perl ./bench.pl 
         Rate  Tied  Fast
Tied   9372/s    --  -92%
Fast 114943/s 1126%    --
[yappo@stfuawsc lvalue]$perl ./bench.pl 
         Rate  Tied  Fast
Tied   9259/s    --  -92%
Fast 111111/s 1100%    --
[yappo@stfuawsc lvalue]$

10倍くらいの差がでました、やはりtieを使ってるとこんなん結果になるんですね。

lvalueの挙動というのは、lvalue attributeを付けられたメソッドが最後に返したスカラ(returnでかえしちゃだめ)に対して代入処理を行っているため、lvalue が付いたメソッド自体は

$self->attr() = 'value'
の形で代入された事を感知出来ません。
そこでtieを使って感知も出来る様にした実装がClass::Accessor::Lvalueなのです、しかしtieの機能が要らない人に取っては余計な遅さなので、tie使わないシンプルな実装としてClass::Accessor::Lvalue::Fastが在る訳です。

やっぱり足して2で割ったやつが欲しいな。

Posted by Yappo at 18:03 | Comments (0) | TrackBack

2008年01月01日

CodeReposでShipItを快適に使うモジュールをCPANにうp

年納めという事でShipItを使ってCPANリリースする時にCodeReposのCommit messege rulesにそったコミットメッセージを吐くようや拡張としてShipIt::Step::CommitMessageWrapをリリースしました。
最初のバージョンあたりは、テストしつつうpるというとんでもない事やってたので動きません。
せめてversion 0.03 から動きます。

何をするかと言うとShipItがsvnとかでコミットした時のコミットメッセージに任意のコメントを追加出来たりします。
例は実際http://coderepos.org/share/browser/lang/perl/ShipIt-Step-CommitMessageWrap/trunk/.shipitを見て下さい。

ついでにpmsetupの方も良い感じにsetupしてくれるように変更しました。

Posted by Yappo at 00:03 | Comments (0) | TrackBack

2007年12月28日

Perlで数有る$selfを取る手法をベンチマーク取った

PerlでOOなコード書く時のコンテキストを取る方法は色々あります、最近audreyがselfvarsをリリースしたので、gugodのself.pmとingyのSpiffyそして、既存のmy $self = shift;やshift->や$_[0]->で$selfを取る方法それぞれのベンチマークを取ってみました。

テストコードのモジュール名は、それぞれのモジュールの作者名から取り、既存の手法はYAPC::Asiaでプレゼンした事のある日本を代表するPerlな企業のCTOからモジュール名を取らせていただきました。

コードは以下の通りです。

package Audrey;
use strict;
use warnings;
use selfvars;
sub new { bless { count => 0 }, shift }
sub inc { $self->{count}++ }
1;
package Gugod;
use strict;
use warnings;
use self;
sub new { bless { count => 0 }, shift }
sub inc { self->{count}++ }
1;
package Ingy;
use strict;
use warnings;
use Spiffy -Base;
#sub new { bless { count => 0 }, shift }
sub inc { $self->{count}++ }
1;
package Ikebe;
use strict;
use warnings;
sub new { bless { count => 0 }, shift }
sub inc { $_[0]->{count}++ }
1;
package Naoya;
use strict;
use warnings;
sub new { bless { count => 0 }, shift }
sub inc { my $self = shift; $self->{count}++ }
1;
package Batara;
use strict;
use warnings;
sub new { bless { count => 0 }, shift }
sub inc { shift->{count}++ }
1;
use strict;
use warnings;

use Benchmark qw(:all);

use Audrey;
use Gugod;
use Ingy;
use Ikebe;
use Naoya;
use Batara;

my $inst  = {};
my $codes = {};

for my $pkg qw( Audrey Gugod Ingy Ikebe Naoya Batara ) {
    $inst->{$pkg} = $pkg->new;
    $codes->{$pkg} = sub {
        $inst->{$pkg}->inc;
    };
}
cmpthese(1000000, $codes);

以下結果。

            Rate Audrey  Gugod   Ingy  Naoya  Ikebe Batara
Audrey  110375/s     --    -9%   -91%   -92%   -92%   -93%
Gugod   121803/s    10%     --   -90%   -91%   -91%   -92%
Ingy   1250000/s  1033%   926%     --    -4%   -12%   -21%
Naoya  1298701/s  1077%   966%     4%     --    -9%   -18%
Ikebe  1428571/s  1194%  1073%    14%    10%     --   -10%
Batara 1587302/s  1338%  1203%    27%    22%    11%     --

大体よそおどおりでしょうか?Spiffyはソースフィルタリングしてるので他と肩を並べる速度になってますね。

12/28 21:02追記:すんげー色々ポカってたのでちゃんとやり直しましたorz yasu++

Posted by Yappo at 20:44 | Comments (2) | TrackBack

2007年12月26日

Class::Componentから見たNEXT問題

ちまたで大ブームなNEXTキメェwwwwww問題ですが、Class::Componentを半年作って来て感じた事を

Class::ComponentにもClass::C3っぽい挙動をするNEXTメソッドを内蔵しています。
違和感ありますよね?NEXT.pmとかClass::C3とかを使ってるんじゃなくて、内蔵ですからね。
何でかって言うとClass::Componentは、利用する側に対して必要最小限の干渉しかしないというポリシーで書いてあるので、Class::C3とかを使ってないのです。
ソース見ればわかりますが、Class::C3を使うとnextという名前空間をこっそりと追加してたりするので、それを避けたかったのです。
Class::Componentのソースを見ればわかる通り、徹底的に不要な物を隠そうとしてる為ごちゃごちゃしたコードになってます。

ここまでがClass::Componentの事情の話、ここからはClass::ComponentとNEXTの付き合い方について。

Class::Componentは単体では何もやってくれないモジュールで、use Class::Componentしてからモジュールを作った時に初めて役に立ってくれます。
大まかに言うとClass::Componentを使うモジュールには3人の関係者が発生します。

  1. Class::Component作者
  2. Class::Componentを使ったMyAppというモジュールの作者
  3. MyAppの利用者

MyAppでNEXTを使う局面としては、MyApp::Component::*以下の名前空間で実装されたモジュールで使う事が多いでしょう、ここはCatalyst::Plugin::*と役割的には同等なのです。
MyApp::Plugin::*以下は、Plagger::Plugin::*のそれと近くNEXTが使えません。

だんだん答えが近づいて来ましたが、Class::Component的NEXTの作法としては、MyAppの作者がNEXTを多用するMyApp::Componentの管理や作成に責任を負い、MyAppの利用者はMyApp::Pluginのみ弄れる様にします。

CatalystやDBICの混乱をみるとNEXTを実行する場所が、それぞれ好き勝手にやっていて混乱してしまっているので、Class::ComponentではNEXTを使ったMyApp::Component::*を弄れるのはMyApp作者が全責任を追う事で混乱を防ごうという訳です。

もっというとClass::Component::Component以下(MyApp::Component以下も同義)はClass::Componentを利用したモジュールの作者の為に有るという事ですね。
Pluginは、最終的な利用者の為の選択肢を広めるためにあって、Class::Componentを利用するモジュール作者の利便性を上げる為にある。
Attributeに関しては省く。

MyApp利用者側はHookとかを活用すればMyApp::Componentを弄れなくても困る事は無い筈なので、こんなポリシーでもいけると思います。
要するにClass::ComponentではNEXT以外の方法を提供してるのでCatalyst等の様にNEXT地獄に堕ちる必要が無い訳ですね。

Posted by Yappo at 13:24 | Comments (0) | TrackBack

2007年12月20日

ShipItつかわなくて良いのは小学生まで

超クールな CPAN リリースツール 1 選。ShipIt がスバラシイ件 - TokuLog 改め だまってコードを書けよハゲが火種になってるけど、今ShipItが熱い!
という事でちょっと前からShipItに移行してます。 一昨日辺には、オレオレpmsetupもplaggerからコピペしてきたリリースツールを消してShipItしてます。
http://coderepos.org/share/changeset/3295

結構どうでも良いBKがあって、cpanに上げる時にShipIt::ProjectType::Perlを利用してperl Makefile.PLするフェーズがあるのですが、ShipIt::ProjectType::Perl::MakeMakerの実装を見てわかるとおり

sub prepare_build {
    my $self  = shift;
    system("perl", "Makefile.PL") and die "Makefile.PL failed";
}
とかなってるんですよね、要するにperl5.10とかを/usr/local/perl5.10.0/bin/perl とかに置いていた場合には、5.10のperlコマンドを使ってくれない。

そんな感じなので、danをshipitする時にはひと工夫をして(5.9.5以上じゃないとmakeできない)

PATH=/usr/local/perl5.10.0/bin:$PATH shipit
してあげて先に5.10のperlを見つける様にして動かしてあげて解決。
shipitは基本/usr/bin/perlから起動されるので5.10の環境にShipIt入れなくてもうまくいきます。

ちなみにShipItはsoftware release toolという要約の通りCPAN以外へのリリースも出来ます。
標準だとCPANしか無いけどShipIt::Step以下の名前空間にモジュールを置いていけば色々と拡張できます。
皆が大好き跳ね込むが色々うpってるので参考にどうぞ。

JSとか、そういうののリリースツールとかで使うと面白げ

Posted by Yappo at 14:14 | Comments (0) | TrackBack

2007年12月19日

perl 5.10 and perl 20 years old

perlが20歳になったのと、5.10.0がめでたくリリースされたので、お祝い代わりにdanをCPANにuploadしました。

くわしい説明はYappoLogs: dan - リテラルとかを読まなくなるプラグマ作ったにて

Posted by Yappo at 18:22 | Comments (0) | TrackBack

2007年12月12日

overloadのreblessとRHLのoverloadが遅いパッチ

fbis++
overloadと再blessの問題 - Unknown::Programming

でも現状の対策としてはどうすればいいのかちょっと思いつかないですね。リファレンスを捜索してoverloadフラグを立てる、なんてことをするモジュールとか作れるのかしら・・・。
この段落を見て全てが繋がった!
fbisすげーよ!まじすげーよ!

以前騒がせたFedoraCoreやCentOS系の遅いPerlのパッチの件で、overloadすると極端に遅くなるって話題ですが、問題のpatchのコメントに注目すると

This is a hack cope with reblessing from class with overloading magic to one without (or the other way).
まさしく、今回id:fbisが指摘した事へのパッチだった訳ですね!

長年の疑問がすっきり解消しました!
で、v5.9.4から解消されたという事で、もしや?と思ってv.5.10.0RC2で調べてみました。

$ perl /tmp/overload.pl 
Benchmark: timing 1000000 iterations of not overload, overload...
not overload:  2 wallclock secs ( 1.51 usr +  0.00 sys =  1.51 CPU) @ 662251.66/s (n=1000000)
  overload:  1 wallclock secs ( 1.48 usr +  0.00 sys =  1.48 CPU) @ 675675.68/s (n=1000000)
おお!変わってない!

Posted by Yappo at 19:44 | Comments (0) | TrackBack

2007年11月08日

dan - リテラルとかを読まなくなるプラグマ作った

何を言っているのか解らないとは思いますが、use danをするとそれ以降の""とか''やq{}とかとかで囲まれた文字列を全て読まなくなります。

  use dan;
  print "foo"; # not displaying
  no dan;
  print "foo"; # foo
こんな感じで、use danからno danの間にあるもの全てを読まなくなります。
正規表現だろうがqwの中身だろうがヒアドキュメントだろが構わずです。
その他フィルタ的にも使えるので詳しくはソースとか読んでみて下さい。
サンプルは
テストを見るべし。 ちょっとしたアーミーナイフ的で素敵です。
use orz的に考えてもらえると嬉しいです。

なんだかuse utf8してると、hint bits的にdanの処理がうまく行かないのでforceモード付けて、use utf8環境でも動くようにしました。
svn co http://svn.coderepos.org/share/lang/perl/dan/trunk dan
して、どうぞご利用ください。

ちなみに誰からも止められなければperl 5.10のリリースされた日に、これをCPANにうpる

Posted by Yappo at 23:31 | Comments (1) | TrackBack

2007年11月06日

GunghoっていうWebクロウラーたんの件

なんか男前そうなクロウラーたんを発見したお

資料はhttp://www.slideshare.net/lestrrat/gungho-swarmage-pocomdba/を見るべし。

ちなみに、これ書くのに使ったGunghoはVersion 0.09001 のCPANの。

概要

GunghoはPlaggerっぽいwebクロウラーたんです。なのでGunghoの名前空間以下にあるモジュールとかを個別に使おうとしたら大変です。
Gunghoのアーキテクチャにそった一本道な動作をさせるのがいいはず。
設定はConfig::Any使ってるので、色んな形式のを使えます。

Providerにより収集URLを取得し、EngineがHTTPでコンテンツを取得し、Handlerで取得したコンテンツを処理します。 Provider,Engine,Handlerは、それぞれ一つづつしか選べません。
まぁよくあるとおり、Gungho::Component以下のにあるやつとか+つきのcomponentを自由にGunghoに継承させれます。Pluginってのも追加出来ます。
おまけにLogってのも選べます。

Engine

EngineにはPOE,brad,IO::Asyncが選べます。どれも非同期なやつですね。
EngineはGunghoからrunメソッドにcontextを引数として起動されます。そのまえにsetup処理も入るけど。
とにかくrunから先はengineさんの好きにしても良いです。
でもやんなきゃいけない事は、runされたらcontextのdispatch_requestsを呼び出して下さい。 これはGungho::Component::Coreに居ます。

何をするかと言うとProviderのdispatchメソッドさんを呼び出します。
こいつが、URLをGungho::Requestにラッピングされてるオブジェクトを延々とcontextのsend?requestメソッドに投げます。
そしてPluginとかでdispatch.dispatch_requestsフックの処理とかをして、engineのsend_requestに送ります。
engineのsend_requestはローカルアドレスとかDNSがあるかとかを見てくれてます。

そしてengineのsrart_requestメソッドを呼び出します。
これは、まさしくhttpつかってコンテンツを取得する所です。
エラーがあるか、正常にコンテンツが取れるかに関わらず、engineのhandle_responseメソッドが呼ばれ、Gungho::Responseのオブジェクトとしてレスポンスをラッピングしてからcontextのhandle_responseメソッドを呼びます。
ちなみにbradとIO::AsyncはHTTPをGunghoが喋っていて(Gungho::Request::httpでrequest作成)HTTP::Parserで処理されたのをGungho::Responseに渡してる。

で、Coreのhandle_responseが呼ばれたら、とりあえずnextしてみてから、Handlerのhandlerメソッドに処理を投げます。
あとは、Handlerたんの実装しだいで好きにしてね。

なんか良くわからないけど、engineによって呼ばないhookがある。
あとあと、なんでdmaki wareなのにGungho::Handler::Swarmageがないのかが謎。

IO::Asyncつかうと何かエラーでた。

Cannot operate on a notifer that is not read-bound to a handle with a fileno at /usr/lib/perl5/site_perl/5.8.5/Gungho/Engine/IO/Async.pm line 138

Danga::Socketはなんあか起動に時間かかり過ぎで家の環境だとうまくいってなす。たぶん家のDNSのせいっぽいけど。結局POEか。

Provider

処理するリクエストを扱ってくれるマシン。
dispatchが呼ばれたらcontextのdispatch_requestメソッドにGungho::Requestなオブジェクトを投げ続けます。
engine君はループで延々とdispatchを呼んでくるので、辞めたくなったらcontextのis_runnningに0をあげるとengine君は止まります。

pushback_requestがたまに呼ばれます。
なんらかの事情によりリクエストを最初からやり直したい時とかに、やり直したいリクエストが渡されるので、各Providerでリクエストプールかなんかに戻してあげて、dispatchが呼ばれた時に、それをまた投げてあげて下さい。
POE使ってる時はタイミングによってはis_runningが0になっちゃってリクエストが処理されない気がするけど泣いちゃ駄目。確かにPOEでRobotRules使うとタイミング次第でだめぽ。

Handler

このくらいはソース読め

面白いComponent達の挙動

RobotRules

robots.txtを持ってなければ、requestをpendingリストに突っ込みrobots.txtを取って来るrequestをpushbackする。
robots.txtを取れた時にpendingリストに入れられたrequest全てをpushbackする。
storageにmemcachedとか使えるけど、いづれにしろ非同期。

で、うごかねーーとか思ってたら、Gunghoのtestが/tmp/robots.dbにテストファイルおきっぱなしで消してなかったorz

BlockPrivateIP

Danga::SocketかIO::Asyncをengineしてる時に、これ使ってないと血を吐いて死ぬ。

Authentication

認証付きのURLをクロールするには必須。

Throttle::Domain

Data::Throttlerというモジュールを使って、一つのドメインに対するリクエストを特定期間の間に特定回数しか行わないようにできる。
なので、例えば1時間のうち100回までしかアクセスしない。と設定してもGunghoは一気にリクエストがきたら1秒間に100回アクセスする。
十数秒/1回がベターか?それかネスト出来ると良いかもね。
なにはともあれData::Throttlerってモジュールが面白いよ!

どっちかって言うとAレコード版も欲しいってか簡単だから作ろうかな

Componentで使えるメソッド達

基本Gungho::Component::Core見ろ。

setup

初期化フェーズ。初期化したければここかいてnextれ。

send_request

リクエスト前になんかやる。RobotRurles見ろ。

handle_response

リクエスト後になんかやる。RobotRurles,RobotsMETA見ろ。

hook points

たぶん色々変わりそうだから略

Posted by Yappo at 23:42 | Comments (0) | TrackBack

2007年10月04日

Class::Component の連載はじめました

gihyo.jp で Class::Component に関する連載をはじめました。

第1回目は、Perlでプラガブルモジュール作ってみよう、ということと、Class::Component がどういったモジュールなのか、その概要について書いています。

この連載を一通り読めば、Class::Component をモジュール開発の現場で活用するための十分な知識が得られる、といったものを目指しています。

分かりにくいなどご意見ございましたら、ぜひお知らせください。

1週間毎に更新予定です。

Posted by Yappo at 13:17 | Comments (0) | TrackBack

2007年09月11日

Re: Class::Component::Plugin の init()

なんだかんだしてたら返事が遅れて超亀レスで申し訳ないですが

sexさんのsubtech - sexさんのブログ - Class::Component::Plugin の init()

init() っていうメソッドがたぶんabstract methodとしてあるっぽいんだけど、その中でなにも渡ってこないのが悔しい><

との事ですが、どうせcallとかrun_hookで呼ばれる時にはMethod,Hookなメソッドにはcontextが渡されるので、要らないかな?というのと
今となってはDisableDynamicPluginを使うと、pluginのinitを呼ばれるタイミングでは、大元のpackageのインスタンスが出来てないので$contextをinitに渡せないという理由があったりします。

やるとすればComponentとしてnewした時にpluginを初期化する処理とか実装したほうがいいのかなぁ?と
例えば以下のようなComponentを用意して

package Class::Component::Component::PluginSetContext;
use strict;
use warnings;
use Scalar::Util ();

sub new {
    my $class = shift;
    my $self = $class->NEXT( new => @_ );

    for my $plugin (@{ $self->class_component_plugins }) {
        $plugin->{context} = $self;
        Scalar::Util::weaken( $self->{ context } );
    }

    $self;
}

package Class::Component::Plugin;
sub context { shift->{context} }
1;

これをload_componentsすれば、元記事でやりたい事は一応できます。

使い方のサンプルとしては

package OIOI;

use strict;
use warnings;

use Class::Component;
__PACKAGE__->load_components(qw/ PluginSetContext /);

sub hello {
    my $self = shift;
    print $self->{hello} . "\n";
}

1;

package OIOI::Plugin::Hoge;

use strict;
use warnings;
use base 'Class::Component::Plugin';

sub hoge :Method {
    my($self, $c) = @_;
    $self->context->{hello} = 'hoge';
}

sub uge :Method {
    my($self, $c) = @_;
    $self->context->{hello} = 'uge';    
}

1;

use strict;
use warnings;

use OIOI;

my $oioi = OIOI->new({ load_plugins => [ qw / Hoge / ] });

$oioi->call( 'hoge' );
$oioi->hello; # print "hoge\n";

$oioi->call( 'uge' );
$oioi->hello; # print "uge\n";

こんな感じです。

まだまだ、手をつけなきゃいけないところもあるし

とか、他にもいろいろしたいよ!

という要望。

という事なので、もっと色々聞かせていただきたく。

CodeRepos行き?

Posted by Yappo at 22:21 | Comments (0) | TrackBack

2007年09月07日

Gopper - Gopher2.0時代のプラガブルGopher Serverをリリース

空前のGopherブームが到来したわけですが、PlaggerやMoxyのようにプラガブルに機能を拡張できるGopher Serverを書きました。
http://coderepos.org/share/browser/lang/perl/Gopper/trunk
svn co http://svn.coderepos.org/share/lang/perl/Gopper/trunk Gopper

今のところ超シンプルなGopher Serverにしかなりませんが、Pluginを書いて行く事によりApacheっぽいhttpdになったりします。
configなんかもPlaggerさわってる人なら判りやすいはず。

global:
  log:
    level: debug

  engine:
    module: Simple
    config:
      host: example.org
      port: 70

plugins:
  - module: Setuid
    config:
      user: nobody
      group: nobody

  - module: Protocol::Gopher

  - module: Handler::Static
    config:
      docroot: /foo/bar/example/docroot

プラガブルな機構はClass::Componentをそのまま利用しています。
なので、Component追加とかAttribute追加とかまで労せずできます。
Class::Component標準のrun_hookは、ちょっと細かいニーズに耐えられないので別途実装しました。run_hookを拡張する仕組みをClass::Componentに入れた方がいいのかしら。

パッチ書いたりプラグイン追加したい方は、CodeReposのコミット権さえあれば誰でも開発の参加が可能なのでCodeReposに参加してくださいな。

ちなみにGopherだからってXHTML原理主義とかとは無縁というわけではない。
gopher://yappo.jp/h/shinjukujs.html
こんなリッチなアプリケーションだって書けるのだ。

ところでFirefoxで70番以外で上がってるgopherのみかたありませんか?><

Posted by Yappo at 11:31 | Comments (0) | TrackBack

2007年08月03日

bradとmyとuse fieldsとPseudo-hashesとHash::Utilと

bradプロダクトではuse fieldsが多用されています。そして、

my ClassName $var;
のような変数宣言が多用されています。
perldoc -f myしてみるとuse fieldsで使うみたいな事が書いてありました。
use fieldsってのは
package Jitensya;
use strict;
use warnings;
use fields qw/(sound);

sub new {
    my $proto = shift;
    my $self  = ref $proto ? $proto : fields::new($proto);
    $self;
}
1;
のようなコードがあるとして
use strict;
use warnings;
use Jitensya;

my $hatena = Jitensya->new;
$hatena->{sound} = 'わいが近藤や';
$hatena->{dog}   = 'しなもん';
という使い方をした時に、$hatena->{dog}のところでfieldsで宣言されてないからエラーが出るという物です。

で、冒頭の

my ClassName $var;
の件ですが、このuse fieldsされたpackageがuse baseとかで継承された時に役立つようです。
たとえば、以下のpackageが在る状態で
#はてなスタッフを表す
package Hatena;
use strict;
use warnings;

use fields qw(jkondo naoya kawasaki);

sub new {
  my Hatena $proto = shift;
  my $self = ref $proto ? $proto : fields::new($proto);
  $self->{jkondo}   = 'syatyou';
  $self->{naoya}    = 'CTO';
  $self->{kawasaki} = 'fukusyatyou';
  $self;
}
1;
# はてなユーザを表す
package Hatena::User;
use strict;
use warnings;
use base 'Hatena';

use fields qw(yappo);

sub new {
  my Hatena::User $proto = shift;
  my $self = $proto->SUPER::new(@_);
  $self;
}
1;
下記のコードを走らせた時はエラーもなく動きます。
use strict;
use warnings;
use Data::Dumper;

use Hatena::User;

my $jitensya = Hatena::User->new;
$jitensya->{yappo} = 'gennin';

warn Dumper $jitensya;
しかし、Hatena::Userのオブジェクトを受け取る$jitensyaの前にHatenaという指定を追加すると。。。
use strict;
use warnings;
use Data::Dumper;

use Hatena::User;

my Hatena $jitensya = Hatena::User->new;
$jitensya->{yappo} = 'gennin';

warn Dumper $jitensya;
Javaとかのtypecastみたいに、一時的に別の名前空間のfieldsにする(継承元の名前空間に固定する)みたいな事をするんだと思います。
この例では、Hatenaは、はてなスタッフだけがいるpackageなので、はてな社員でないyappoに値を入れると怒られます。

bradプロダクトで見かける

            my Perlbal::BackendHTTP $self   = shift;
            my Perlbal::HTTPHeaders $hd     = $self->{res_headers};
            my Perlbal::ClientProxy $client = $self->{client};
            my Perlbal::HTTPHeaders $rqhd   = $self->{req_headers};
のmyの後にpackage名を書くのは、こういうことからなのかなぁと。

実は、fieldsを使わなくてもハッシュのキーの制限は出来て

my $hash = [{ boofy => 1, sledge => 2 }];
$hash->{boofy}  = 'mixi';
$hash->{sledge} = 'livedoor';
$hash->{'catalyst::shanon'} = 'shanon'; # error
みたいに出来ますが、perl 5.9からは使えなくなります。
配列の一項目目ハッシュリファレンスだったら制限付きのハッシュになるそうで、これをpseudo-hash(仮想ハッシュ)と言うそうです。

perl 5.9からどうすればいいかというと、Hash::Utilを使います。

use Hash::Util;
my $hash = {};
Hash::Util::lock_keys(%$hash, qw/ boofy sledge /);
$hash->{boofy}  = 'mixi';
$hash->{sledge} = 'livedoor';
$hash->{'catalyst::shanon'} = 'shanon'; # error
と書けます。これは5.8でも使えるので、今から仮想ハッシュしたければHash::Util使えばおkっぽい。

use fieldsも5.9以降からはHash::Utilを使って実装されていますが、なぜかfields::phashが使えなくなってます、Hash::Util使えば実装出来るのになんで削除されるんだろう。

Hash::Utilの実装を見てるとInternalという名前空間の関数使いまくりなんですが、これの資料がどこにあるかが解らない。

と、つい最近知ったばっかりの仕様についてだらだら書いてみました。
応用すれば5.8環境でhash版のuse strict 'vars'もどきが書けそうですね。

Posted by Yappo at 19:56 | Comments (13) | TrackBack

2007年07月31日

Soozy Conference #2 と naoyaさんへの返事

Soozy Conference #2でid:naoyaへの返事というタイトルで発表をして来ました。

内容としては
naoyaグループ - naoyaの日記 - Class::Component
naoyaグループ - naoyaの日記 - Class::Component#2
という、二つのClass::Componentに関する質問への返事+αとなっております。
資料は矢印キーでページ操作出来ます。Firefoxでしか動作確認してません。

あいかわらず皆さんの発表内容は高クオリティで、とても勉強になりました。
みなさん、お疲れさまでした。

Posted by Yappo at 17:43 | Comments (0) | TrackBack

2007年06月22日

encoding::sourceをperl5.8系で動かす

ことの発端はmiyagawaさんの

というわけで上記のような問題になやまされずにリテラルをソースに書くことが出来そう。5.9 からバックポートされたのかなぁ、と思ってソースをみると思いっきり use 5.9.5 が。5.10 のリリースがまたひとつ待ち遠しくなったなぁ。

から

なんで5.9から?

encoding:sourceのソースを見てみると5.10の新演算子//が使われていた。のでまずはdefined使いまくりでソースを書き換えたけど上手く動かない。よく見ると

my $hinthash = (caller($level))[10];

なるコードがある、callerの戻り値のリストは10個しか無い筈なのに11個目を取ってる。
調べてみると、5.10からの仕様でperlpragmaなるドキュメントがある。
callerで指定した呼び出し元のhinthashを取得出来る物らしい。

$^Hと%^H

$^Hはおなじみのuse strictとかでも使用されている、インタプリタに特殊なフラグを渡す為に使われる変数です。
%^Hなんですが、あまり使われてない(overloadとかで使ってる)ソースのコンパイル時に役立ちそうな情報を保存しておく場所みたいな使われ方です。
どれもBEGINのフェーズで活用されます。

なんでBEGINかって言うと、コンパイルフェーズ中にhintを見てコンパイラが色々挙動を買えてくれるので、BEGINフェーズが終わると値が変になる。

BEGIN {
    $^H{hoge} = 'aaa';
}
print $^{hoge};# BBBが表示される
BEGIN {
    $^H{hoge} = 'BBB';
}

こんな感じで普通に考えたら違和感の在る事になる(そういうもんだけどね)

でperlvarを見ると%^Hはレキシカルスコープを抜けたら元に戻る的な事が書いてあったんだけど、これをやるには$^Hで特定のビットを立てなきゃいけないoverload.pmとか見るとわかると思う。

(caller(x))[10]

で、さっきの11個目の値というのは

BEGIN {
    $^H{hoge} = 'aaa';
}
sub c {
    my $hinthash = (caller(0))[10];
    print $hinthash->{hoge};# aaaが表示される
}
c();
BEGIN {
    $^H{hoge} = 'BBB';
}

って事をやってくれる。
5.9.4だと上の上のコードのprint $^H{hoge}で、値が取って来れなくなってた。
perl 5.8系だとこれが使えないから意図した動作にならないわけです。

とりあえずパッチ作った

意図した通りにはならないけど、caller使わず%^Hだけを駆使してパッチを書いてみた
http://tech.yappo.jp/download/encoding-source-0.02_v58.patch
とりあえず一通りのケースで動くけどpackとかで上手く動かない。なんで買って言うとリテラルのencodingはBEGINフェーズ中に行われているので%^Hが上手く活用されるんだが、変数に入ったデータとかをdecodeしようとする時(pack)はBEGINが終わって通常のフェーズ中で処理されるおで%^Hが取れなくなるわけ。

hioさんも5.8で動くのを作っていて、そっちはソースフィルタを使ってcallerの件を上手く回避してます。さすがです><

今後

とりあえず呼び出し元のレキシカルスコープを細く出来るモジュールをXSで書いて、それを使って上手い具合に5.8で動かせる様にしたいす。

Scope::Stash (Lexical::Stash ?)

これは、呼び出し元のx階層上のスコープに特定の値をメモします。例として

use Scope::Stash;

sub hoge {
    print Scope::Stash->get(0, 'hoge');# 出力しない
    Scope::Stash->set(0, hoge => 'boofy');
    print Scope::Stash->get(0, 'hoge');# boofy
    {
        print Scope::Stash->get(0, 'hoge');# boofy
        Scope::Stash->set(0, hoge => 'mixi');
        print Scope::Stash->get(0, 'hoge');# mixi
    }
    print Scope::Stash->get(0, 'hoge');# boofy
}
print Scope::Stash->get(0, 'hoge');# 出力しない

こんな動作をするモジュールをどうにかして書こうかなぁと

PadWalkerのXSコードを見るとpads_into_hashの中のCOP_SEQ_RANGE_(LOW|HIGH)辺りを参考にすれば、補足出来そうな気がする。
呼び出し元のcos_seqを探して来てHIGHの値までに紐づく様にデータ保持しておいて、上書きが合ったら上書き前のcos_seqを、上書き呼び出し時のcos_seqに書き換えてみたいな構造で。
これを%^Hの変わりに使う策略。

%^Hと同期も取れる様にScope::Stash::Hinthashってのも作っておくと良いのかな?
プラグマパッケージのimport/unimport中ならScope::Stash::Hinthashを普通に使うだけで上手く動く気がする。

ついでにhinthashって名前のpragmaも作っておくと、普通のプログラム上で操作出来る様になるから面白い事できる?

副産物

$^ENCODINGの使い方わかったお!



このへんの事は体で理解している弾さんに添削されたい><

Posted by Yappo at 17:57 | Comments (0) | TrackBack

2007年06月12日

Class::Component - プラガブルなモジュールを作る為のベースモジュールの解説

pluginやcomponentを取り扱うモジュールを書く時に、plugin/componentを取り扱いを全て引き受けてくれるモジュールを作りました。
だいぶ前からCPANには上げてたんですが、色々あって今日報告と。

既出のアイディアとしてはid:naoyaの Class::Pluggableid:ya_kenの Class::Pluggable等があります。

これらのモジュールもシンプルでいい感じなのですが、シンプルな分、若干物足りなさがあった(例えばメソッドの生やし方に自由度持たせたいとか)のでこしらえました。
詳しくはCPANのClass::Componentにもありますが日本語でも説明文書きたい。

出来る事

  • component追加で基本メソッド拡張が出来る
  • plugin追加で、hook pointへのhook処理追加や、pluginメソッドを追加出来る
  • pluginで追加するメソッドの実装方式(普通にメソッド生やす、AUTOLOAD、SingletonMethod)を選べる。選ばなければメソッド生えない
  • Class::Componentを使ったオブジェクトをYAML::DumpとかしてもYAML::Loadすれば普通に動く
  • Plaggerっぽくconfigを渡すとpluginまで設定が渡される
  • pluginはattributeを使い、sub jitensya: Method {} のように書くだけでメソッド追加出来る
  • Class::Component::Attribute::以下にモジュールを追加すると、任意のattribute処理が出来る
  • 作ったモジュールを、さらに別のモジュールで継承する事も可能
  • その場合のPluginの名前解決方法はClass::C3っぽい順番で解決する
  • Class::C3の再発明

影響を受けたもの

Class::Component::Attribute::*に追加してpluginで使うattributeを拡張できるようにするのはCatalystから。
Class::Component::Pluginに書いてあるAttributeを集める仕組みはClass::DBIxから
configやhookなどはPlaggerから

Component

いわゆるCatalystのPlugin方式に拡張します。
単純に@ISAにパッケージを突っ込んで行って継承ツリーを太らせます。
ここには、モジュールの動作に多大な影響を与える物を置いておきます。

Attributeを拡張した時に、呼び出すメソッドなんかはComponentで。

Class::Componentには、標準でComponentが4つ付いて来て最低限の挙動をチョイス出来ます。

DisableDynamicPlugin
blessされたobjectからはpluginを追加出来なくします。__PACKAGE__->load_pluginsやMyClass->load_pluginsの形でしか追加出来なくなります。
後述しますがClass::Componentはblessされたオブジェクト別にpluginを管理出来るのですが、この機能をOFFにします。
若干new時のコストが押さえられます。
Autocall::InjectMethod
*{"$pkg::$method"} = sub {}な形で、pluginのメソッドをパッケージに割り当てます。
これやるとオブジェクト毎にメソッド管理出来なくなりますがシンプルです。
Autocall::Autoload
AUTOLOADを使ってオブジェクト毎に使えるメソッド名を判断して処理出来ます。
Autocall::SingletonMethod
その名の通りです。id:naoya氏の実装に近いです。
これはDisableDinamicPluginとの併用が出来ません。
どっちにしろ相反するcomponentではありますね。
Autocall::*の何れかを利用すれば$obj->plugin_methodの形で呼び出せますが
一切利用しないと$obj->call( plugin_method => options ... )の形でしか呼べなくなります。

AutoloadとSingletonMethodはg:id:naoya:Pluggableの話の時のSingletonMethodなの