我试图通过元编程跟踪每个类变量的历史记录。我不喜欢问这些问题,但我花了5个小时才能写出来,从现在起我不知道如何继续(我是红宝石的新手,这是我第一次玩元编程。)
在我的理解中;当attr_accessor_with_history
在类中初始化时,它应该执行它包含的代码。因此,每次这个方法初始化时,通过元编程的优点,每个类都将有自己的方法来解决我所描述的问题。
在我提交的代码中,读者已正确初始化,但我不能对class_eval
部分中的代码说同样的内容。我需要澄清代码无效的原因,以及一般的元编程。
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{
@#{attr_name}_history=[nil]
def #{attr_name}=(value)
#{attr_name}=value
#{attr_name}_history.push(value)
end
}
"
end
end
class Klass
attr_accessor_with_history :kamil
def initialize(value)
kamil = value
end
end
a = Klass.new(5)
a.kamil = 1
puts "#{a.kamil_history}"
答案 0 :(得分:4)
kamil
是什么?如果它是实例变量,则应为@kamil
。我还建议你修改关于这个考虑的class_eval
论点。
编辑:
@#{attr_name}_history=[nil]
。
我还会将此代码放到某个方法中,因为从任何方法初始化实例变量都不是很好。
答案 1 :(得分:1)
每次调用此方法时,都会调用方法'def attr_accessor_with_history(attr_name)'中的代码。你写的时候在课堂上叫它 Klass班 attr_accessor_with_history:kamil ..
当Ruby处理这行'attr_accessor_with_history:kamil'时,它实际上将运行Class.attr_accessor_with_history方法中的代码。 class_eval中的字符串被解释为直接由您编写的代码。
最后,你的解释代码将是这样的:
类Klass ..
@ kamil_history = [nil]
def kamil=(value)
kamil=value
kamil_history.push(value)
end
看到问题? 它必须是@ kamil = value,否则它将再次调用方法'kamil =',而不是访问实例变量@kamil。
同样,它必须是'@ kamil_history.push(..)'。
您可以在此处找到工作代码: http://maxivak.com/ruby-metaprogramming-and-own-attr_accessor/
答案 2 :(得分:0)
要在self上调用setter方法,您需要编写self.foo = bar
。如果您只是编写foo = bar
,它将只创建名为bar的局部变量,而不是调用任何方法。因此,您需要相应地更改第11行和第23行。
同样通过在引号内使用%Q {},您的整个eval实际上只会计算为字符串。您应该使用%Q {}或引号 - 而不是两者。事实上,您可能根本不应该使用字符串,而是使用块调用class_eval并在块内使用define_method
。