Как установить 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
Ответы
Ответ 1
этот ответ не загрязняет пространство классов, например.. если я делаю 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
Ответ 2
Это можно сделать, используя __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
Ответ 3
Легко. Вы можете динамически определять считыватель атрибутов внутри метода 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
посмотреть, работает ли это для вас
Ответ 4
Здесь существует одна проблема с двумя методами... если переменная экземпляра задана в одном экземпляре, ее accessor будет доступен для всех экземпляров, потому что вы определяете методы на 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
.
Ответ 5
Вы можете использовать OpenStruct:
require "ostruct"
class Mine < OpenStruct
end
dude = Mine.new
dude.my_number = 1
dude.my_number # => 1
Я не знаю, почему вы хотите, чтобы dude.my_1
возвращал 1 - это не значит, что вы возвращаете то, что у вас уже есть?
Ответ 6
предыдущая тема, но я сочла это полезным. Вот код ответа Dorkus Prime, но также принимающий экземпляры vars от имени \values в хеше
@cookies = browser.cookies.to_a
@cookies.each do |cookie|
self.class.__send__(:attr_accessor, "#{cookie[:name]}")
self.__send__("#{cookie[:name]}=",cookie[:value])
end