用于访问 Ruby 中的 class 方法的动态变量

Dynamic Variables to access class methods in Ruby

在 Ruby 中工作,我们必须使用第 3 方框架,它有一个 class 设置如下:

class Foo 

    attr_accessor :bar

    def initialize() 
    end

end

class Poorly_Designed_Class

    attr_accessor :thing1
    attr_accessor :thing2
    attr_accessor :thing3
    attr_accessor :thing4
    attr_accessor :thing5

    # through :thing_n .. number defined at runtime

    def initialize()
        @thing1 = Foo.new
        @thing2 = Foo.new
        @thing3 = Foo.new
        @thing4 = Foo.new
        @thing5 = Foo.new
    end

end

到运行时才知道有多少"things"。可能有 5 个,也可能有 50 个。

我想做的是:

pdc = Poorly_Designed_Class.new
for i in 0..numberOfThings do
    pdc."thing#{i}".bar = value[i]
end

以上方法无效。

我也试过通过以下方式访问它:

instance_variable_set("pdc.thing#{i}.bar",value)

我知道 class 应该使用数组或散列。不幸的是,我无法对 class 的设计方式做任何事情,我们必须使用它。

我想做的事情有可能吗?

您可以尝试调用 getter(最好是,因为它支持封装):

pdc = PoorlyDesignedClass.new
1.upto(number_of_things.times do |i|
  pdc.public_send(:"thing#{i}").bar = value[i]
end

或者获取实例变量(不太推荐,因为它破坏了封装):

pdc = PoorlyDesignedClass.new
1.upto(number_of_things) do |i|
  pdc.instance_variable_get(:"@thing#{i}").bar = value[i]
end

所以,您的方向是正确的,您的代码只有两个问题:实例变量名称以 @ 符号开头,并且 . 不是标识符中的合法字符.

您正在使用 Object#instance_variable_set incorrectly. The first argument must be a string or a symbol representing the name of an instance variable including the @ prefix: e.g. "@thing{i}". However you actually want to get the value of an instance variable and then send #bar= to it. That can be done with Object#instance_variable_get:

1.upto(numberOfThings) { |i| pdc.instance_variable_get("@thing#{i}").bar = value[i] }

有点长,因为 attr_acessor :thingX 定义了 getter 方法,通常最好用 Object#public_send 调用它们而不是直接访问实例变量(getter方法可能会做一些事情,而不仅仅是返回一个值):

1.upto(numberOfThings) { |i| pdc.public_send("thing#{i}").bar = value[i] }