Ruby 正在初始化具有历史记录的类似“attr\u访问器”的方法

Ruby 正在初始化具有历史记录的类似“attr\u访问器”的方法,ruby,metaprogramming,Ruby,Metaprogramming,但是, 它应该是[nil 如何为示例类定义单个初始化方法 …\u history值将被初始化为[nil]?我认为,最好的办法是为历史定义一个自定义读取器(以及自定义编写器) 一个班的学生 班级 def attr_访问器_和_历史记录(attr_名称) attr\u name=attr\u name.to\u s 属性读取器属性名称 属性读取器属性名称+“\u历史” 等级评估%Q{ def#{attr_name}=(val) 如果@#{attr_name}u历史 @#{attr\u name}\

但是,

它应该是
[nil

如何为
示例
类定义单个
初始化
方法
…\u history
值将被初始化为
[nil]

我认为,最好的办法是为历史定义一个自定义读取器(以及自定义编写器)

一个班的学生

班级
def attr_访问器_和_历史记录(attr_名称)
attr\u name=attr\u name.to\u s
属性读取器属性名称
属性读取器属性名称+“\u历史”
等级评估%Q{
def#{attr_name}=(val)
如果@#{attr_name}u历史

@#{attr\u name}\u history这个“attr\u访问器\u with\u history”在哪里问题来自?它是。它来自Coursera上“软件工程为软件即服务”课程的第一个家庭作业。@AndrewMarshall:是的,似乎我甚至回答了几个问题。但后来忘了:)这是原始帖子中的内容:)但我知道你可以写得更好。)我已经更改了我的答案,希望你在le更喜欢它ast it works)@YuriBarbashov:你能不能也添加一些例子(比如在我的第一个片段中),我可以复制/粘贴/运行它?:)起初我不明白你为什么要提供完整的答案片段,现在我知道了。编辑我的答案)任何让提问者朝着正确的方向前进的答案都是有帮助的,但一定要试着在你的答案中提及任何限制、假设或简化。简洁是可以接受的,但更完整的解释是可以接受的更好。
class Class
  def attr_accessor_with_history(attr_name)
    attr_name = attr_name.to_s
    attr_reader attr_name
    attr_reader attr_name + "_history"
    class_eval %Q{
      def #{attr_name}=(new_value)
        @#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
        @#{attr_name}_history << @#{attr_name} = new_value
      end
    }
  end
end

class Example
  attr_accessor_with_history :foo
  attr_accessor_with_history :bar
end
> a = Example.new; a.foo = 2; a.foo = "test"; a.foo_history
=> [nil, 2, "test"]
> a = Example.new; a.foo_history
=> nil
class Class
  def attr_accessor_with_history(attr_name)
    attr_name = attr_name.to_s
    attr_reader attr_name
    class_eval %Q{
      def #{attr_name}_history
        @#{attr_name}_history || [nil] # give default value if not assigned
      end

      def #{attr_name}=(new_value)
        @#{attr_name}_history ||= [nil] # shortcut, compare to your line
        @#{attr_name}_history << @#{attr_name} = new_value
      end
    }
  end
end

class Example
  attr_accessor_with_history :foo
  attr_accessor_with_history :bar
end

a = Example.new; a.foo = 2; a.foo = "test"; 
a.foo_history # => [nil, 2, "test"]

a = Example.new
a.foo_history # => [nil]
class Class
  def attr_accessor_with_history(attr_name)
    attr_name = attr_name.to_s
    attr_reader attr_name

    define_method "#{attr_name}_history" do
      instance_variable_get("@#{attr_name}_history") || [nil]
    end

    define_method "#{attr_name}=" do |new_value|
      v = instance_variable_get("@#{attr_name}_history")
      v ||= [nil]
      v << new_value

      instance_variable_set("@#{attr_name}_history", v)
      instance_variable_set("@#{attr_name}", new_value)
    end
  end
end