Защо не мога да използвам attr_accessor вътре в инициализацията?

Опитвам се да направя instance_eval, последвано от attr_accessor вътре в initialize, и продължавам да получавам това: ``initialize': undefined method 'attr_accessor'`. Защо това не работи?

Кодът изглежда така:

class MyClass
   def initialize(*args)
      instance_eval "attr_accessor :#{sym}"
   end
end

person Geo    schedule 14.11.2009    source източник


Отговори (3)


Не можете да извикате attr_accessor на екземпляра, защото attr_accessor не е дефиниран като метод на екземпляр на MyClass. Предлага се само за модули и класове. Подозирам, че искате да извикате attr_accessor в метакласа на екземпляра, като това:

class MyClass
  def initialize(varname)
    class <<self
      self
    end.class_eval do
      attr_accessor varname
    end
  end
end

o1 = MyClass.new(:foo)
o2 = MyClass.new(:bar)
o1.foo = "foo" # works
o2.bar = "bar" # works
o2.foo = "baz" # does not work
person sepp2k    schedule 14.11.2009
comment
class_eval е същото като да го поставите там, където сте написали self - person johannes; 15.11.2009
comment
Не, не е. class <<self; ...;end не е затваряне. Няма да имате достъп до varname вътре в него, но можете да получите достъп до него в блока class_eval. - person sepp2k; 15.11.2009
comment
отговорът на semiomant е добър. виж това. - person d_ethier; 08.09.2014

По-чиста реализация (NB: Това ще добави инструмента за достъп към ВСИЧКИ екземпляри на класа, а не само към единичния екземпляр, вижте коментарите по-долу):

class MyClass
  def initialize(varname)
    self.class.send(:attr_accessor, varname)
  end
end
person Rob d'Apice    schedule 24.05.2011
comment
Това дефинира инструмента за достъп като метод на екземпляр на MyClass. Така че, ако имате o1 = MyClass.new(:foo) и o2 = MyClass.new(:bar), и o1, и o2 имат инструменти за достъп както за foo, така и за bar, което не е очакваното поведение. - person sepp2k; 25.05.2011
comment
Съвсем правилно! Ето ги моите лодки. Ще оставя този отговор тук (с вашия коментар) за всеки, който може да го попадне. - person Rob d'Apice; 26.05.2011
comment
Решението на Роб изглежда много по-чисто. Но аз ще се придържам към решението на sepp2k, като имам достъпите само за един екземпляр. - person JAkk; 10.11.2012

Rob d'Apice го правипочтиправ. Просто трябва да напишете:

self.singleton_class.send(:attr_accessor, varname)

or

self.singleton_class.class_eval "attr_accessor :#{varname}"

или любимият ми вариант

self.singleton_class.class_exec do attr_accessor varname end

приемайки, че стойността на varname е символ

person semiomant    schedule 20.02.2013