iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
0
自我挑戰組

Metaprogramming Ruby and Rails系列 第 20

Day 20 -- Refinement Wrapper & Prepended Wrapper

  • 分享至 

  • xImage
  •  

Refinement Wrapper

昨天我們學到了 Refinement 如何利用 using 關鍵字,來控制覆寫方法可影響的範圍。
今天要介紹 Refinement 的另一項特性將可以取代 Around Aliases  -  super
看看以下例子:

class MyClass
  def my_method(change = false)
    "original my_method()"
  end
  def another_method
    my_method
  end
end

module MyClassRefinement
  refine MyClass do
    def my_method(change)
      change ? super : "refined my_method()"
    end
  end
end

using MyClassRefinement
self                          # main

MyClass.new.my_method(true)   # => "original my_method()"

MyClass.new.my_method(false)  # => "refined my_method()"

MyClass.new.another_method    # => "original my_method()"

如果將 super 關鍵字放在重新定義後的方法內,就可以利用 super 取得原始舊版的方法。
再來一個範例:

module StringRefinement 
  refine String do
    def length
      super > 5 ? 'long' : 'short'
    end 
  end
end

using StringRefinement
"War and Peace".length # => "long"

上面的程式碼利用 refine 關鍵字,重新定義 String 類別並且打包ㄧ個 length() 方法。就如同其他的 Refinements, Refinement Wrapper 也只能活到該檔案結束為止。
就因為 Refinements 所能影響的範圍是區域性,所以通常被視為比 Around Alias 更安全的選項。

Prepended Wrapper

還記得第八天所介紹的 Module#prepend() 方法嗎?Include() 與 prepend() 類似,都可以將方法引入 module,其中的差別在於 prepend 所引入的方法會在該類別的下方。
就因為這個區別,讓模組內的方法可以被覆寫並且呼叫 super 來取得未經修改的原始方法。

module ExplicitString 
  def length
    super > 5 ? "long" : "short" 
  end
end

String.class_eval do 
  prepend ExplicitString
end

"War and Peace".length          # => "long"

在以上程式碼,我們在 ExplicitString 模組內重新定義了 length() 方法,在以 class_eval() 方法打開 String 類別,並且以 prepend 該模組在 String 類別的下方。
最後的結果就是,之後任何物件呼叫 String#length() 都會得到修改後的回傳值。 

小結

目前為止我們介紹了三種 method wrappers: (1) Around Alias, (2) Refinement Wrapper, (3) Prepend Wrapper。 其中我比較偏好的是 Refinement Wrapper ,因為它提供了其他 Wrappers 都沒有的特性就是可用關鍵字 using 來決定覆寫方法可影響的範圍。然而,此特性的罩門就是容易搞會模組內呼叫方法的順序,因而得到與預想不同的回傳值。書中推薦的 method wrapper 則是 Prepend Wrapper,因為它的程式碼寫起來比較乾淨,也清楚許多。


上一篇
Day 19 -- Refinement
下一篇
Day 21 -- Rails BCrypt 使用者身分驗證
系列文
Metaprogramming Ruby and Rails33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言