Как использовать class_eval для значения нескольких атрибутов - PullRequest
2 голосов
/ 06 марта 2012

Я пытался расширить код из этого вопроса для хранения записей значения атрибута. Тем не менее, мой код не работает в случае более чем одного атрибута. Вот код:

class Class
  def attr_accessor_with_history(attr_name)
    attr_name = attr_name.to_s
    attr_reader attr_name

    ah=attr_name+"_history"
    attr_reader ah 

    class_eval %Q{          
      def #{attr_name}= (attr_name)
        @attr_name=attr_name

        if @ah == nil
          @ah=[nil]
        end
        @ah.push(attr_name)
      end
      def #{ah}
        @ah
      end  

      def #{attr_name}
        @attr_name
      end
     }
  end
end

Здесь фиктивный класс для тестирования

class Foo
  attr_accessor_with_history :bar
  attr_accessor_with_history :bar1
end

f = Foo.new
f.bar = 1
f.bar = 2
f.bar1 = 5
p f.bar_history  
p f.bar1_history  

По некоторым причинам, f.bar и f.bar1 оба возвращают 5 и f.bar_history = f.bar1_history = [nil, 1, 2, 5]. Есть идеи, почему это так?

1 Ответ

2 голосов
/ 06 марта 2012

Вы использовали @ah и @attr_name вместо @#{ah} и @#{attr_name} при получении / настройке в методах. Это означало, что они всегда устанавливали и возвращали одну и ту же переменную экземпляра, а не разные динамически именуемые.

class Class
  def attr_accessor_with_history(attr_name)
    class_eval %{
      attr_reader :#{attr_name}, :#{attr_name}_history

      def #{attr_name}=(value)
        @#{attr_name} = value
        @#{attr_name}_history ||= [nil]
        @#{attr_name}_history << value
      end
     }
  end
end

Я также, как правило, немного очистил ваш код, чтобы сделать его (я думаю) более ясным и лаконичным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...