[ACCEPTED]-How do I set an attr_accessor for a dynamic instance variable?-attr-accessor
this answer doesn't pollutes the class space, example.. if 4 i do mine.my_number 4
then the other instances of Mine
will 3 not get the my_4
method.. this happens because 2 we use the singleton class of the object 1 instead of the class.
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
This can be accomplished using __send__
. Here:
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
0
Easy. You can dynamically define the attribute 2 reader inside the my_number method:
def my_number num
self.instance_variable_set "@my_#{num}", num
self.class.class_eval do
define_method("my_#{num}") { num }
end
end
see if 1 that works for you
You may want to use OpenStruct:
require "ostruct"
class Mine < OpenStruct
end
dude = Mine.new
dude.my_number = 1
dude.my_number # => 1
I don't know 2 why you'd want dude.my_1
to return 1 - isn't that 1 giving you back what you already have?
There's one problem with the two methods 13 here... if an instance variable is set in 12 one instance, its accessor will be available 11 to all instances, because you're defining 10 methods on self.class
instead of on self.
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
What you 9 probably want to do is modify only the instance 8 that has the instance variable:
class Mine
# ...
def my_number num
class << self
attr_accessor "my_#{num}"
end
self.send("my_#{num}=", num)
end
end
This way, instance 7 variables only get accessors on the objects 6 they were created for. I also didn't bother 5 with instance_variable_set, because if you're 4 setting an accessor, then I think it reads 3 better to just reuse that. But that's a 2 style call. The big deal here is calling 1 class << self
instead of self.class
.
older thread, but I found it useful thank 3 you. Here is the code Dorkus Prime's answer, but 2 also taking instance vars from name\values 1 in a hash
@cookies = browser.cookies.to_a
@cookies.each do |cookie|
self.class.__send__(:attr_accessor, "#{cookie[:name]}")
self.__send__("#{cookie[:name]}=",cookie[:value])
end
Yet another solution to add to the pile, define_singleton_method
:
class Mine
def my_number num
define_singleton_method("num_#{num}") { num }
end
end
One 5 side effect of all of these solutions is 4 that if you call it multiple times with 3 different numbers, you end up with a bunch 2 of methods on your object:
dude = Mine.new
dude.my_number 1
dude.my_number 5
dude.my_1
=> 1
dude.my_5
=> 5
We can fix this 1 by removing the old method:
class Mine
def my_number num
old_num = @num
if @num
# need to use `old_num` local variable
# instance var scope is different inside `class_eval`
singleton_class.class_eval { remove_method("num_#{old_num}") }
end
@num = num
define_singleton_method("num_#{num}") { @num }
end
end
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.