2012-06-15 31 views
0

工作,我在initialize方法使用eval()紅寶石二傳手不EVAL

class ActiveRecord::FakedModel 

    def initialize(attributes={}) 
    attributes = {} if not attributes 

    attributes.each do |attr_name, value| 
     eval("@#{attr_name}=#{value.inspect}") 
    end 

    @attributes = attributes 
    end 
... 
end 

,並有清洗空格二傳手:

class ContactForm < ActiveRecord::FakedModel 
    attr_accessor :plz 

    def plz=(plz) 
    @plz = plz.try(:delete,' ') 
    end 
... 
end 

但此setter不能當我工作在散列中給出'plz':

c=ContactForm.new(:plz=>' 1 3 3 3 ') 
=> #<ContactForm:0x1024e3a10 @attributes={:plz=>" 1 3 3 3 "}, @plz=" 1 3 3 3 "> 

使用setter在有什麼問題?

回答

3

您的eval語句不調用setter方法,它直接設置實例變量。如果你想讓你的構造函數使用的setter,使用send

attributes.each do |attr_name, value| 
    send "#{attr_name}=", value 
end 
2

使用Object#instance_variable_set設置實例變量的方法。

attributes.each do |attr_name, value| 
    self.instance_variable_set("@#{attr_name}", value.inspect) 
end 
+1

這是一個很好的提示,但不是一個真正的答案的問題,這是不被調用的二傳手。 –

1

要動態執行的方法,使用Object#send

class ActiveRecord::FakedModel 

    def initialize(attributes={}) 
    attributes = {} if not attributes 

    attributes.each do |attr_name, value| 
     send("#{attr_name}=", value) 
    end 

    @attributes = attributes 
    end 

end 

您還可以獲得無需調用inspect並強制轉換爲變量字符串的優勢。

您也可以使用Object#instance_variable_set,但在這種情況下,您繞過了setter方法,並且如果在setter中具有某些自定義邏輯(如投射),則代碼將無法按預期工作。

class ActiveRecord::FakedModel 

    def initialize(attributes={}) 
    attributes = {} if not attributes 

    attributes.each do |attr_name, value| 
     instance_variable_set("@#{attr_name}", value) 
    end 

    @attributes = attributes 
    end 

end