Reputation: 47
Working in Ruby, we have to use a 3rd party Framework, which has a class setup something like this:
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
I don't know how many "things" there are until run time. there could be 5 or their could be 50.
What I would like to do is something like:
pdc = Poorly_Designed_Class.new
for i in 0..numberOfThings do
pdc."thing#{i}".bar = value[i]
end
The above doesn't work.
I've also tried accessing it via:
instance_variable_set("pdc.thing#{i}.bar",value)
I understand that the class should be using an array or hash. Unfortunately I can't do anything about how the class is designed and we have to use it.
Is what i'm trying to do even possible?
Upvotes: 0
Views: 479
Reputation: 4927
You're using 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] }
That's a bit long and since attr_acessor :thingX
defines getter methods, it's usually preferable to call them with Object#public_send
instead of directly accessing the instance variable (a getter method might do something else than just returning a value):
1.upto(numberOfThings) { |i| pdc.public_send("thing#{i}").bar = value[i] }
Upvotes: 0
Reputation: 369428
You could either try to call the getter (preferably, since it honors encapsulation):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things.times do |i|
pdc.public_send(:"thing#{i}").bar = value[i]
end
or get the instance variable (less preferred, since it breaks encapsulation):
pdc = PoorlyDesignedClass.new
1.upto(number_of_things) do |i|
pdc.instance_variable_get(:"@thing#{i}").bar = value[i]
end
So, you were on the right track, there were just two problems with your code: instance variable names start with an @
sign, and .
is not a legal character in an identifier.
Upvotes: 1