如何使用method_missing动态声明方法?

时间:2011-11-10 05:12:51

标签: ruby closures metaprogramming

我有一个ruby程序,我想接受用户编写的方法,并用该名称创建一个新方法。我试过这个:

def method_missing(meth,*args,&block)
  name = meth.to_s
  class << self
    define_method(name) do
      puts "hello " + name
    end
  end
end

我收到以下错误:

`define_method': interning empty string (ArgumentError) in 'method_missing'

有什么想法吗?谢谢。

编辑:

我以不同的方式工作,但我仍然很好奇如何以这种方式做到这一点。这是我的代码:

def method_missing(meth,*args,&block)
  Adder.class_eval do
    define_method(meth) do
      puts "hello " + meth
    end
  end
  send("#{meth}")
end

2 个答案:

答案 0 :(得分:12)

变量name在类定义(class << self)范围内不可用。它没有抛出NameError,因为你已经覆盖了method_missing

要执行您要执行的操作,您需要使用name保留范围。为了做到这一点,你必须只使用基于块的方法(例如class_eval)而不是直接打开类,所以像这样:

def method_missing(meth,*args,&block)
  name = meth.to_s
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    define_method(name) do
      puts "hello " + name
    end
  end
end

但实际上,meth中的符号已足够 - 您根本不需要名称。 (尽管你仍然需要上述技术。)最重要的是,你想立即执行该方法。最简单的方法就是重新发送消息:

def method_missing(meth,*args,&block)
  eigenclass = class << self; self; end
  eigenclass.class_eval do
    define_method(meth) do
      puts "hello #{meth}"
    end
  end
  send(meth, *args, &block)
end

答案 1 :(得分:1)

问题是class << self不作为闭包,这意味着变量name将无法在方法定义中使用。

另一方面,当你使用class_eval时,你传递的是一个块(Proc),这是一个闭包,这意味着当前绑定中的所有局部变量都可用在块体内。