元编程ruby for

时间:2012-03-03 17:46:55

标签: ruby metaprogramming

我试图通过元编程跟踪每个类变量的历史记录。我不喜欢问这些问题,但我花了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}"

3 个答案:

答案 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