12

我正在使用 Spree,它广泛使用 Rails 引擎。我发现一个常见的模式是这样的。但是我无法理解这段代码。

class Engine < Rails::Engine 
  def self.activate
    ...
  end     

  config.to_prepare &method(:activate).to_proc
end
  1. .to_prepare做什么
  2. 运营商是做什么的&method
  3. 代码的整体效果如何?

非常感谢!

4

1 回答 1

43

&method(:activate).to_proc

最好一次消耗一件。(应该注意,这部分代码是 100%Rails 特定的 Ruby。)

method是一个 Ruby 方法(这都是非常元的)。因此记录在案

在 obj 中查找命名方法作为接收者,返回一个 Method 对象(或引发 NameError)。Method 对象充当 obj 对象实例中的闭包,因此实例变量和 self 的值仍然可用。

查看以下 IRB 会议:

ruby-1.9.2-p136 :001 > def my_method
ruby-1.9.2-p136 :002?>   puts "in my_method"
ruby-1.9.2-p136 :003?>   10
ruby-1.9.2-p136 :004?>   end
 => nil 
ruby-1.9.2-p136 :005 > method(:my_method)
 => #<Method: Object#my_method>

因此,method调用正在查找(在您的示例中)该activate方法并为其创建一个Method对象Method包含一个名为 的方法to_proc,它“返回与此方法对应的 Proc 对象”。继续我们的 IRB 会议:

ruby-1.9.2-p136 :006 > method(:my_method).to_proc
 => #<Proc:0x000001010a3e38 (lambda)>

最后,我们使用 & 运算符,Proc在方法调用期间在对象前面时,它将被Proc包含的块替换。在 IRB 再来一次:

ruby-1.9.2-p136 :007 > def executor(&block)
ruby-1.9.2-p136 :008?>   block.call
ruby-1.9.2-p136 :009?>   end
 => nil 
ruby-1.9.2-p136 :010 > executor( &method(:my_method).to_proc )
in my_method
 => 10

因此,在伪代码中,您列出的行是:

config.to_prepare(a block containing the functionality of the method activate)

config.to_prepare

[根据 schof 的评论编辑]

config.to_prepare需要一个应该运行的块来设置你的 Railtie/引擎。它在生产模式和开发中的每个请求上运行一次,并且是唯一保证在开发模式下的每个请求上调用的代码。如果您将修改类(class_eval等)作为引擎初始化的一部分,这一点很重要;否则,您将在开发与生产中看到不同的行为。

但为什么?

这是一个常见的习惯用法的原因是您不必在to_prepare块本身内定义准备代码;你可以在你的类中定义方法,然后使用上面描述的魔法将它们转换为一个块(它记住它的范围)。该代码在功能上等同于:

class Engine < Rails::Engine 
  config.to_prepare do
    (the contents of self.activate)
  end
end
于 2011-02-24T19:16:37.637 回答