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

发布于 2024-12-18 09:37:49 字数 693 浏览 2 评论 0原文

这是我之前关于 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 目前处理这个问题的方式使得不可能有一个具有自身之外知识的方法,并且通过仅采用没有上下文的单个方法来破坏类封装。

This is a more focused version of a previous question of mine around Sinatra's handling of route methods.

From my understanding of the source code Sinatra takes the method block within the route, and passes a new method containing the same body out i.e:

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

So in this example the method body seems to get copied into a new method which is applied to the Sinatra object. I am just wondering why this happens, I tried going on their IRC channel but no one was there, and the mailing list is not that busy.

The main bulk of the source code that I am talking about in their framework is within base.rb around line 1180:

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

So is there any specific reason why they do this and not just reference the method itself?

The reason I ask this question is because the way Sinatra currently handles this it makes it impossible to have a method that has knowledge outside of itself, and breaks a classes encapsulation by just taking a single method without context.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

颜漓半夏 2024-12-25 09:37:50

正如上面的评论,这会生成一个方法。一个正确的方法。如果 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 }

As by the comments above, this generates a method. A proper method. If Sinatra would not remove the method again in generate_method, you could actually call it by doing something like send("GET some/url"). The question is, why does Sinatra remove this method again? Simple, there could be more than one handler per route:

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

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

Both methods have the same name.

As to your comments about subclasses and methods, this should work:

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

Or, when doing a classic application:

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

get('some/route') { content }
御弟哥哥 2024-12-25 09:37:50

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

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

My guess is that they want to have full-fledged method (with access to other instance and class methods) for every route, but don't want to pollute namespace. Method name is generated as "#{verb} #{path}" so if, for example, you have multiple routes with different conditions for the same path collisions are inevitable unless you remove method right after defining and storing it somewhere else. And that's exactly what they do. Method is unbound, but it's not a problem as they can later bind it to any instance of the class.

Note, it's only a guess. I'm not that familiar with Sinatra, so this implementation can have entirely different idea behind it.

原谅我要高飞 2024-12-25 09:37:50

我猜它只是模拟 instance_exec 以支持 1.8.7 之前的 Ruby

I guess it just simulates instance_exec to support Ruby older than 1.8.7

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文