module A; def a; end; end
module B; def b; end; end
class C; include A; end
module A; include B; end
class D; include A; end
C.new.b # undefined method error
D.new.b # nil
C.ancestors # [C, A, Object...]
D.ancestors # [D, A, B, Object...]
如何在A中包含模块B,以便已经包含模块A的类也将从模块B获取方法?
答案 0 :(得分:3)
正如已经说过的那样,Ruby不会像这样工作 - 当一个类包含一个模块时,它不维护对该模块实例的任何引用,所以如果该模块包含其他模块,那么已经有的类包括它将不知道变化。
您可以通过将包含模块的类存储在模块本身中来解决这个问题 - 这样,只要模块包含另一个模块,您就可以更新它们,例如:
module A
class<<self
attr_accessor :observers
end
self.observers = []
def a
"#{self} successfully called a"
end
def self.included(base)
self.observers << base unless self.observers.include?(base)
end
def self.include(mod)
observers.each {|o| o.send(:include,mod) }
super
end
end
module B
def b
"#{self} successfully called b"
end
end
class C
include A
end
module A
include B
end
class D
include A
end
module E
def e
"#{self} successfully called e"
end
end
module A
include E
end
puts C.new.b
puts D.new.b
puts C.new.e
puts D.new.e
不确定这是您想要采取的方向,但表明它原则上可以完成。
答案 1 :(得分:2)
你不能。
当你include
混合M
进入类C
时,Ruby会创建一个新类⟦M′⟧
,其方法表指向mixin {{1}的方法表并且其超类是M
的超类,然后使该类成为C
的新超类。对于混合到C
中的每个mixin重复此操作。
请注意,当您将M
混合到M
时,此算法只运行一次。稍后获得C
d的模块将不予考虑。
答案 2 :(得分:1)
你应该在 C类之前在A中加入B;包括A;端强>
module A; def a; end; end
module B; def b; end; end
module A; include B; end
class C; include A; end
class D; include A; end
p C.new.b # nil
p D.new.b # nil
p C.ancestors # [C, A, B, Object, Kernel, BasicObject]
p D.ancestors # [D, A, B, Object, Kernel, BasicObject]
修改强>
module A; def a; end; end
module B; def b; end; end
class C; include A; end
module A; include B; end
class D; include A; end
C.send(:include, A)
p C.new.b # nil
p D.new.b # nil
p C.ancestors # [C, A, Object...]
p D.ancestors # [D, A, B, Object...]