2012-03-03 97 views
0

我想通過元編程跟蹤每個類變量的歷史。我不喜歡問這樣的問題,但花了我5個小時才能寫出這些,從現在開始我不知道如何繼續(我是Ruby新手,這是我第一次玩元編程)。元編程紅寶石

以我的理解;當attr_accessor_with_history在類中初始化時,它應該執行它所包含的代碼。因此,每次這個方法初始化時,根據元編程的優點,每個類將對我描述的問題有自己的方法。

在我提交的代碼中,讀者已被正確初始化,但我無法對class_eval部分中的代碼進行相同的說明。我需要澄清一下爲什麼代碼不工作,以及一般的元編程。

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{ 
    @#{attr_name}_history=[nil] 
    def #{attr_name}=(value) 
     #{attr_name}=value 
     #{attr_name}_history.push(value) 
    end 
    } 
    " 
    end 
end 

class Klass 
    attr_accessor_with_history :kamil 
    def initialize(value) 
    kamil = value 
    end 
end 

a = Klass.new(5) 
a.kamil = 1 
puts "#{a.kamil_history}" 
+2

我不相信你應該換你的'%Q'引號的'class_eval'位。 '%Q {...}'評估爲內插字符串。 – mrlee 2012-03-03 17:54:21

回答

0

要自我調用setter方法,您需要編寫self.foo = bar。如果你只寫foo = bar它只會創建一個名爲bar的局部變量而不會調用任何方法。所以你需要相應地改變第11行和第23行。

此外,通過使用引號內的%Q {},您的整個eval實際上只會計算一個字符串。您應該使用%Q {}或引號 - 而不是兩者。實際上,你可能根本不應該使用字符串,但可以使用塊調用class_eval並在塊內使用define_method

4

薩斯當然是吧?你應該知道實例變量應該以@符號開頭。因此,例如在你的初始化方法中,什麼是kamil?如果它是一個實例變量,它應該是@kamil。我還建議你修改你的關於這個考慮的論點。

編輯:

@#{attr_name}_history=[nil]

我也會把這段代碼放到某種方法上,因爲它不是很好的方式來初始化你的實例變量。

+1

+1「Saas course,呵?」 – 2012-03-06 05:35:57

1

每次調用此方法時,都會調用方法'def attr_accessor_with_history(attr_name)'中的代碼。當寫 Klass類 attr_accessor_with_history你把它在你的類:卡米爾 ..

當Ruby進程這一行「attr_accessor_with_history:卡米爾」,它會實際運行從方法Class.attr_accessor_with_history的代碼。 class_eval內的字符串被解釋爲代碼,因爲它是由您直接編寫的。

最後,你的解釋的代碼將是這樣的:

Klass類 ..

@ kamil_history = [無]

def kamil=(value) 
    kamil=value 
    kamil_history.push(value) 
end 

看這個問題? 它必須是@ kamil = value,否則它會再次調用方法'kamil =',而不是訪問實例變量@kamil。

同樣,它必須是'@ kamil_history.push(..)'。

您可以在這裏找到工作代碼: http://maxivak.com/ruby-metaprogramming-and-own-attr_accessor/