Sinatra请求对象

我可能在这里遗漏了一些非常明显的东西,但我似乎无法找到答案,或者自己解决这个问题。 在Sinatra中,他们有一个self.get方法,它捕获块,当一个块被调用时,你可以在里面使用request变量,这怎么可能?

西纳特拉

 module Sinatra class Base class Request < Rack::Request end attr_accessor :request def call!(env) @request = Request.new(env) end class << self def get(path, opts = {}, &block) ... end end end end 

应用

 class App < Sinatra::Base get '/' do puts request end end 

哇。 你激起了我的好奇心,果然,研究这个很有吸引力。 魔术从compile!开始compile! 定义的方法: https : //github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1529

 def compile!(verb, path, block, options = {}) options.each_pair { |option, args| send(option, *args) } method_name = "#{verb} #{path}" unbound_method = generate_method(method_name, &block) pattern, keys = compile path conditions, @conditions = @conditions, [] wrapper = block.arity != 0 ? proc { |a,p| unbound_method.bind(a).call(*p) } : proc { |a,p| unbound_method.bind(a).call } wrapper.instance_variable_set(:@route_name, method_name) [ pattern, keys, conditions, wrapper ] end 

请注意,我们通过generate_method(在上面定义了几行)将传递给get (或任何路由函数)的块转换为未绑定的方法。 然后,我们存储一个proc,它接受两个参数,一个绑定方法的对象,以及一个参数列表,该方法被调用。

跳到process_route : https : //github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L971

 def process_route(pattern, keys, conditions, block = nil, values = []) route = @request.path_info route = '/' if route.empty? and not settings.empty_path_info? return unless match = pattern.match(route) values += match.captures.to_a.map { |v| force_encoding URI.unescape(v) if v } if values.any? original, @params = params, params.merge('splat' => [], 'captures' => values) keys.zip(values) { |k,v| Array === @params[k] ? @params[k] << v : @params[k] = v if v } end catch(:pass) do conditions.each { |c| throw :pass if c.bind(self).call == false } block ? block[self, values] : yield(self, values) end ensure @params = original if original end 

这里有很多,但关键是:

 block[self, values] 

这将使用self和相应的参数调用上面的存储块。 因此,未绑定方法绑定到process_route绑定的任何内容( process_route中的当前self )。 什么是process_route绑定? Sinatra::Base一个实例,我们知道它有一个属性访问器request ,现在可以在原始块中访问。 田田!