3

我知道 TOPLEVEL_BINDING 是 main 的 Binding 对象。以下代码证实了这一点:

def name
  :outer
end

module Test
  class Binder
    def self.name
      :inner
    end

    def self.test_it
      eval 'name', TOPLEVEL_BINDING
    end
  end
end

p Test::Binder.test_it # => :outer

在查看机架的来源时,我感到困惑。问题在于理解文件中的这段代码lib/rack/builder.rb

def self.new_from_string(builder_script, file="(rackup)")
  eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
    TOPLEVEL_BINDING, file, 0
end

def run(app)
end

new_from_string 方法传递 config.ru 文件的内容,该文件类似于

run DemoApp::Application

这里似乎 TOPLEVEL_BINDING 指的是 Builder 对象,因为该方法run是为 Builder 定义的,而不是为 Object 定义的。然而,前面的实验确定 TOPLEVEL_BINDING 指的是 main 的绑定。我不明白 run 方法是如何在这里工作的。请帮助我理解这段代码。

4

1 回答 1

2

TOPLEVEL_BINDING 顶级绑定。

该方法将字符串“run ...”传递给Builder.new { run ... }

Builder.new 然后在块上执行 instance_eval ( https://github.com/rack/rack/blob/df1506b0825a096514fcb3821563bf9e8fd52743/lib/rack/builder.rb#L53-L55 ),从而使块内的代码可以直接访问实例的方法。

def initialize(default_app = nil,&block)
  @use, @map, @run, @warmup = [], nil, default_app, nil
  instance_eval(&block) if block_given?
end

run是Builder类的实例方法,定义在这里-> https://github.com/rack/rack/blob/df1506b0825a096514fcb3821563bf9e8fd52743/lib/rack/builder.rb#L103-L105

def run(app)
  @run = app
end

简而言之,"run DemoApp::Application"变成:

Rack::Builder.new {
  run DemoApp::Application
}.to_app

编辑:一个简单的例子来说明这一点:

class Builder
  def initialize(&block)
    instance_eval(&block)
  end

  def run(what)
    puts "Running #{what}"
  end
end

TOPLEVEL_BINDING.eval "Builder.new { run 10 }"

印刷

Running 10
于 2013-11-05T08:12:48.363 回答