rackを読む #5

to_appで生成されたObjの構造

例として二つのクラスのinitializeを挙げた。

  class ShowExceptions
    CONTEXT = 7

    def initialize(app)
      @app = app
      @template = ERB.new(TEMPLATE)
    end
    
    #省略
    
  class CommonLogger
    def initialize(app, logger=nil)
      @app = app
      @logger = logger
    end
    
    #省略

引数のappにはBuilder.to_appで説明した通り、
前のブロックで評価されたインスタンスが入ったり、run mapのインスタンスが入ったりする。
つまり、構造的には

#<Rack::CommonLogger
 @app=<Rack::ShowException
   @app=<...
     @app=<...
       @app=<...>>>>>

再帰的に@appが続く構造になっている。
 

WEBrick.run、WEBrick.server

      def self.run(app, options={})
        server = ::WEBrick::HTTPServer.new(options)
        server.mount "/", Rack::Handler::WEBrick, app
        trap(:INT) { server.shutdown }
        server.start
      end

runはデプロイを行う。
アクセスがHTTPReqestが来た時に実際に動くのは

      def service(req, res)
        #省略
        status, headers, body = @app.call(env)
        #省略

@app.callがHTTPレスポンスを実際に作る部分のようである。
@appというのは前述した構造をもつあれのことだ。
 

@app.call

Rack::ShowExceptionsのcallを見てみる。

  class ShowExceptions
    CONTEXT = 7
    
    def call(env)
      @app.call(env)
    rescue StandardError, LoadError, SyntaxError => e
      [500, {"Content-Type" => "text/html"}, pretty(env, e)]
    end

call内部で更に@app.callを行っている。
@appは再帰的構造をしていることは前述した通り。
つまり、このcallは再帰的呼び出しを行っていることになる。

# イメージ
# @app.call{|env| @app.call {|env| @app.call...}}
@app.call(env)

最終的な場所にはrunがあるはずなので、
そこまでにErrorがあればShowExceptionsなどが拾ったり、
CommonLoggerが拾ってLogをはいたりする。
runが無事走れば生成したHTMLResponseを返却し、WEBrickに渡すことになる。
 

終わり

終わり