Подтвердить что ты не робот

Как установить 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
4b9b3361

Ответ 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