ruby中的class_eval
最近幾天在做一個ruby作業的時候遇到了一些問題,題目是這樣要求的
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s
attr_reader attr_name
attr_reader attr_name + "_history"
class_eval %Q{ }
end
end
class Foo
attr_accessor_with_history :bar
attr_accessor_with_history :baw
end
要求自己寫一個訪問器屬性,可以記錄下來該屬性所描述的類中數據成員的所有歷史值(原諒我對ruby從沒有系統學習過,所以只有用自己在c++或者c#中知道的術語來描述)。
由于是在編譯階段就自動生成相應方法,所以這里就用了class_eval 函數。
盡管對語言不熟悉,但是我還是在一開始初步形成思路,也就是在class_eval 中添加一個方法模板,使得每個有該屬性attr_accessor_with_history (或者說關鍵字?)的屬性的類都自動的生成一個相關的setter,在setter中進行對歷史值列表的維護。
想起來固然簡單,但是由于對ruby的符號和元編程都毫無了解,實際開始操作的時候就發現了其中有很多沒辦法忽視的問題。
第一,我應該如何在class_eval 的字符串參數中訪問到只知道變量名字字符串的變量?
經過一番學習之后,了解到了在編譯階段,會自動的將#{str}替換成str對應的變量,知道了這些,就方便了很多。
至少了解到該如何define這個setter的模板。
def #{attr_name}=(value)
end
第二,在這個參數內部如何訪問類的成員又成了一個問題,尤其是訪問成員的歷史值數組。
經過多次嘗試,以及對手冊又多次理解,發現這個問題其實跟上一個是相同的,由于#{str}只是一種格式,其中的str是任何返回值為字符串的表達式都可以自動替換成相應變量。
所以就簡單的寫了一個if就搞定了。
if #{attr_name} == nil then
@#{(attr_name + "_history")} = Array.new
@#{(attr_name + "_history")}.push(nil)
end
@#{attr_name} = value
@#{(attr_name + "_history")}.push(value)
posted on 2012-03-05 17:19 fingerpass 閱讀(818) 評論(0) 收藏 舉報
浙公網安備 33010602011771號