2011-09-23 29 views
18

我试图从哈希(与嵌套哈希)生成attr_reader,以便它自动镜像instance_variable创建。Ruby:动态生成attribute_accessor

这里是我到目前为止有:

data = {:@datetime => '2011-11-23', :@duration => '90', :@class => {:@price => '£7', :@level => 'all'}} 


class Event 
#attr_reader :datetime, :duration, :class, :price, :level 
    def init(data, recursion) 
    data.each do |name, value| 
    if value.is_a? Hash 
     init(value, recursion+1) 
    else 
     instance_variable_set(name, value) 
     #bit missing: attr_accessor name.to_sym 
    end 
    end 
end 

但我不能找到一个办法做到这一点:(

回答

33

你需要调用(私人)类方法attr_accessorEvent类:

self.class.send(:attr_accessor, name) 

我建议你在这一行添加@

instance_variable_set("@#{name}", value) 

并且不要在散列中使用它们。

data = {:datetime => '2011-11-23', :duration => '90', :class => {:price => '£7', :level => 'all'}} 
+0

你是我的新朋友!!!!这只是工作,是如此简单...红宝石是魔术:)而你是一个明星:)(我很高兴,因为我看了一会儿) –

+0

只是一个简单的问题更多,是否有任何方式预先命名包含散列的访问者名称,以便我可以调用my_class.class.price,或类似的东西? –

+0

首先,'class'是一个保留关键字,不要使用它。你在这里评论中的第二个问题超出了这个特定问题的范围。你可能想开始一个新的问题,因为它处理递归等,而不是属性访问器。 (PS,不要忘记接受最好的答案) – rdvdijk

1

attr_accessor是一个类方法,因此需要在类上调用它。它也是一个私有方法,因此您需要在类对象为self的上下文中调用它。

举个例子:

class C 
    def foo 
    self.class.instance_eval do 
     attr_accessor :baz 
    end 
    end 
end 

创造C实例,并在该实例上调用foo,该实例后 - 和所有未来实例 - 将包含方法bazbaz=

3

你可以做一点的元魔解决这个问题,使用的method_missing:

class Event 
    def method_missing(method_name, *args, &block) 
    if instance_variable_names.include? "@#{method_name}" 
     instance_variable_get "@#{method_name}" 
    else 
     super 
    end 
    end 
end 

这将完成是允许访问对象通过object.variable语法实例变量,如果对象具有这些变量而不需要通过attr_accessor来修改整个类。