首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Sinatra请求对象

Sinatra请求对象
EN

Stack Overflow用户
提问于 2013-05-15 05:22:52
回答 1查看 1.8K关注 0票数 3

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

Sinatra

代码语言:javascript
复制
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

应用程序

代码语言:javascript
复制
class App < Sinatra::Base
  get '/' do
    puts request
  end
end
EN

回答 1

Stack Overflow用户

发布于 2013-05-15 09:34:04

哇。你激起了我的好奇心,果然,研究这件事是虚情假意的。神奇之处在于在https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1529中定义的compile!方法

代码语言:javascript
复制
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_routehttps://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L971

代码语言:javascript
复制
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

这里发生了很多事情,但关键是:

代码语言:javascript
复制
block[self, values]

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16553091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档