通過使用鉤子方法,可以讓我們在Ruby的類或模塊的生命周期中進行干預,可以極大的提高編程的靈活性。
與生命周期相關的鉤子方法有下面這些:
類與模塊相關
Class#inherited Module#include Module#prepended Module#extend_object Module#method_added Module#method_removed Module#method_undefined單件類相關
BasicObject#singleton_method_added BasicObject#singleton_method_removed BasicObject#singleton_method_undefined示例代碼
module M1 def self.included(othermod) puts “M1 was included into #{othermod}” endendmodule M2 def self.prepended(othermod) puts “M2 was prepended to #{othermod}” endendclass C include M1 include M2end# 輸出M1 was included into CM2 was prepended to Cmodule M def self.method_added(method) puts “New method: M##{method}” end def my_method; endend# 輸出New method: M#my_method
除了上面列出來的一些方法外,也可以通過重寫父類的某個方法,進行一些過濾操作后,再通過調用super方法完成原函數的功能,從而實現類似鉤子方法的功效,如出一轍,環繞別名也可以作為一種鉤子方法的替代實現。
運用實例
任務描述:
寫一個操作方法類似attr_accessor的attr_checked的類宏,該類宏用來對屬性值做檢驗,使用方法如下:
class Person include CheckedAttributes attr_checked :age do |v| v >= 18 endendme = Person.newme.age = 39 #okme.age = 12 #拋出異常
實施計劃:
使用eval方法編寫一個名為add_checked_attribute的內核方法,為指定類添加經過簡單校驗的屬性
重構add_checked_attribute方法,去掉eval方法,改用其它手段實現
添加代碼塊校驗功能
修改add_checked_attribute為要求的attr_checked,并使其對所有類都可用
通過引入模塊的方式,只對引入該功能模塊的類添加attr_checked方法
Step 1
def add_checked_attribute(klass, attribute) eval " class #{klass} def #{attribute}=(value) raise 'Invalid attribute' unless value @#{attribute} = value end def #{attribute}() @#{attribute} end end "endadd_checked_attribute(String, :my_attr)t = "hello,kitty"t.my_attr = 100puts t.my_attrt.my_attr = falseputs t.my_attr
這一步使用eval方法,用class和def關鍵詞分別打開類,且定義了指定的屬性的get和set方法,其中的set方法會簡單的判斷值是否為空(nil 或 false),如果是則拋出Invalid attribute異常。
Setp 2
def add_checked_attribute(klass, attribute) klass.class_eval do define_method "#{attribute}=" do |value| raise "Invaild attribute" unless value instance_variable_set("@#{attribute}", value) end define_method attribute do instance_variable_get "@#{attribute}" end endend
新聞熱點
疑難解答