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

5

我有一个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
3个回答

13

在类定义的(class << self)范围内,变量name不可用。它没有抛出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

@Aditya Sanghi:感谢您的纠正。但我实际上是想切换到插值,它是全方位更好的选择(更快,垃圾少,读起来更清晰,而且可以与符号一起使用!)。 - Chuck
2
你可以使用 self.class.class_eval 来代替 eigenclass = class << self; self; end - poorva

1
问题在于 class << self 并不像闭包一样运作,这意味着变量 name 在方法定义内部是不可用的。
另一方面,当你使用 class_eval 时,你正在传递一个块(Proc),它是一个闭包,这意味着当前绑定中的所有局部变量都将在块体内可用。

0

当调用method_missing时,定义动态方法的另一种方式是调用define_singleton_method

class Person
  def method_missing(method_name, *args, &block)
    define_singleton_method(method_name) do
      puts "I'm a new method called #{__method__}"
    end
    # Add this is you want to automatically call the new method
    public_send(method_name)
  end

  # Add this for proper introspection.
  def respond_to_missing?(method_name, include_private = false)
    true
  end
end

这将为您提供

Person.new.test_method # => "I'm a new method called test_method"

注意:该解决方案与其他提出的解决方案略有不同,它仅在当前实例上定义方法而不是类。相同类的新实例将不具有新定义的方法;但通常在method_missing中定义新方法时,这正是人们所追求的目标。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接