Rack 概要

Rackイメージ図

rackup, config.ru イメージ図

基本は、 1 「call(env)を受けて[code, {header}, [body]]を返すオブジェクト」を 2 「server に渡す」

ということをやっている。

前者をappと呼ぶと、これを生成するにはいくつかやり方があって、

  1. def call(env) を実装したクラスを作り、new すること。
  2. Rack::Builder をnewし、そのオブジェクトをrun()で渡してあげる。Builderクラスは call()関数を持ち、run で渡されたオブジェクトに call() を移譲する。
  3. config.ru を使う方法。*.ru はDSLだが実質的にruby スクリプトで、これをeval or requireする関数が用意されている:app = Rack::Builder.parse_file('config.ru')

1.は、

class App
  def call (env)
    [200, {"content-type" => 'text/html'}, ['Hello World']]
  end
end
app = App.new

2.は、

app = Rack::Builder.new { 
  run App.new 
}
 # あるいは、
 # app = Rack::Builder.new; app.run(App.new);

rakeup は内部的に 3 をやっている。

こうして app オブジェクトを作ったら、server に渡してあげる: server.run(app, options)。使うサーバーによってハンドラーで切り分けて云々やってるけど、そこはお任せでいいでしょう。

app 内で、いちいちENV['REQUEST_METHOD'] とかやるのは面倒なので、Rack::Request, Response などが用意されている。

  • Rack::Request.new(env).request_method
  • res.write(str) で body への追加と content-length まで面倒みてくれる

んで、r.finish とすると、[code, {header}, [body]] と配列化してくれるので call() の最後に置く。

path_info のマッピングは、Rack::Builder の map() を使う。builder = Rack::Builder.new して、builder.map '/hoge' do; run App.new; end; と登録する。 builder.use Rack::Reloader すると動くかなと思ったらうまくいかない模様

んで、ここらへんの処理をいろいろ楽にしてくれるのが、sinatra なわけだ。