簡體   English   中英

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

[英]Ruby on Rails: alias_method_chain, what exactly does it do?

我已經嘗試閱讀各種博客文章,試圖解釋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 - 它還在使用嗎?

顯然是的, alias_method_chain() 仍然在Rails中使用 (從3.0.0版開始)。

2 - 你何時會使用alias_method_chain?為什么?

注意: 以下內容主要基於Paolo Perrotta在Metaprogramming Ruby中alias_method_chain()的討論,這是一本非常好的書,你應該開始使用。

讓我們從一個基本的例子開始:

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() ,它們是同一方法的別名。 困惑? 好!

根據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() 前兩個包括功能,而第三個沒有。 而不是復制這些別名,ActiveSupport提供的alias_method_chain()為您完成所有別名。

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

我不確定它是否已經過時了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! 現在也做你的自定義的東西。

是用的嗎?

似乎是這樣 這是Rails開發人員的常見做法

你何時會使用alias_method_chain?為什么?

盡管有這些警告,alias_method_chain仍然是向現有方法注入功能時使用的主要策略,至少在Rails 2.x中,並且后來有很多人在擴展它。 Yehuda應該從rails 3.0中刪除alias_method_chain來說明他在Rails門票中的帖子和評論。 它仍然被許多擴展使用,它們在執行的某些點添加自定義行為,例如記錄器,錯誤報告器,基准測試,數據注入等。

IMO,最好的選擇是包含一個模塊,因此你可以裝飾而不是委托。 (例如,按照實施例4中此信息 )。 這樣,如果您願意,您甚至可以單獨更改對象,而不會污染類的方法。 這樣做的缺點是方法查找鏈會為您注入的每個模塊增加,但這就是模塊的用途。

非常有趣的問題,將關注其他人的想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM