【问题标题】:Ruby metaprogramming: adding @variables to existing 'initialize' method (using class_eval) [duplicate]Ruby元编程:将@variables添加到现有的'initialize'方法(使用class_eval)[重复]
【发布时间】:2012-10-09 08:52:50
【问题描述】:

可能重复:
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

现在,当我测试一个变量的脚本时。它工作正常。但是当我尝试创建两个或更多变量时(像这样)......

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 的第二次调用中被覆盖,因此第一个变量的记录被破坏。

我不知道如何解决这个问题。我已经尝试调用 'super' 。有什么线索吗?

【问题讨论】:

  • 让您知道这是 edx.org 软件即服务课程的家庭作业项目。
  • 谢谢大家。这是家庭作业的一部分,是的
  • 并且该班级的荣誉代码明确禁止发布作业。你能把它删掉吗?

标签: ruby metaprogramming class-eval


【解决方案1】:

在您的 setter 方法中,只需检查历史实例变量是否已经初始化:

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

如果之前没有设置默认值,您需要为历史变量设置另一个 getter:

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

然后你可以删除你的初始化方法,顺便说一句容易被覆盖。

【讨论】:

  • @AlexD 我不这么认为,因为问题中history ivar的初始状态是[nil]。这是否是一个好方法取决于业务领域。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 2023-02-10
相关资源
最近更新 更多