2
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

Class.attr_accessor_with_historyと同じ機能を提供するattr_accessorだけでなく、属性がこれまでに持っていたすべての値を追跡するメソッドがあります。

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

しかし、

> a = Example.new; a.foo_history
=> nil

そしてそれはあるべきです[nil

各値が次のように初期化されるクラスに 単一のinitializeメソッドを定義するにはどうすればよいですか?Example…_history[nil]

4

2 に答える 2

10

最善の策は、履歴のカスタム リーダーを (カスタム ライターと共に) 定義することだと思います。

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_eval(必要なく使用すると眉をひそめます)。

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
于 2012-07-22T21:40:48.327 に答える