Ruby on Rails: alias_method_chain, что именно он делает? - PullRequest
50 голосов
/ 12 сентября 2010

Я пытался читать различные посты в блоге, в которых пытался объяснить alias_method_chain и причины его использования, а не использования. В частности, я учел:

http://weblog.rubyonrails.org/2006/4/26/new-in-rails-module-alias_method_chain

и

http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/

Я до сих пор не вижу практического использования alias_method_chain. Кто-нибудь сможет объяснить несколько вещей.

1 - он все еще используется?
2 - когда бы вы использовали alias_method_chain и почему?

Ответы [ 4 ]

104 голосов
/ 13 сентября 2010

1 - он все еще используется?

Очевидно, да, alias_method_chain() все еще используется в Rails (начиная с версии 3.0.0).

2 - когда бы вы использовали alias_method_chain и почему?

( Примечание: следующее в значительной степени основано на обсуждении alias_method_chain() in Metaprogramming Ruby от Paolo Perrotta, которая является прекрасной книгой, которую вы должны получить. )

Давайте начнем с базового примера:

class Klass
  def salute
    puts "Aloha!"
  end
end

Klass.new.salute # => Aloha!

Теперь предположим, что мы хотим окружить Klass#salute() поведением логирования.Мы можем сделать то, что Perrotta называет вокруг псевдонима :

class Klass
  def salute_with_log
    puts "Calling method..."
    salute_without_log
    puts "...Method called"
  end

  alias_method :salute_without_log, :salute
  alias_method :salute, :salute_with_log
end

Klass.new.salute
# Prints the following:
# Calling method...
# Aloha!
# ...Method called

Мы определили новый метод с именем salute_with_log() и присвоили ему псевдоним salute().Код, который раньше вызывал salute(), все еще работает, но он также получает новое поведение при ведении журнала.Мы также определили псевдоним для исходного salute(), поэтому мы можем приветствовать его без регистрации:

Klass.new.salute_without_log # => Aloha!

Итак, salute() теперь называется salute_without_log().Если нам нужна регистрация, мы можем вызвать либо salute_with_log(), либо salute(), которые являются псевдонимами одного и того же метода.Смущенный?Хорошо!

По словам Перротты, такой тип псевдонимов очень распространен в Rails:

Посмотрите на другой пример того, как Rails решает проблему по-своему.Несколько версий назад код Rails содержал много экземпляров той же идиомы: Around Alias ​​ (155) использовался для добавления функции к методу, а старая версия метода была переименована во что-то вродеmethod_without_feature().Помимо имен методов, которые менялись каждый раз, код, который делал это, всегда был одинаковым, везде дублировался.В большинстве языков вы не можете избежать такого дублирования.В Ruby вы можете разбрызгивать магию метапрограммирования над вашим шаблоном и извлекать его в свой собственный метод ... и, таким образом, он родился alias_method_chain().

Другими словами, вы предоставляете оригинальный метод foo(), и расширенный метод foo_with_feature(), и в итоге вы получите три метода: foo(), foo_with_feature() и foo_without_feature().Первые два включают функцию, а третье нет.Вместо дублирования этих псевдонимов alias_method_chain(), предоставляемый ActiveSupport , сделает все за вас.

7 голосов
/ 18 января 2017

alias_method_chain устарел в Rails 5 в пользу Module#prepend.

Запрос на извлечение: https://github.com/rails/rails/pull/19434

Журнал изменений: https://github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md#deprecations-4

5 голосов
/ 12 сентября 2010

Я не уверен, что он вышел из моды с Rails 3 или нет, но он до сих пор активно используется в версиях до этого.

Вы используете его для добавления некоторых функций до (или после)метод вызывается без изменения места, вызывающего этот метод.См. Этот пример:

module SwitchableSmtp
  module InstanceMethods
    def deliver_with_switchable_smtp!(mail = @mail)
      unless logger.nil?
        logger.info  "Switching SMTP server to: #{custom_smtp.inspect}" 
      end
      ActionMailer::Base.smtp_settings = custom_smtp unless custom_smtp.nil?
      deliver_without_switchable_smtp!(mail = @mail)
    end
  end
  def self.included(receiver)
    receiver.send :include, InstanceMethods
    receiver.class_eval do
      alias_method_chain :deliver!, :switchable_smtp
    end
  end
end

Это дополнение к ActionMailer, позволяющее менять настройки SMTP при каждом вызове на deliver!.Позвонив по номеру alias_method_chain, вы можете определить метод deliver_with_switchable_smtp!, в котором вы делаете свои собственные вещи, и по окончании вызова deliver_without_switchable_smtp! оттуда.

alias_method_chain псевдонимы старого deliver! к вашему новому пользовательскому методу, так что остальная часть вашего приложения даже не знает, deliver! теперь тоже делает ваши пользовательские вещи.

3 голосов
/ 13 сентября 2010

это вообще используется?

Кажется, так . Это обычная практика среди разработчиков Rails

когда бы вы использовали alias_method_chain и почему?

Несмотря на предупреждения, alias_method_chain по-прежнему является основной стратегией, используемой при внедрении функциональности в существующий метод, по крайней мере, в Rails 2.x и за ним следуют многие, расширяющие его. Иегуда должен удалить alias_method_chain из rails 3.0, чтобы сказать это из своих постов и комментариев в билетах Rails. Он по-прежнему используется многими расширениями, которые добавляют настраиваемое поведение в определенных точках выполнения, таких как средства ведения журнала, репортеры ошибок, бенчмаркинг, внедрение данных и т. Д.

IMO, лучшая альтернатива - это включить модуль, таким образом, вы имеете украшение над делегированием. (Например, следуйте примеру 4 в этом посте ). Таким образом, вы можете изменять объекты даже индивидуально, если хотите, не загрязняя методы класса. Недостатком этого является то, что цепочка поиска метода увеличивается для каждого внедряемого вами модуля, но в любом случае это то, что нужно для модулей.

Очень интересный вопрос, посмотрим, что другие люди подумают об этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...