Ruby元编程:无法将方法发送到模块 [英] Ruby metaprogramming: cannot send a method to a module
问题描述
例如,我有以下自定义类和模块:
For example I have following custom class and module:
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
我尝试使用方法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
换句话说,我不知道如何从SimpleModule
调用hello_world
.如果该方法是使用self before定义的,则是可能的.
In other word, I don't know how to invoke hello_world
from SimpleModule
. It is possible if that method is defined with self before.
我需要这样做是因为我想实现一个"custom-include":包括从模块到另一个类的所有方法.
I need to do this because I want to implement a "custom-include": that include all methods from module to another class.
请告诉我该怎么做.
推荐答案
这五个语句
让我们一次考虑这五个语句(但顺序与所呈现的顺序不同).请注意,send
的参数必须是表示为字符串或符号的方法的名称.
Let's consider those five statements one at a time (but in a different order than as presented). Note that send
's argument must be the name of the method expressed as a string or symbol.
SimpleModule.send("class_hello_world")
# i am a SimpleModule class method
这很正常,尽管此类方法通常称为模块方法.一些常见的内置模块(例如 Math )包含模块方法
This is normal, though such methods are normally called module methods. Some common built-in modules, such as Math, contain module methods only.
SimpleClass.send(:class_hello_world)
# i am a SimpleClass class method
由于类是模块,所以行为与上述相同. class_hello_world
通常被称为类方法.
Since a class is a module, the behaviour is the same as above. class_hello_world
is usually referred to as a class method.
SimpleClass.new.send(:hello_world)
# i am SimpleClass method
这是实例方法的常规调用.
This is the normal invocation of an instance method.
SimpleModule.send("hello_world")
#=> NoMethodError: undefined method `hello_world' for SimpleModule:Module
没有模块方法hello_world
.
SimpleModule.new.send(hello_world)
#=> NoMethodError: undefined method `new' for SimpleModule:Module
一个人无法创建模块的实例.
One cannot create an instance of a module.
include
与prepend
include
vs prepend
假设一个人写过
SimpleClass.include SimpleModule
#=> SimpleClass
SimpleClass.new.hello_world
# i am SimpleClass method
因此,SimpleClass
的原始方法hello_world
不会被相同名称的模块方法所覆盖.考虑SimpleClass
的祖先.
so SimpleClass
' original method hello_world
is not overwritten by the module's method by the same name. Consider SimpleClass
' ancestors.
SimpleClass.ancestors
#=> [SimpleClass, SimpleModule, Object, Kernel, BasicObject]
在考虑SimpleModule
之前,Ruby将在SimpleClass
中寻找hello_world
并找到它.
Ruby will look for hello_world
in SimpleClass
--and find it--before considering SimpleModule
.
但是,可以使用 Module#prepend 将SimpleModule#hello_world
放在SimpleClass#hello_world
之前.
One can, however, use Module#prepend to put SimpleModule#hello_world
before SimpleClass#hello_world
.
SimpleClass.prepend SimpleModule
#=> SimpleClass
SimpleClass.new.hello_world
# i am a SimpleModule method
SimpleClass.ancestors
#=> [SimpleModule, SimpleClass, Object, Kernel, BasicObject]
绑定未绑定方法
您还有另一件事. SimpleModule
的实例方法(这里只有一个)是未绑定的.您可以使用 UnboundMethod#bind 进行绑定每个都SimpleClass
的实例,然后使用call
或send
执行它.
There is one other thing you do. SimpleModule
's instance methods (here just one) are unbound. You could use UnboundMethod#bind to bind each to an instance of SimpleClass
and then execute it using call
or 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
这篇关于Ruby元编程:无法将方法发送到模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!