Ruby on Rails:alias_method_chain,它究竟做了什么?

ran*_*its 51 ruby ruby-on-rails

我已经尝试阅读各种博客文章,试图解释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?为什么?

Yas*_*man 104

1 - 它还在使用吗?

显然,是的,alias_method_chain()Rails中仍在使用(如3.0.0版).

2 - 你何时会使用alias_method_chain?为什么?

(注意:以下内容主要基于Paolo Perrotta alias_method_chain()Metaprogramming Ruby中的讨论,这是一本非常好的书,你应该亲自动手.)

让我们从一个基本的例子开始:

class Klass
  def salute
    puts "Aloha!"
  end
end

Klass.new.salute # => Aloha!
Run Code Online (Sandbox Code Playgroud)

现在假设我们想要围绕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
Run Code Online (Sandbox Code Playgroud)

我们定义了一个名为的新方法,salute_with_log()并将其别名化salute().以前调用的代码salute()仍可正常工作,但它也会获得新的日志记录行为.我们还定义了原始的别名salute(),所以我们仍然可以在没有记录的情况下致敬:

Klass.new.salute_without_log # => Aloha!
Run Code Online (Sandbox Code Playgroud)

所以,salute()现在被称为salute_without_log().如果我们想要记录,我们可以调用salute_with_log()或者salute(),它们是同一方法的别名.困惑?好!

根据Perrotta的说法,这种别名在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提供,为您完成所有别名.

  • 和小补充:所以现在我们可以输入```alias_method_chain:foo,:feature```我们将有3种方法:````foo```,```foo_with_feature```,```foo_without_feature`这些正确的别名为*Yases Sulaiman*之前描述的 (14认同)
  • "任何足够先进的技术都与魔术无法区分." 亚瑟C.克拉克 (2认同)

tfe*_*tfe 5

我不确定它是否在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
Run Code Online (Sandbox Code Playgroud)

这是对ActionMailer的补充,允许在每次调用时换出SMTP设置deliver!。通过调用,alias_method_chain您可以定义一种用于 deliver_with_switchable_smtp!执行自定义内容的方法,并deliver_without_switchable_smtp!在完成后从此处进行调用。

alias_method_chain将旧名称别名为deliver!新的自定义方法,因此应用程序的其余部分甚至deliver!现在都不知道自定义内容。