2012-06-15 67 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