Ruby - 包括多个单个模块和祖先层次结构

时间:2016-05-30 14:29:52

标签: ruby inheritance module

我正在阅读'Metaprogramming Ruby',同时编写一些代码来澄清概念。我已经读过,当您多次包含/添加单个模块时,所有进一步的包含都不会改变所述模块在祖先链中的位置。

我编写了一些代码,这些代码以我没想到的方式工作 - 那里实际发生了什么?

module GreatGrandfather; end

module Grandfather
  include GreatGrandfather
end

module Father
  include Grandfather
  prepend GreatGrandfather
end

module Son
  include Father
end

Son.ancestors # => [Son, Father, Grandfather, GreatGrandfather]

我假设当我跑Son.ancestors时,儿子将包括父亲,父亲将包括祖父并且在前祖父和祖先树将被设置为[Son, GreatGrandfather, Father, Grandfather]。显然这没有发生。

一旦Son包含父亲,它就会开始查看父模块并找到include Grandfatherprepend GratGrandfather。它是否真的'进入'Grandfather它包含GreatGrandfather,然后只执行prepend GreatGrandfather行(并忽略它,因为它已经存在于祖先中)?

说实话,我怀疑我会从中获得多少用处,但知道模块之间的链条是如何完全没有关系的。

@edit - 我已经玩了很多,而且似乎我的直觉在任何一种情况下都不对。我已经包含了一张我认为可以采用的两种方式的图片,一个接一个的指令,一个关于创建继承层次结构的图片 - 图片中出现的一个图片与给出的原始示例相反,所以#1或#2都不能正在发生。

修改后的示例代码(仅更改了GreatGrandfather)

module GreatGrandfather
  include Grandfather
end

module Grandfather
  include GreatGrandfather
end

module Father
  prepend GreatGrandfather
  include Grandfather
end

module Son
  include Father
end

Son.ancestors # => Son, GreatGrandfather, Father, Grandfather

enter image description here

总结 - 我仍然不知道它是如何发生的

1 个答案:

答案 0 :(得分:1)

Module#prepend_feature

  

Ruby的默认实现是覆盖常量,方法,   如果此模块没有,则将此模块的模块变量修改为mod   已被添加到mod或其祖先之一。

但是你已经通过祖父将GreatGrandfather添加到了父亲那里。

这样可以按预期工作:

module GreatGrandfather; end

module Grandfather
  include GreatGrandfather
end

module Father
  prepend GreatGrandfather
  include Grandfather
end

module Son
  include Father
end

p Son.ancestors # => [Son, GreatGrandfather, Father, Grandfather]

<强>更新

1.你不能修改这样的例子:

module GreatGrandfather
  include Grandfather
end

module Grandfather
  include GreatGrandfather
end

因为你定义了GreatGrandfather Grandfather没有定义。

2.这就是将模块添加到其他模块时会发生什么。注释说明了模块层次结构及时发生的情况:

module GreatGrandfather
  # GG
end

module Grandfather
  # GG
  # G
  include GreatGrandfather
  # GG
  # G -> GG
end

module Father
  # GG
  # G -> GG
  # F
  prepend GreatGrandfather
  # GG
  # G -> GG
  # GG -> F
  include Grandfather
  # Don't change the position of GG in Father hierarchy, cause it is already in ancestors
  # GG
  # G -> GG
  # GG -> F -> G
end

module Son
  # GG
  # G -> GG
  # GG -> F -> G
  # S
  include Father
  # GG
  # G -> GG
  # GG -> F -> G
  # S -> GG -> F -> G
end