Ruby中的元编程错误

时间:2012-04-19 07:47:58

标签: ruby metaprogramming

好吧,这让我发疯了。这段代码的意思是我应该能够动态添加一个方法,前提是它的形式为object.plusnum,其中num是任意数字。我不太清楚如何让它发挥作用。到目前为止,这是我最好的拍摄,但我现在遇到了一些错误。

代码:

class Adder
def initialize(_val)
    @start_value = _val
end

def method_missing(method_name, *args)
    method = method_name.to_s
    if method.start_with?("plus") then
        num = method[4 .. method.length]
        if (/^[\d]+(\.[\d]+){0,1}$/ === num) then
            number = Integer(num)
            self.class_eval("def #{method} return @start_value + #{number} end")
        else
            super
        end
    else
        super
    end
end

end

我目前得到的错误是“class_eval”未定义。我对元编程和红宝石很新,这让我发疯了。

3 个答案:

答案 0 :(得分:2)

我认为你错了:)

第一次调用方法会产生不同的结果,而不是第二次调用它,所以可能你希望在定义之后立即调用这个方法。此外 - 您正在使用相当复杂的正则表达式,然后将值转换为Integer并删除点后的所有数字。

您正在使用class_eval并将字符串传递给它,这通常是个坏主意,出于安全和性能原因,应尽可能使用块。

我看起来如何:

class Adder
  def initialize(val)
    @start_value = val
  end

  def method_missing(method_name, *args)
    if method_name.to_s =~ /^plus(\d+)$/
      self.class.class_eval do
        define_method(method_name) { @start_value + $1.to_i }
      end
      self.send(method_name)
    else
      super
    end
  end
end

答案 1 :(得分:1)

    class Adder
def initialize(_val)
    @start_value = _val
end

def method_missing(method_name, *args)
    method = method_name.to_s
    if method.start_with?("plus") then
        num = method[4 .. method.length]
        if (/^[\d]+(\.[\d]+){0,1}$/ === num) then
            number = Integer(num)
            self.class.class_eval("def #{method}() return @start_value + #{number} end")
            eval(method)
        else
            super
        end
    else
        super
    end
end

end

a = Adder.new(0)
a.plus1

确保最后添加eval(方法)来调用方法,否则只返回nil才能创建方法。或者你可以简单地返回@start_value +#{number}

答案 2 :(得分:0)

  1. 您必须在class_eval课程上致电Adder,而不是在加法器实例上。
  2. 该字符串无效Ruby。在#{method}之后加上括号。
  3. 新版本的代码:

    class Adder
    def initialize(_val)
        @start_value = _val
    end
    
    def method_missing(method_name, *args)
        method = method_name.to_s
        if method.start_with?("plus") then
            num = method[4 .. method.length]
            if (/^[\d]+(\.[\d]+){0,1}$/ === num) then
                number = Integer(num)
                self.class.class_eval("def #{method}() return @start_value + #{number} end")
            else
                super
            end
        else
            super
        end
    end
    
    end
    
    a = Adder.new(0)
    a.plus1
    

    对我自己说,我建立这种方法的方式只是从

    开始
    class Adder
    end
    
    Adder.class_eval("def plus1() return 0 + 1 end")
    a = Adder.new
    a.plus1
    

    然后逐步用可配置的值替换硬连线值,而不是一次写入所有内容。