Ruby元编程:无法向模块发送方法

Trầ*_* Dự 2 ruby metaprogramming

例如,我有以下自定义类和模块:

module SimpleModule
  def hello_world
    puts 'i am a SimpleModule method'
  end

  def self.class_hello_world
    puts 'i am a SimpleModule class method'
  end
end

class SimpleClass
  def hello_world
    puts 'i am SimpleClass method'
  end

  def self.class_hello_world
    puts 'i am a SimpleClass class method'
  end
end
Run Code Online (Sandbox Code Playgroud)

我尝试使用方法在类和模块中调用这些方法 send

SimpleClass.send(class_hello_world)  # work
SimpleClass.new.send(hello_world)    # work
SimpleModule.send(class_hello_world) # work
SimpleModule.new.send(hello_world)   # not work
SimpleModule.send(hello_world)       # not work
Run Code Online (Sandbox Code Playgroud)

换句话说,我不知道如何调用hello_worldSimpleModule.如果该方法之前使用self定义,则可能.

我需要这样做,因为我想实现一个"自定义包含":包括从模块到另一个类的所有方法.

请告诉我怎么做.

Car*_*and 5

五个陈述

让我们一次一个地考虑这五个陈述(但是以与呈现的顺序不同的顺序).请注意,send参数必须是表示为字符串或符号的方法的名称.

SimpleModule.send("class_hello_world")
  # i am a SimpleModule class method
Run Code Online (Sandbox Code Playgroud)

这是正常的,尽管这种方法通常称为模块方法.一些常见的内置模块(如Math)仅包含模块方法.

SimpleClass.send(:class_hello_world)
  # i am a SimpleClass class method
Run Code Online (Sandbox Code Playgroud)

由于类是模块,因此行为与上述相同.class_hello_world通常被称为类方法.

SimpleClass.new.send(:hello_world)
  # i am SimpleClass method
Run Code Online (Sandbox Code Playgroud)

这是实例方法的正常调用.

SimpleModule.send("hello_world")
  #=> NoMethodError: undefined method `hello_world' for SimpleModule:Module
Run Code Online (Sandbox Code Playgroud)

没有模块方法hello_world.

SimpleModule.new.send(hello_world)
  #=> NoMethodError: undefined method `new' for SimpleModule:Module
Run Code Online (Sandbox Code Playgroud)

无法创建模块的实例.

include VS prepend

假设有人写道

SimpleClass.include SimpleModule
  #=> SimpleClass
SimpleClass.new.hello_world
  # i am SimpleClass method
Run Code Online (Sandbox Code Playgroud)

所以SimpleClass'原始方法hello_world不会被模块的方法用同名的方法覆盖.考虑一下SimpleClass'祖先.

SimpleClass.ancestors
  #=> [SimpleClass, SimpleModule, Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)

红宝石将寻找hello_worldSimpleClass--and找到它-考虑之前SimpleModule.

但是,可以使用Module#prepend放在SimpleModule#hello_world之前SimpleClass#hello_world.

SimpleClass.prepend SimpleModule
  #=> SimpleClass
SimpleClass.new.hello_world
  # i am a SimpleModule method
SimpleClass.ancestors
  #=> [SimpleModule, SimpleClass, Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)

绑定未绑定的方法

还有一件事你做.SimpleModule实例方法(这里只有一个)是未绑定的.您可以使用UnboundMethod#bind将每个绑定到一个实例,SimpleClass然后使用call或执行它send.

sc = SimpleClass.new
  #=> #<SimpleClass:0x007fcbc2046010> 
um = SimpleModule.instance_method(:hello_world)
  #=> #<UnboundMethod: SimpleModule#hello_world> 
bm = um.bind(sc)
  #=> #<Method: SimpleModule#hello_world> 
bm.call
  #=> i am a SimpleModule method
sc.send(:hello_world)
  #=> i am a SimpleModule method
Run Code Online (Sandbox Code Playgroud)