为什么Sinatra会复制路径的方法块?

时间:2011-11-29 16:04:44

标签: ruby methods sinatra

这是关于Sinatra处理路线方法的前一个问题的一个更集中的版本。

根据我对源代码的理解,Sinatra在路由中获取方法块,并传递一个包含相同主体的新方法,即:

get "some/url" do 
   return "Hello World" # this gets taken out
end

因此,在此示例中,方法体似乎被复制到应用于Sinatra对象的新方法中。我只是想知道为什么会这样,我试着去他们的IRC频道,但没有人在那里,邮件列表并不那么繁忙。

我在他们的框架中讨论的主要代码是在1180行的base.rb中:

  def generate_method(method_name, &block)
    define_method(method_name, &block)
    method = instance_method method_name
    remove_method method_name
    method
  end

那么为什么他们这样做而不只是引用方法本身有什么具体原因?

我问这个问题的原因是因为Sinatra目前处理这个问题的方式使得它不可能拥有一个具有自身知识的方法,并且通过仅采用一个没有上下文的方法来打破类封装。

3 个答案:

答案 0 :(得分:4)

如上面的评论所示,这会产生一种方法。一个合适的方法。如果Sinatra不会在generate_method中再次移除该方法,您实际上可以通过执行send("GET some/url")之类的操作来调用它。问题是,为什么Sinatra会再次删除此方法?很简单,每条路线可能有多个处理程序:

get 'some/route' do
  pass if request.referrer == '/foo'
  "didn't come from /foo"
end

get 'some/route' do
  "did come from /foo"
end

两种方法都有相同的名称。

关于你对子类和方法的评论,这应该有效:

class MyApp < Sinatra::Base
  def content
    return "did come from /foo" if request.referrer == '/foo'
    "didn't come from /foo"
  end

  get('some/route') { content }
end

或者,在做一个经典的应用程序时:

helper do
  def content
    return "did come from /foo" if request.referrer == '/foo'
    "didn't come from /foo"
  end
end

get('some/route') { content }

答案 1 :(得分:3)

我的猜测是他们希望为每个路由提供完整的方法(可以访问其他实例和类方法),但不想污染命名空间。方法名称生成为"#{verb} #{path}",因此,例如,如果您有多条路径具有相同路径的不同条件,则冲突是不可避免的,除非您在定义并将其存储在其他位置后立即删除方法。而这正是他们所做的。方法是未绑定的,但它不是问题,因为它们稍后可以将它绑定到类的任何实例。

注意,这只是猜测。我对Sinatra并不熟悉,所以这个实现背后可能有完全不同的想法。

答案 2 :(得分:0)

我猜它只是模拟instance_exec来支持早于1.8.7的Ruby