Possible可能な限りナマケモノでありたいタグ:HTTP::Engine2009年06月02日HTTP::Engineでテストそう言えばこないだのうどん屋のコードは一切テストを書かなかったけど、それはよろしく無い、まったくもって主義に反するし、RubyのときはちゃんとSpec書いたのにPerlのときは書かないだとかふざけてる、と思ったのでテストも書いてみることにした。テストだけど、HTTP::Engineにはちゃんとテスト用のインターフェースが用意されている。あと、テストリクエストを生成するモジュールもある。なんだ、じゃあ話は簡単だ。engineを作るHTTP::Engine::Test::Requestでrequestを作るengineのrunメソッドにテストリクエストを投げてやる返ってきたレスポンスをチェックするってことですね、わかります。素直に書いてみるコード量少ないのではっつけちゃおう。Udon::AppにGETリクエストを投げるテストはこんな感じ。request';ふむ、まぁ、簡単ですね!あとはこんな感じでどんどん$reqを作ってどんどん$engine->runしてやれば良い。Test::Declareところで、Test::Moreはまぁ見慣れてるんで使い方に迷うことは無いんだけども、普段からRSpecが大好きで勢いあまってObjective-CのテストにまでRSpecを使っちゃう僕としては少々見栄えが気に入らない。Test::Declareってやつを使ってみることにした。ようし、少し見栄えが良くなった。入ってるから気に入ったんじゃないんだから。えーとほら、こうして何に対するテストなのかの説明と順番とテストコードとがひとまとめになってた方がわかりやすいじゃん。?それは良いんだけど、setup_engineとかHTTP::Engine::Test::Request->newとかが今度は美しくない。このコードだと一個しか書いてないからまだあれだけど、「彼女が404」のSpecくらいに網羅しようと思うとちょっとげんなりする。そんなもん大体同じなんだから何度も書きたくないし、見にくい。Test::HTTP::Engineそう言えばRackのときはRack::Testを使ったら劇的にさっぱりした。同じ方法で解決してみれば良いんじゃなかろうか。と思い立って適当にこんなものを拵えてみた。1;で、これを使うとさっきのテストはこうなる。};};さっぱりした。テスト増やしたけどさっきより見易いし、そこはかとなくRSpec版に近付いた気がするぞ。あとはpostとかdeleteとかも作ってやればRack::Testでやったのと近いことができる。思い付きで作ったけど意外と良いな。テストも簡単だから怠けてないで書けよとというわけでApacheやServerSimpleでサーバプロセスを立ち上げたりしなくてもサクっとアプリのテストが出来ちゃって良いですね。こんな簡単なら最初からテスト書けよって言われそうですね。後でうどん屋のやつにもテスト追加しときますって。したほうがいかもーとのこと。Tweet2009年05月27日HTTP::Engineのミドルウェアを作ってみる先週末からこっちうどん屋をいじって遊んでたのだけど、HTTP::EngineにはHTTP::Engine::Middlewareというミドルウェアを作る仕組みもあるので、せっかくなのでUdonMap(Rack::URLMapもどき)をミドルウェアで実装してみた。GitHub前回の記事のときと構成が変わってるけど気にしない方向で。あとで前の記事直しとこう前の記事も補足した。Udon::Middleware::URLMapがミドルウェアで、server-middleware.plがミドルウェア版UdonMapを使って書き直したもの。ミドルウェア自体は簡単に作れた。HTTP::Engine::MiddlewareするとMooseの初期化処理をしたりミドルウェア用のメソッドを生やしたりしてくれるので、HTTP::Engineをnewするときに指定したハンドラより前に実行する処理を作りたいときは、before_handleでHTTP::Engine::Requestを受けとってHTTP::Engine::Responseを返す処理を書いてやればいいだけ。そのミドルウェアが処理すべきRequestじゃないときや、Requestを加工して次に渡したいときは、ResponseじゃなくてRequestを返してやると次のミドルウェアやハンドラに処理が渡る様子。あとモジュールの最後に__MIDDLEWARE__を書くのを忘れずに。これで後処理もしてくれる。厳密に言うと、before_handleの返す値がHTTP::Engine::Responseだったときに限り、そこでbefore_handleのループが終了する。次のミドルウェアに処理を回したいときは、別にHTTP::Engine::Requestを返さなきゃいけないわけではない。前のミドルウェアが返した値がそのまま次のミドルウェアもしくはrequest_handlerにリクエストとして渡るので、普通はHTTP::Engine::Requestかそれと同じ振る舞いをするオブジェクトを返すものだと思う。しないとミドルウェアを重ねられないし。その後request_handler、after_handleの処理へと続くんだけど、もしbefore_handleがあるのうちのどれかがHTTP::Engine::Responseを返してた場合はrequest_handlerは呼ばれない。after_handleはエラーでも出てない限りは呼ばれるし途中で止まることもない。after_handleを持ってるミドルウェアは全部実行される。ところで実はこれ自体はさくっと作れたんだけど、公開しようと思ってファイルの場所移してモジュールの名前変えたらいきなり動かなくなってちょっとだけハマった。最初に書いてたときはNetaKit::Middleware::URLMapって名前にしてたんだけど、UdonMap2って名前にすると何故か「before_handleだの__MIDDLEWARE__だの、そんなもんねーよ、アホか」とPerlさんに怒られる。なんじゃろ、と思いつつソース読んでるときにその理由に気付いた。HTTP::Engine::Middlewareをuseしてるやつのモジュール名の中にMiddlewareってのが含まれてないと、そのモジュールをミドルウェアとして初期化してくれない。HTTP::Engine::Middlewareなんだけど、importの中でいろいろと前処理してるので、何もしなければ使う側のときでもMooseの初期化したりbefore_handleを生やしたりしてしまう。モジュール名に制約を付けておけばよしなにやってくれるようにしてるんだろう。思ってたらちゃんとそう言ってるじゃん。いうわけでHTTP::EngineとHTTP::Engine::Middlewareの使い方がなんとなく分かってきたので、そろそろうどん屋と戯れるのは終わりにして、一通りWAFっぽい動きをするものでも作ってみようかな。Tweet2009年05月24日うどん屋のステータスを返すこのブログではまず滅多にPerlの話を書かないのだけど、実は仕事ではPerlばっかり書いてたりする。Mongerな方々にトゥシューズに画鋲を入れられたり机に花を飾られたりしてしまう(※)、ということで今週末はHTTP::Engineをいじってみることにした。Mongerはそんな陰湿ないじめはしませんし、Rubyistを公言してると社内で立場が危うくなるなんてことももちろんありませんし、そう言えばトゥシューズなんか履いたことないや。GitHub比較の為に「彼女が404」を作ろうかと思ったんだけど、そのまんま同じのを作ってもあんまり芸がないので「うどん屋が403」にしてみた。彼女のと同じくGET、POST、PUT、DELETEに対応しててそれぞれ違うレスポンスを返すので、適当にリクエスト投げてみてくだしあ。ファイルの構成はこんな感じ。UdonApp.pmうどん屋のステータスを返すアプリ。UdonMap.pmRack::URLMapもどき。パスとアプリを関連付けてアプリのhandle_requestを呼ぶ。要Path::Dispatcher。UdonHandler.pmUdonMapを呼ぶためのmod_perl2用のハンドラ。PerlSetEnvでAPP_BASE_DIR(必須)とAPP_LOCATION(任意)を設定できる。/perl」みたいにして使う。server.pl実行するとスタンドアロンでサーバ立ち上げる。改めB日記」を参考に直したもの。なんで最初からそう書かなかったのかと言うと、Macの方のPerlが5.8なので...。given-whenの方が好みだなぁ。server-urlmap.plserver.plをUdonMapを使うように直したもの。これが一番すっきりするかなぁ。いうかしないとUdonMapの意味無いけど。udon.cgiCGI。普通にApacheとかで動く。*.msnviewファイル。モジュールはUdon*.pmからlib/Udon/*.pmに、テンプレートは*.msnからview/*.msnに、スクリプトは*.plからbin/*.plに移動。Ruby版の挙動になるべくあわせるようにしようとして、わざわざURLMapもどきを作ってしまった。Path::Dispatcherの無駄遣いな感が否めない。本当はPath::Dispatcherはもっと色々できる高機能なディスパッチャなので、WAFを作るときはUdonMapにあたるところがディスパッチャでUdonAppがアプリケーションじゃなくてコントローラ、的な構成にすると思うけど、まぁRackのプチアプリとの比較ってことでその辺は御愛嬌。今思ったけど、これHTTP::Engine::Middlewareとかで実装すべきかしら。いうかすでにこんなのあったりしそう。Middlewareの方はちゃんと追えてないので後で。