2

重複の可能性:
Ruby.Metaprogramming. class_eval

私はこの小さなプロジェクトを持っています。目標は、作成された変数に割り当てられたすべての値の記録を保持する「attr_accessor_with_history」メソッドを作成することです。コードは次のとおりです。

class Class
  def attr_accessor_with_history(attr_name)
  attr_name = attr_name.to_s   # make sure it's a string
  attr_reader attr_name        # create the attribute's getter
  attr_reader attr_name+"_history" # create bar_history getter

  a = %Q{
        def initialize
        @#{attr_name}_history = [nil]
    end         

    def #{attr_name}
        @#{attr_name} 
    end 

    def #{attr_name}=(new_value)
        @#{attr_name}=new_value 
        @#{attr_name}_history.push(new_value)
    end }
      puts a

      class_eval(a)

  end
end

ここで、1 つの変数についてスクリプトをテストします。それは正常に動作します。しかし、2 つ以上の変数を作成しようとすると (このように) ....

class Foo
attr_accessor_with_history :bar
attr_accessor_with_history :lab
end

a = Foo.new
a.bar = 45
a.bar = 5
a.bar = 'taat'
puts a.bar_history

b = Foo.new
b.lab = 4
b.lab = 145
b.lab = 'tatu'
puts b.lab_history

....Ruby は、「(class_eval) bar_history.push(new_value) に対して存在しない 'push' メソッド」を発行します。attr_accessor_with_history の 2 回目の呼び出しで「initialize」メソッドがオーバーライドされるため、最初の変数のレコードが破棄されると思います。

これを回避する方法がわかりません。私はすでに 'super' を呼び出してみました。どんな手掛かり ?

4

1 に答える 1

2

セッター メソッドで、履歴インスタンス変数が既に初期化されているかどうかを確認します。

def #{attr_name}=(new_value)
  @#{attr_name}=new_value
  @#{attr_name}_history ||= [nil]
  @#{attr_name}_history.push(new_value)
end

以前に設定されていなかった場合にデフォルト値を設定する、履歴変数用の別のゲッターが必要になります。

def #{attr_name}_history
  @#{attr_name}_history ||= [nil]
end

次に、初期化メソッドを削除できます。これは、ところで上書きされる脆弱性がありました。

于 2012-10-09T10:18:39.133 に答える