とりあえずRackのミドルウェアとして実装すればいいんじゃない?
最近Rackの上にごくごく簡単なフレームワークをSinatraも使わず組んでいるんですが, ミドルウェアが便利で, 仕組みもごくごく単純でステキだなぁとか思っているからとりあえずメモしておこうと思って久しぶりにブログを書こうとふにゃらららら.
仕組みから言えばフィルターとして動きます. たとえば:
use Rack::ShowExceptions use Rack::Lint run ExampleApp.new
ってミドルウェアを積むと, Rack::ShowExceptions#call(env) -> Rack::Lint#call(env) -> ExampleApp#call(env)と順番に呼ばれます. ただチェインしているだけですね. 素直な実装でボクうれしい.
つーコトでオプション的な機能は引数のoptionsとか設けて対応するんじゃなくて, Rackのミドルウェアに任せれば済むんじゃないか. 素直な実装というコトで, 簡単に作れました. 試しに行頭と行末のホワイトスペースおよび改行を削除するミドルウェアを書いてみた.
require 'rubygems' require 'rack' class Strip def initialize(app) @app = app end def call(env) status, headers, body = @app.call env body, content_length = strip body headers['Content-Length'] = content_length.to_s [status, headers, body] end def strip(body) content_length = 0 body.each do |s| s.gsub! /^\s+|\s+$|[\r\n]/m, '' content_length += Rack::Utils.bytesize s end [body, content_length] end end
あとはuse StripってしてあげればOK. 簡単だね.
ただミドルウェアを積む順番を意識するのはめんどうなので, @app.call(env)を必ず呼び出して, その結果を加工する程度のモノにした方がよさそうです. 試しにキャッシュ機能とか実装してみたんですけど, キャッシュがあった時点で後方のアプリケーションを呼び出さないので, 順番によって結果が変わる可能性があるからです.