ADZ 學習筆記

Ruby/Rails, Startup, Life

rails 筆記 - Gem Memoist

| Comments

有一種情況是 method 裡面有些計算,重複呼叫時不需要重複計算,這時候我們會想要把 method 的結果 cache 讓程式碼 clean 一點,這時我們會使用 ||= 搭配 instance variable 來實現 method cache。

class Cart
  ... ()
  def total_amount
    # 如果是 nil 則執行後方運算並回傳,否則就直接回傳。

    @total_amount ||= items.map { |item| item.price * item.qty }.sum 
  end
  ... ()
end

不過以上程式碼有兩個問題:

  1. nil 無法 cache (如果複雜計算後的結果是 nil,下次呼叫還是執行計算)
  2. method with argument 的狀況

第二點的 method with argument 也是可以實作,不過 code 會變得不是那麼 clean,例如:

class Cart
  def total_amount(cost=1)
    @total_amount ||= {}
    @total_amount[cost] = items.map { |item| item.price * item.qty }.sum * cost
  end
end

這些問題事在看 codeschool 的時候的發現解法的,原來 rails 內建有一個 module 叫做 ActiveSupport::Memoizable 作用也是實作 method cache,不過跟以上的方式不太一樣,解決了 nil 無法 cache 跟 method with argument 的問題,並且使用上很簡單:

class Cart
  extend ActiveSupport::Memoizable # 要先 extend 這個 module

  
  def total_amount(cost=1)
    items.map { |item| item.price * item.qty }.sum * cost
  end
  memoize :total_amount # 加上這行就搞定

end

這裡是 ActiveSupport::Memoizable 的 source code:

https://github.com/rails/rails/blob/36253916b0b788d6ded56669d37c96ed05c92c5c/activesupport/lib/active_support/memoizable.rb#L66

不幸的是,這支 module 似乎在 2011 年就被棄用了,但是有人把這隻 module 重新包裝成一隻新 gem 叫做 memoist

https://github.com/matthewrudy/memoist

使用方式看起來跟 ActiveSupport::Memoizable 一樣,有興趣的人研究看看吧 :)

Comments

comments powered by Disqus