例如,我有以下自定义类和模块:
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
换句话说,我不知道如何从hello_world
调用SimpleModule
。如果该方法之前使用self定义,则可能。
我需要这样做,因为我想实现一个“自定义包含”:包括从模块到另一个类的所有方法。
请告诉我怎么做。
答案 0 :(得分:5)
五个陈述
让我们一次一个地考虑这五个陈述(但是与呈现的顺序不同)。请注意,send
的参数必须是表示为字符串或符号的方法的名称。
SimpleModule.send("class_hello_world")
# i am a SimpleModule class method
这是正常的,但这些方法通常称为模块方法。一些常见的内置模块(例如Math)仅包含模块方法。
SimpleClass.send(:class_hello_world)
# i am a SimpleClass class method
由于类是模块,因此行为与上述相同。 class_hello_world
通常称为类方法。
SimpleClass.new.send(:hello_world)
# i am SimpleClass 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
无法创建模块的实例。
include
vs prepend
假设有人写了
SimpleClass.include SimpleModule
#=> SimpleClass
SimpleClass.new.hello_world
# i am SimpleClass method
所以SimpleClass
'原始方法hello_world
不会被模块的方法用同一名称覆盖。考虑SimpleClass
'祖先。
SimpleClass.ancestors
#=> [SimpleClass, SimpleModule, Object, Kernel, BasicObject]
Ruby会在考虑hello_world
之前在SimpleClass
中查找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]
绑定未绑定的方法
你还有另外一件事。 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
执行它。
select
c.id,
group_concat(concat(u.name, ' ', u.ma_lastname) order by u.id separator ', ') pass
from config_project c
left join users u on find_in_set(u.id, c.pass) > 0
group by c.id;
答案 1 :(得分:2)
模块不具备实例方法,因为它们不是类。如果在模块中定义实例方法,则称为mixin。这些&#34; mixins&#34;可以包含在另一个类中,然后可以使用。
完整的说明在docs
中编辑:
例如,您可以执行以下操作:
module SimpleModule
def hello_world
p 'hello world'
end
end
class Example
include SimpleModule
end
Example.new.send(:hello_world)
这是调用模块mixin的一种方法。
答案 2 :(得分:2)
因为您似乎想要创建自己的包含版本。
查看Module.append_features
文档
当这个模块包含在另一个模块中时,Ruby会调用append_features 这个模块,在mod中传递接收模块。 Ruby的默认值 实现是添加常量,方法和模块变量 如果此模块尚未添加到mod,则此模块为mod 或其中一个祖先。另请参见模块#include。
如果您想自己重写include
,那么这就是您必须要做的事情。
既然你喜欢冒险,也许你会喜欢阅读Ruby的源代码,看看它是如何在内部实现的。见https://github.com/ruby/ruby...class.c#L853:L934
答案 3 :(得分:0)
您也可以使用constantize
:
def call_method(method)
"SimpleModule::#{method}".constantize
end