两个模块Foo
分别Baa
定义了一个同名的方法,而name
我在特定的上下文中做了。include Foo
include Baa
当我调用时name
,如何区分是否调用or的name
方法?Foo
Baa
两个模块Foo
分别Baa
定义了一个同名的方法,而name
我在特定的上下文中做了。include Foo
include Baa
当我调用时name
,如何区分是否调用or的name
方法?Foo
Baa
只有模块包含的顺序决定了调用哪个模块。不能同时具有相同的名称 - 后者将覆盖前者。
当然,你可以做任何技巧,只是从我的头顶:
module A
def foo
:foo_from_A
end
end
module B
def foo
:foo_from_B
end
end
class C
def initialize(from)
@from = from
end
def foo
from.instance_method(__method__).bind(self).call
end
private
attr_reader :from
end
C.new(A).foo #=> :a_from_A
C.new(B).foo #=> :a_from_B
但这对现实生活中的用例没有好处:)
从技术上讲,没有名称冲突,因为方法 foo 被重新定义。
在下面的例子中,A.foo 被重新定义并且永远不会被调用
module A
def foo
raise "I'm never called"
end
end
module B
def foo
puts :foo_from_B
end
end
class C
include A
include B
end
C.new.foo
# =>
# foo_from_B
如果你写 A 和 B 模块,你可以使用 super 来调用之前定义的 foo。好像它在哪里继承了一个方法。
module A
def foo
puts :foo_from_A
end
end
module B
def foo
super
puts :foo_from_B
end
end
class C
include A
include B
end
C.new.foo
# =>
# foo_from_A
# foo_from_B
有副作用,我不会使用它,但这样做可以解决问题:
module A
def foo
puts :foo_from_A
end
end
module B
def foo
puts :foo_from_B
end
end
class C
def self.include_with_suffix(m, suffix)
m.instance_methods.each do |method_name|
define_method("#{method_name}#{suffix}", m.instance_method(method_name))
end
end
include_with_suffix A, "_from_A"
include_with_suffix B, "_from_B"
end
c= C.new
c.foo_from_A
c.foo_from_B
begin
c.foo
rescue NoMethodError
puts "foo is not defined"
end
# =>
# foo_from_A
# foo_from_B
# foo is not defined
如果没有任何方法Foo
或Baa
调用name
(这似乎是一个合理的假设),则可以简单地创建别名。
module Foo
def name; "Foo#name"; end
end
module Baa
def name; "Baa#name"; end
end
class C
include Foo
alias :foo_name :name
include Baa
alias :baa_name :name
undef_method :name
end
c = C.new
c.foo_name
#=> "Foo#name"
c.baa_name
#=> "Baa#name"
C.instance_methods & [:foo_name, :baa_name, :name]
#=> [:foo_name, :baa_name]
关键字在此处alias
记录。也可以使用#alias_method方法。有关两者的比较,请参阅此博客。
Module#undef_method不是绝对必要的。name
这只是为了确保在调用 时引发异常。
您应该明确阅读有关方法查找的信息。
无论如何,我会这样做:
module Foo
def name
:foo
end
end
module Bar
def name
:bar
end
end
class MyClass
include Foo
include Bar
def foo_name
Foo.instance_method(:name).bind(self).call
end
def bar_name
Bar.instance_method(:name).bind(self).call
end
#
# or even like this: obj.name(Foo)
#
def name(mod)
mod.instance_method(:name).bind(self).call
end
end
顺便说一句,如果您正在使用Module#instance_method
并且UnboundMethod#bind
您实际上并不需要包含特定模块。此代码有效:
Foo.instance_method(:name).bind('any object (e.g. string)').call