rackを読む #2

ミニマムなプログラムを動かす

コードを読む際は当然ながら、そのプログラムをどう動かすのかを知っていなくてはならない。
また、簡単なプログラムを用意して、動く環境をもつことが結構重要だったりする。
そこで、Rackのプログラムを用意してみた。
(via Redirect)

require 'rack/request'
require 'rack/response'
 
module Rack
  class HelloRackup
    def call(env)
      Response.new.finish do |res|
        res.write "Hello, Rackup"
      end
    end
  end
end

rackでは「.ru」を起動ファイルとする

require 'hello-rackup' #さっき作ったファイル
run Rack::HelloRackup.new
rack/bin $ rackup hello-rackup.ru

無事動いたはずだ。
 

まずはmainから

binの中のrackupを読んでみる事にする。
実際に.ruファイルを読み込んでいる所をまず見つけるべきだ。

if config =~ /\.ru$/
  cfgfile = File.read(config)
  #Stringの正規表現
  #読み込みファイルにあるオプション文言をparse実行
  if cfgfile[/^#\\(.*)/]
    opts.parse! $1.split(/\s+/)
  end
  
  #ここで.ruをevalかます
  require 'rack'
  inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", nil, config
else

気づいた方は分かると思うが、先ほどのruファイルに書かれていた、
"run Rack::HelloRackup.new"
というのはミニマムなDSLだ。
ブロックがここでevalされているので、Rack::BuilderクラスにDSLの内容が定義されていることになる。
 

main部を最後まで読んでみる

inner_appはどこで使われるのか?
最後の方に記述があった。

  #mini DSL
  #link to Rack::Builder
  app = Rack::Builder.new {
    use Rack::CommonLogger, STDERR  unless server.name =~ /CGI/
    use Rack::ShowExceptions
    use Rack::Reloader
    use Rack::Lint
    run inner_app
  }.to_app

#省略

#serverはWEBrickなど指定済み
server.run app, options

どうやらRack::Builder.new {} .to_appしたものをrunすることで、
WEBrickなどにデプロイするようである。
 

次回は

Rack::Builderを軸に読んで行こうと思う。
このクラスがrackの肝であり、一番おもしろい部分だ。