Ruby - 如何在模块中动态调用实例方法

3
我希望能够动态调用实例方法。我发现可以使用 send, call, eval 来实现这一点。有一些关于动态调用类方法的示例,但我还没有弄清楚如何将其应用到实例方法上。
例如:
module MyModule
  def Foo
    puts "hello"
  end
end

可以通过以下方式列出实例方法名称:

MyModule.instance_methods
#=> [:Foo]

但我不知道如何调用这个方法:
MyModule.send("Foo")
#=> NoMethodError: undefined method `Foo' for MyModule:Module

MyModule.method("Foo").call
#=> NameError: undefined method `Foo' for class `Module'

eval 'MyModule.Foo'
#=> NoMethodError: undefined method `Foo' for MyModule:Module

如何通过方法名称调用实例方法,例如Foo


1
请注意,eval 'MyModule.Foo'MyModule.Foo是相同的。 - Stefan
4
这是一个“实例方法”。你需要一个实例。 - Jörg W Mittag
1个回答

11

免责声明:这是一种不良的做法,几乎没有意义:

MyModule.instance_method(:Foo) # #<UnboundMethod: MyModule#Foo>
        .bind(Object)          # #<Method: MyModule#Foo>
        .call                  #=> hello

不能调用未绑定的方法,因此您必须首先将其绑定到某个对象上。

参考资料:


如果你将该方法设置为单例方法,就会更容易。

module MyModule
  def self.Foo
    puts "hello"
  end
end

MyModule.Foo
#=> "hello"

另一种选择是使用module_function(当使用此选项时,请了解该方法的包含对象的可见性):

module MyModule
  def Foo
    puts "hello"
  end
  module_function :Foo
end

MyModule.Foo
#=> "hello"

还有一种方法是使用extend self

module MyModule
  def Foo
    puts "hello"
  end

  extend self
end

MyModule.Foo
#=> "hello"

顺便说一下,在方法名中使用大写字母并不是传统做法。在Ruby中,只有很少的情况可以这样使用,而你的情况绝不是其中之一 :)


2
这里值得一提的是module_functionextend self - Aleksei Matiushkin
非常感谢!单例方法方案对我有用! - jerry
1
不需要编辑模块主体,只需使用 Class.new.include(MyModule).new.Foo 这种丑陋但仍然可行的方式。 - Ilya
1
@Ilya,你不需要创建一个类:Object.new.extend(MyModule).Foo - Stefan
@Stefan Object.extend(MyModule).Foo 更短(尽管会引起一定的污染) :) - Andrey Deineko
@Stefan,是的,它有点简单,但仍然太复杂了,不能只称之为一个方法 :) - Ilya

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