2011-02-11 55 views
29

我动态创建一个实例变量,我的类中:如何为动态实例变量设置attr_accessor?

class Mine 
    attr_accessor :some_var 

    def intialize 
    @some_var = true 
    end 

    def my_number num 
    self.instance_variable_set "@my_#{num}", num 
    end 
end 

我如何@my_#{num}现在作为一个ATTR价值?

例如我希望能够这样做:

dude = Mine.new 
dude.my_number 1 
dude.my_1 
=> 1 

回答

25

这个答案不污染种类空间,例如..如果我做mine.my_number 4那么Mine其他实例将不能获得my_4方法。这是因为我们使用了单独的类的对象,而不是类的。

class Mine 
    def my_number num 
    singleton_class.class_eval { attr_accessor "my_#{num}" } 
    send("my_#{num}=", num) 
    end 
end 

a = Mine.new 
b = Mine.new 
a.my_number 10 #=> 10 
a.my_10 #=> 10 
b.my_10 #=> NoMethodError 
23

这可以使用__send__完成。这里:

class Mine 
    attr_accessor :some_var 

    def intialize 
    @some_var = true 
    end 

    def my_number num 
    self.class.__send__(:attr_accessor, "my_#{num}") 
    self.__send__("my_#{num}=", num) 
    end 
end 

dude = Mine.new 
dude.my_number 1 
puts dude.my_1 

=> 1 
+2

从名称\值瓦尔这将定义存取所有的情况下,不只是你叫`my_number`的一个。我添加了一个额外的答案,只为您添加实例变量的实例添加方法。 – carpeliam 2011-06-06 21:40:14

10

很简单。您可以动态定义的属性读者my_number方法中:

def my_number num 
    self.instance_variable_set "@my_#{num}", num 
    self.class.class_eval do 
     define_method("my_#{num}") { num } 
    end 
    end 

看是否适合你

5

还有一个问题,这里的两个方法......如果一个实例变量被设置在一个实例中,其访问者将可用于所有实例,因为您正在定义方法self.class而不是自己。

dude = Mine.new 
dude.my_number 1 
puts dude.my_1 
dudette = Mine.new 
dudette.my_1 = 2 # works, but probably shouldn't 
dudette.my_number 2 
dude.my_2 = 3  # works, but probably shouldn't 

什么你可能想要做的是只修改有实例变量的实例:

class Mine 
    # ... 
    def my_number num 
    class << self 
     attr_accessor "my_#{num}" 
    end 
    self.send("my_#{num}=", num) 
    end 
end 

这样,实例变量只能得到他们对创建对象的存取。我也没有打扰instance_variable_set,因为如果你正在设置一个访问器,那么我认为重新使用它会更好。但这是一个风格的呼吁。这里的大问题是拨打class << self而不是self.class

+0

当我尝试这个时,我得到了错误“未定义的局部变量或方法`数量为#”。似乎这里的num变量超出了范围。 – kinofrost 2011-07-08 10:22:11

+0

啊,你是对的!我必须多想一想。同时,这不是正确的解决方案。 :/ – carpeliam 2011-07-08 23:12:35

+0

也没有为我工作。如果它不起作用,请删除您的答案。 – davidmontoyago 2015-04-16 19:13:24

3

您可能需要使用OpenStruct:

require "ostruct" 

class Mine < OpenStruct 
end 

dude = Mine.new 
dude.my_number = 1 
dude.my_number # => 1 

我不知道为什么你要dude.my_1返回1 - 这不就是给你回你已经拥有?

0

较旧的线程,但我发现它很有用,谢谢。下面是代码Dorkus总理的回答,还要考虑例如在哈希

@cookies = browser.cookies.to_a 

@cookies.each do |cookie| 
self.class.__send__(:attr_accessor, "#{cookie[:name]}") 
self.__send__("#{cookie[:name]}=",cookie[:value]) 
end 
相关问题