Что означает этот код Rails Engine: config.to_prepare & method (: activate).to_proc

Я работаю со Spree, который широко использует Rails. Общим примером я нахожу это. Однако мне трудно понять этот код.

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

  config.to_prepare &method(:activate).to_proc
end
  • Что делает .to_prepare do
  • Что делает оператор &method?
  • Каков общий эффект от кода?

Большое спасибо!

Ответ 1

&method(:activate).to_proc

Это лучше всего потребляется по одному пункту за раз. (Следует отметить, что эта часть кода - это 100% не-Rails-специфичный Ruby.)

method - это метод Ruby (все это очень мета). Это задокументировано:

Вызывает именованный метод как приемник в obj, возвращая метод объект (или повышение NameError). Объект метода действует как замыкание в экземпляр объекта objs, поэтому экземпляр переменные и значение 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/Engine. Он запускается один раз в режиме производства и при каждом запросе в разработке и является единственным кодом, гарантированным для каждого отдельного запроса в режиме разработки. Это важно, если вы модифицируете классы (class_eval и т.д.) Как часть инициализации вашего двигателя; в противном случае вы увидите различное поведение в процессе разработки и производства.

Но почему?

Причина, по которой это обычная идиома, заключается в том, что вам не нужно определять код подготовки внутри самого блока to_prepare; вы можете определить метод в своем классе и затем преобразовать их в блок (который запоминает его область действия), используя описанную выше магию. Код функционально эквивалентен:

class Engine < Rails::Engine 
  config.to_prepare do
    (the contents of self.activate)
  end
end