Ruby中鉤子方法的運(yùn)用實(shí)例解析
通過(guò)使用鉤子方法,可以讓我們?cè)赗uby的類(lèi)或模塊的生命周期中進(jìn)行干預(yù),可以極大的提高編程的靈活性。
與生命周期相關(guān)的鉤子方法有下面這些:
類(lèi)與模塊相關(guān)
- Class#inherited
- Module#include
- Module#prepended
- Module#extend_object
- Module#method_added
- Module#method_removed
- Module#method_undefined
單件類(lèi)相關(guān)
- BasicObject#singleton_method_added
- BasicObject#singleton_method_removed
- BasicObject#singleton_method_undefined
示例代碼
module M1
def self.included(othermod)
puts “M1 was included into #{othermod}”
end
end
module M2
def self.prepended(othermod)
puts “M2 was prepended to #{othermod}”
end
end
class C
include M1
include M2
end
# 輸出
M1 was included into C
M2 was prepended to C
module M
def self.method_added(method)
puts “New method: M##{method}”
end
def my_method; end
end
# 輸出
New method: M#my_method
除了上面列出來(lái)的一些方法外,也可以通過(guò)重寫(xiě)父類(lèi)的某個(gè)方法,進(jìn)行一些過(guò)濾操作后,再通過(guò)調(diào)用super方法完成原函數(shù)的功能,從而實(shí)現(xiàn)類(lèi)似鉤子方法的功效,如出一轍,環(huán)繞別名也可以作為一種鉤子方法的替代實(shí)現(xiàn)。
運(yùn)用實(shí)例
任務(wù)描述:
寫(xiě)一個(gè)操作方法類(lèi)似attr_accessor的attr_checked的類(lèi)宏,該類(lèi)宏用來(lái)對(duì)屬性值做檢驗(yàn),使用方法如下:
class Person include CheckedAttributes attr_checked :age do |v| v >= 18 end end me = Person.new me.age = 39 #ok me.age = 12 #拋出異常
實(shí)施計(jì)劃:
使用eval方法編寫(xiě)一個(gè)名為add_checked_attribute的內(nèi)核方法,為指定類(lèi)添加經(jīng)過(guò)簡(jiǎn)單校驗(yàn)的屬性
重構(gòu)add_checked_attribute方法,去掉eval方法,改用其它手段實(shí)現(xiàn)
添加代碼塊校驗(yàn)功能
修改add_checked_attribute為要求的attr_checked,并使其對(duì)所有類(lèi)都可用
通過(guò)引入模塊的方式,只對(duì)引入該功能模塊的類(lèi)添加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
"
end
add_checked_attribute(String, :my_attr)
t = "hello,kitty"
t.my_attr = 100
puts t.my_attr
t.my_attr = false
puts t.my_attr
這一步使用eval方法,用class和def關(guān)鍵詞分別打開(kāi)類(lèi),且定義了指定的屬性的get和set方法,其中的set方法會(huì)簡(jiǎn)單的判斷值是否為空(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
end
end
這一步更換掉了eval方法,同時(shí)也分別用class_eval和define_method方法替換了之前的class與def關(guān)鍵字,實(shí)例變量的設(shè)置和獲取分別改用了instance_variable_set和instance_variable_get方法,使用上與第一步?jīng)]有任何區(qū)別,只是一些內(nèi)部實(shí)現(xiàn)的差異。
Step 3
def add_checked_attribute(klass, attribute, &validation)
klass.class_eval do
define_method "#{attribute}=" do |value|
raise "Invaild attribute" unless validation.call(value)
instance_variable_set("@#{attribute}", value)
end
define_method attribute do
instance_variable_get "@#{attribute}"
end
end
end
add_checked_attribute(String, :my_attr){|v| v >= 180 }
t = "hello,kitty"
t.my_attr = 100 #Invaild attribute (RuntimeError)
puts t.my_attr
t.my_attr = 200
puts t.my_attr #200
沒(méi)有什么奇特的,只是加了通過(guò)代碼塊驗(yàn)證,增加了校驗(yàn)的靈活性,不再僅僅局限于nil和false之間了。
Step 4
class Class
def attr_checked(attribute, &validation)
define_method "#{attribute}=" do |value|
raise "Invaild attribute" unless validation.call(value)
instance_variable_set("@#{attribute}", value)
end
define_method attribute do
instance_variable_get "@#{attribute}"
end
end
end
String.add_checked(:my_attr){|v| v >= 180 }
t = "hello,kitty"
t.my_attr = 100 #Invaild attribute (RuntimeError)
puts t.my_attr
t.my_attr = 200
puts t.my_attr #200
這里我們把之前頂級(jí)作用域中方法名放到了Class中,由于所有對(duì)象都是Class的實(shí)例, 所以這里定義的實(shí)例方法,也能被Ruby中的其它所有類(lèi)訪問(wèn)到,同時(shí)在class定義中,self就是當(dāng)前類(lèi),所以也就省去了調(diào)用類(lèi)這個(gè)參數(shù)和class_eval方法,并且我們把方法的名字也改成了attr_checked。
Step 5
module CheckedAttributes
def self.included(base)
base.extend ClassMethods
end
end
module ClassMethods
def attr_checked(attribute, &validation)
define_method "#{attribute}=" do |value|
raise "Invaild attribute" unless validation.call(value)
instance_variable_set("@#{attribute}", value)
end
define_method attribute do
instance_variable_get "@#{attribute}"
end
end
end
class Person
include CheckedAttributes
attr_checked :age do |v|
v >= 18
end
end
最后一步通過(guò)鉤子方法,在CheckedAttributes模塊被引入后,對(duì)當(dāng)前類(lèi)通過(guò)被引入模塊進(jìn)行擴(kuò)展, 從而使當(dāng)前類(lèi)支持引入后的方法調(diào)用,即這里的get與set方法組。
到此,我們已經(jīng)得到了一個(gè)名為attr_checked,類(lèi)似attr_accessor的類(lèi)宏,通過(guò)它你可以對(duì)屬性進(jìn)行你想要的校驗(yàn)。
相關(guān)文章
CentOS7下安裝Ruby3.2.4的實(shí)施路徑詳解
在CentOS 7系統(tǒng)上安裝Ruby 3.2.4版本需要先安裝RVM作為版本管理工具,安裝過(guò)程涉及到安裝GPG的key、RVM的最新穩(wěn)定版本以及Ruby的前置依賴(lài),下面給大家介紹CentOS7下安裝Ruby3.2.4的實(shí)施路徑,感興趣的朋友跟隨小編一起看看吧2024-09-09
在Docker中自動(dòng)化部署Ruby on Rails的教程
這篇文章主要介紹了在Docker中部署Ruby on Rails的教程,Docker是當(dāng)下最火的虛擬機(jī),而本文所介紹的Ruby on Rails的部署則充分利用了Ruby中的rake這一炫酷的實(shí)現(xiàn)自動(dòng)化的方法,需要的朋友可以參考下2015-06-06
在Ruby on Rails中使用Rails Active Resource的教程
這篇文章主要介紹了在Ruby on Rails中使用Rails Active Resource的教程,本文來(lái)自于IBM官方網(wǎng)站技術(shù)文檔,需要的朋友可以參考下2015-04-04
Ruby實(shí)現(xiàn)二分搜索(二分查找)算法的簡(jiǎn)單示例
二分查找是一種在已經(jīng)過(guò)排序的數(shù)組中搜索指定元素用的算法,這里我們就來(lái)看一下Ruby實(shí)現(xiàn)二分搜索(二分查找)算法的簡(jiǎn)單示例:2016-07-07
Ruby中使用多線程隊(duì)列(Queue)實(shí)現(xiàn)下載博客文章保存到本地文件
這篇文章主要介紹了Ruby中使用多線程隊(duì)列(Queue)實(shí)現(xiàn)下載博客文章保存到本地文件,本文給出了實(shí)現(xiàn)代碼、并對(duì)代碼的核心部分做了講解,同時(shí)給出了運(yùn)行效果圖,需要的朋友可以參考下2015-01-01
Ruby的基礎(chǔ)語(yǔ)法入門(mén)學(xué)習(xí)教程
這篇文章主要介紹了Ruby的基礎(chǔ)語(yǔ)法入門(mén)學(xué)習(xí)教程,包括空白和保留字等書(shū)寫(xiě)的基本知識(shí)點(diǎn),需要的朋友可以參考下2015-10-10

