實作類似 ActiveRecord 的 callback 結構


#1

這篇單純應觀眾要求 … 實作類似 ActiveRecord 的 callback 結構

class Base
  def self.save_stack(stack_name , *action_name_set)
    puts "save_stack : #{action_name_set.join(' , ')}"
    @@action_stack ||= {}
    @@action_stack[stack_name] ||= []
    action_name_set.each do |action_name|
      @@action_stack[stack_name] << action_name
    end
  end
  def self.process_stack(stack_name , obj)
    puts "process_stack : #{stack_name}"
    @@action_stack ||= {}
    if @@action_stack[stack_name]
      @@action_stack[stack_name].each do |action_name|
        obj.send(action_name)
      end
    end
  end
  def self.before_save(*action_name_set)
    save_stack(:before_save , *action_name_set)
  end
  def self.after_save(*action_name_set)
    save_stack(:after_save  , *action_name_set)
  end
  def save
    self.class.process_stack(:before_save , self)
    puts "==== do save ==="
    self.class.process_stack(:after_save , self)
  end
end
class Item < Base
  before_save :bs_01 , :bs_02
  after_save  :as_01 , :as_02

  def bs_01 ; puts "im_bs01" ; end
  def bs_02 ; puts "im_bs02" ; end
  def as_01 ; puts "im_as01" ; end
  def as_02 ; puts "im_as02" ; end
end

Item.new.save

#=>  save_stack : bs_01 , bs_02
#=>  save_stack : as_01 , as_02
#=>  process_stack : before_save
#=>  im_bs01
#=>  im_bs02
#=>  ==== do save ===
#=>  process_stack : after_save
#=>  im_as01
#=>  im_as02

大致的就是建立 stack (其實就是 array) 然後在特定的時候播放即可,而 before / after 其實就是註冊用的 method 而已,當然你還可以建立類似 only / except 之類的結構,因為 Ruby 取得到上個 method 就能做類似的事情哩,類似這篇所說

或是單純的進行排除過濾之類的,剩下就是自己寫遊戲規則而已,上篇寫的 “Aspect-Oriented Programming” 困難比這很多,還可以進行排序插入有的沒的,而這個就寫得太簡單方便使用而已,且 method 內彼此無關聯,然而這種東西切記不要一個 class 寫到完,善用繼承結構否則腦袋會打結哩,以上