Ruby on Rails: alias_method_chain, что именно он делает?
Я пробовал читать через различные сообщения в блоге, которые пытаются объяснить 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 и почему?
Ответы
Ответ 1
1 - все еще используется?
По-видимому, да, alias_method_chain()
все еще используется в Rails (начиная с версии 3.0.0).
2 - когда вы будете использовать alias_method_chain и почему?
( Примечание: следующее в основном основано на обсуждении alias_method_chain()
в Метапрограммирование Ruby Паоло Перротта, что является отличной книгой, в которой вы должны получить свои руки.)
Начнем с базового примера:
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, делает все наложение на вас.
Ответ 2
Я не уверен, что он вышел из стиля с 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
alias_method_chain
устарел в Rails 5 в пользу Module#prepend
.
Запрос Pull: https://github.com/rails/rails/pull/19434
Список изменений: https://github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md#deprecations-4
Ответ 4
он вообще используется?
Кажется, так. Это обычная практика среди разработчиков Rails
когда вы используете alias_method_chain и почему?
Несмотря на предупреждения, alias_method_chain по-прежнему остается основной стратегией, используемой при внедрении функциональности существующего метода, по крайней мере, в Rails 2.x, за которым следуют многие люди, расширяющие ее. Yehuda должен удалить alias_method_chain из rails 3.0, чтобы сказать из своих сообщений и комментариев в Rails-билетах. Он по-прежнему используется многими расширениями, которые добавляют пользовательское поведение в определенные моменты выполнения, такие как регистраторы, репортеры ошибок, бенчмаркинг, ввод данных и т.д.
ИМО, лучшей альтернативой является включение модуля, таким образом, у вас есть украшение над делегированием. (Например, следуйте примеру 4 в этот пост). Таким образом, вы можете изменить объекты даже индивидуально, если хотите, без загрязнения методов класса. Недостатком этого является то, что цепочка поиска метода увеличивается для каждого вводимого модуля, но это то, что модули в любом случае.
Очень интересный вопрос, будет смотреть на то, что другие люди думают об этом.