alias_method_chain,它具体做什么?

时间:2021-11-30 12:04:28

I've tried reading through various blog posts that attempt to explain alias_method_chain and the reasons to use it and not use it. In particular, I took heed to:

我尝试阅读各种试图解释alias_method_chain的博客文章,以及使用它而不使用它的原因。我特别注意到:

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

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

and

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

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

I still do not see any practical use for alias_method_chain. Would anyone be able to explain a few things.

我仍然没有看到alias_method_chain的任何实际用途。有人能解释一下吗?

1 - is it still used at all?
2 - when would you use alias_method_chain and why?

1 -它还在用吗?2 -什么时候使用alias_method_chain ?为什么?

4 个解决方案

#1


93  

1 - is it still used at all?

1 -它还在用吗?

Apparently yes, alias_method_chain() is still used in Rails (as of version 3.0.0).

显然,alias_method_chain()仍然在Rails中使用(从3.0.0版本开始)。

2 - when would you use alias_method_chain and why?

2 -什么时候使用alias_method_chain ?为什么?

(Note: the following is largely based on the discussion of alias_method_chain() in Metaprogramming Ruby by Paolo Perrotta, which is an excellent book that you should get your hands on.)

(注意:以下内容主要是基于Paolo Perrotta在《元编程Ruby》中对alias_method_chain()的讨论,这是一本很好的书,你应该去看看)。

Let's start with a basic example:

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

class Klass
  def salute
    puts "Aloha!"
  end
end

Klass.new.salute # => Aloha!

Now suppose that we want to surround Klass#salute() with logging behavior. We can do that what Perrotta calls an around alias:

现在假设我们想要用日志行为包围Klass#salute()。我们可以用Perrotta所称的around alias:

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

We defined a new method called salute_with_log() and aliased it to salute(). The code that used to call salute() still works, but it gets the new logging behavior as well. We also defined an alias to the original salute(), so we can still salute without logging:

我们定义了一个名为salute_with_log()的新方法,并将其别名为salute()。用于调用致敬()的代码仍然有效,但是它也获得了新的日志记录行为。我们还定义了原敬礼()的别名,因此我们仍然可以不登录敬礼:

Klass.new.salute_without_log # => Aloha!

So, salute() is now called salute_without_log(). If we want logging, we can call either salute_with_log() or salute(), which are aliases of the same method. Confused? Good!

因此,salute()现在被称为salute_without_log()。如果想要日志记录,可以调用salute_with_log()或salute(),它们是相同方法的别名。困惑吗?好!

According to Perrotta, this kind of around alias is very common in Rails:

根据Perrotta的说法,这种around alias在Rails中很常见:

Look at another example of Rails solving a problem its own way. A few versions ago, the Rails code contained many instances of the same idiom: an Around Alias (155) was used to add a feature to a method, and the old version of the method was renamed to something like method_without_feature(). Apart from the method names, which changed every time, the code that did this was always the same, duplicated all over the place. In most languages, you cannot avoid that kind of duplication. In Ruby, you can sprinkle some metaprogramming magic over your pattern and extract it into its own method... and thus was born alias_method_chain().

看看另一个Rails以自己的方式解决问题的例子。几个版本以前,Rails代码包含许多相同习惯用法的实例:使用一个Around Alias(155)向方法添加特性,旧版本的方法被重命名为method_without_feature()。除了方法名(每次都会更改)之外,执行此操作的代码总是相同的,到处都是重复的。在大多数语言中,你无法避免这种重复。在Ruby中,您可以在模式中添加一些元编程的魔力,并将其提取到自己的方法中……由此诞生了alias_method_chain()。

In other words, you provide the original method, foo(), and the enhanced method, foo_with_feature(), and you end up with three methods: foo(), foo_with_feature(), and foo_without_feature(). The first two include the feature, while the third doesn't. Instead of duplicating these aliases all around, alias_method_chain() provided by ActiveSupport does all the aliasing for you.

换句话说,您提供了原始方法foo()和增强方法foo_with_feature(),最后得到了三个方法:foo()、foo_with_feature()和foo_without_feature()。前两个包含了这个特性,而第三个没有。ActiveSupport提供的alias_method_chain()不需要到处重复这些别名,而是为您完成所有的别名。

#2


4  

I'm not sure if it's gone out of style with Rails 3 or not, but it is still actively used in versions before that.

我不确定它是否在Rails 3中过时了,但在此之前,它仍然在版本中被积极使用。

You use it to inject some functionality before (or after) a method is called, without modifying any place that calls that method. See this example:

您可以使用它在调用方法之前(或之后)注入一些功能,而无需修改调用该方法的任何位置。看这个例子:

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

That's an addition to ActionMailer to allow swapping out of the SMTP settings on each call to deliver!. By calling alias_method_chain you are able to define a method deliver_with_switchable_smtp! in which you do your custom stuff, and call deliver_without_switchable_smtp! from there when you're done.

这是ActionMailer的一个附加功能,允许在每次调用中交换SMTP设置。通过调用alias_method_chain,您可以定义一个方法deliver_with_switchable_smtp!在其中,您执行自定义工作,并调用deliver_without_switchable_smtp!当你完成的时候。

alias_method_chain aliases the old deliver! to your new custom method, so the rest of your app doesn't even know deliver! now does your custom stuff too.

alias_method_chain对旧的交付进行别名!对于您的新定制方法,您的应用程序的其他部分甚至不知道交付!现在你的自定义物品也可以了。

#3


3  

alias_method_chain has been deprecated in Rails 5 in favour of Module#prepend.

在Rails 5中,alias_method_chain已被弃用,取而代之的是模块#prepend。

Pull request: https://github.com/rails/rails/pull/19434

把请求:https://github.com/rails/rails/pull/19434

Changelog: https://github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md#deprecations-4

更新日志:https://github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md # deprecations-4

#4


2  

is it used at all?

它真的用过吗?

Seems so. It's a common practice among Rails developers

看来的确如此。这是Rails开发人员的常见实践

when would you use alias_method_chain and why?

什么时候使用alias_method_chain,为什么?

Despite the warnings, alias_method_chain is still the main strategy used when injecting functionality to an existing method, at least was in Rails 2.x and is followed by many people extending it. Yehuda ought to remove alias_method_chain from rails 3.0 to say from his posts and comments in Rails tickets. It is still used by many extensions that add custom behavior at certain points of the execution, such as loggers, error reporters, benchmarking, data injection, etc.

尽管有警告,alias_method_chain仍然是向现有方法注入功能时使用的主要策略,至少在Rails 2中是这样。x之后有很多人扩展它。Yehuda应该从rails 3.0中删除alias_method_chain,并在rails ticket中的帖子和评论中声明。它仍然被许多扩展所使用,在执行的某些点添加自定义行为,例如日志记录器、错误报告、基准测试、数据注入等等。

IMO, the best alternative is to include a module, thus you have decoration over delegation. (For example, follow example 4 in this post). That way you can alter the objects even individually if you'd like, without polluting the class' methods. The downside to this is that the method lookup chain increases for each module you inject, but this is what modules are for anyway.

在我看来,最好的选择是包含一个模块,这样就有了装饰而不是委托。(例如,请遵循本文中的示例4)。这样,即使您愿意,也可以单独修改对象,而不会污染类的方法。这样做的缺点是,方法查找链会随着您注入的每个模块而增加,但这正是模块的作用所在。

Very interesting question, will keep a look on what other people think about it.

很有趣的问题,会让大家看看其他人是怎么想的。

#1


93  

1 - is it still used at all?

1 -它还在用吗?

Apparently yes, alias_method_chain() is still used in Rails (as of version 3.0.0).

显然,alias_method_chain()仍然在Rails中使用(从3.0.0版本开始)。

2 - when would you use alias_method_chain and why?

2 -什么时候使用alias_method_chain ?为什么?

(Note: the following is largely based on the discussion of alias_method_chain() in Metaprogramming Ruby by Paolo Perrotta, which is an excellent book that you should get your hands on.)

(注意:以下内容主要是基于Paolo Perrotta在《元编程Ruby》中对alias_method_chain()的讨论,这是一本很好的书,你应该去看看)。

Let's start with a basic example:

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

class Klass
  def salute
    puts "Aloha!"
  end
end

Klass.new.salute # => Aloha!

Now suppose that we want to surround Klass#salute() with logging behavior. We can do that what Perrotta calls an around alias:

现在假设我们想要用日志行为包围Klass#salute()。我们可以用Perrotta所称的around alias:

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

We defined a new method called salute_with_log() and aliased it to salute(). The code that used to call salute() still works, but it gets the new logging behavior as well. We also defined an alias to the original salute(), so we can still salute without logging:

我们定义了一个名为salute_with_log()的新方法,并将其别名为salute()。用于调用致敬()的代码仍然有效,但是它也获得了新的日志记录行为。我们还定义了原敬礼()的别名,因此我们仍然可以不登录敬礼:

Klass.new.salute_without_log # => Aloha!

So, salute() is now called salute_without_log(). If we want logging, we can call either salute_with_log() or salute(), which are aliases of the same method. Confused? Good!

因此,salute()现在被称为salute_without_log()。如果想要日志记录,可以调用salute_with_log()或salute(),它们是相同方法的别名。困惑吗?好!

According to Perrotta, this kind of around alias is very common in Rails:

根据Perrotta的说法,这种around alias在Rails中很常见:

Look at another example of Rails solving a problem its own way. A few versions ago, the Rails code contained many instances of the same idiom: an Around Alias (155) was used to add a feature to a method, and the old version of the method was renamed to something like method_without_feature(). Apart from the method names, which changed every time, the code that did this was always the same, duplicated all over the place. In most languages, you cannot avoid that kind of duplication. In Ruby, you can sprinkle some metaprogramming magic over your pattern and extract it into its own method... and thus was born alias_method_chain().

看看另一个Rails以自己的方式解决问题的例子。几个版本以前,Rails代码包含许多相同习惯用法的实例:使用一个Around Alias(155)向方法添加特性,旧版本的方法被重命名为method_without_feature()。除了方法名(每次都会更改)之外,执行此操作的代码总是相同的,到处都是重复的。在大多数语言中,你无法避免这种重复。在Ruby中,您可以在模式中添加一些元编程的魔力,并将其提取到自己的方法中……由此诞生了alias_method_chain()。

In other words, you provide the original method, foo(), and the enhanced method, foo_with_feature(), and you end up with three methods: foo(), foo_with_feature(), and foo_without_feature(). The first two include the feature, while the third doesn't. Instead of duplicating these aliases all around, alias_method_chain() provided by ActiveSupport does all the aliasing for you.

换句话说,您提供了原始方法foo()和增强方法foo_with_feature(),最后得到了三个方法:foo()、foo_with_feature()和foo_without_feature()。前两个包含了这个特性,而第三个没有。ActiveSupport提供的alias_method_chain()不需要到处重复这些别名,而是为您完成所有的别名。

#2


4  

I'm not sure if it's gone out of style with Rails 3 or not, but it is still actively used in versions before that.

我不确定它是否在Rails 3中过时了,但在此之前,它仍然在版本中被积极使用。

You use it to inject some functionality before (or after) a method is called, without modifying any place that calls that method. See this example:

您可以使用它在调用方法之前(或之后)注入一些功能,而无需修改调用该方法的任何位置。看这个例子:

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

That's an addition to ActionMailer to allow swapping out of the SMTP settings on each call to deliver!. By calling alias_method_chain you are able to define a method deliver_with_switchable_smtp! in which you do your custom stuff, and call deliver_without_switchable_smtp! from there when you're done.

这是ActionMailer的一个附加功能,允许在每次调用中交换SMTP设置。通过调用alias_method_chain,您可以定义一个方法deliver_with_switchable_smtp!在其中,您执行自定义工作,并调用deliver_without_switchable_smtp!当你完成的时候。

alias_method_chain aliases the old deliver! to your new custom method, so the rest of your app doesn't even know deliver! now does your custom stuff too.

alias_method_chain对旧的交付进行别名!对于您的新定制方法,您的应用程序的其他部分甚至不知道交付!现在你的自定义物品也可以了。

#3


3  

alias_method_chain has been deprecated in Rails 5 in favour of Module#prepend.

在Rails 5中,alias_method_chain已被弃用,取而代之的是模块#prepend。

Pull request: https://github.com/rails/rails/pull/19434

把请求:https://github.com/rails/rails/pull/19434

Changelog: https://github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md#deprecations-4

更新日志:https://github.com/rails/rails/blob/b292b76c2dd0f04fb090d49b90716a0e6037b41a/guides/source/5_0_release_notes.md # deprecations-4

#4


2  

is it used at all?

它真的用过吗?

Seems so. It's a common practice among Rails developers

看来的确如此。这是Rails开发人员的常见实践

when would you use alias_method_chain and why?

什么时候使用alias_method_chain,为什么?

Despite the warnings, alias_method_chain is still the main strategy used when injecting functionality to an existing method, at least was in Rails 2.x and is followed by many people extending it. Yehuda ought to remove alias_method_chain from rails 3.0 to say from his posts and comments in Rails tickets. It is still used by many extensions that add custom behavior at certain points of the execution, such as loggers, error reporters, benchmarking, data injection, etc.

尽管有警告,alias_method_chain仍然是向现有方法注入功能时使用的主要策略,至少在Rails 2中是这样。x之后有很多人扩展它。Yehuda应该从rails 3.0中删除alias_method_chain,并在rails ticket中的帖子和评论中声明。它仍然被许多扩展所使用,在执行的某些点添加自定义行为,例如日志记录器、错误报告、基准测试、数据注入等等。

IMO, the best alternative is to include a module, thus you have decoration over delegation. (For example, follow example 4 in this post). That way you can alter the objects even individually if you'd like, without polluting the class' methods. The downside to this is that the method lookup chain increases for each module you inject, but this is what modules are for anyway.

在我看来,最好的选择是包含一个模块,这样就有了装饰而不是委托。(例如,请遵循本文中的示例4)。这样,即使您愿意,也可以单独修改对象,而不会污染类的方法。这样做的缺点是,方法查找链会随着您注入的每个模块而增加,但这正是模块的作用所在。

Very interesting question, will keep a look on what other people think about it.

很有趣的问题,会让大家看看其他人是怎么想的。