7
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 中获取方法?

4

3 回答 3

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

不确定这是您想要采取的方向,但表明原则上可以做到。

于 2012-12-19T14:17:56.417 回答
2

你不能。

当你include将 mixinM加入一个类C时,Ruby 会创建一个新类⟦M′⟧,它的方法表指向 mixin 的方法表,M并且它的超类是 的超类C,然后使这个类成为新的超类C。对于混入的每个 mixin 都会重复此操作M

请注意,此算法仅运行一次,当您M混入C. 稍后获得 d 的模块include将不会被考虑。

于 2012-07-16T12:08:48.957 回答
1

您应该在 C 类之前将 B 包含在 A 中;包括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...]
于 2012-07-16T11:37:15.827 回答