简体   繁体   English

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

[英]Ruby - including single module multiple times and ancestry hierarchy

I'm reading 'Metaprogramming Ruby' right now and writing some code at the same time to clarify the concepts.我现在正在阅读“元编程 Ruby”并同时编写一些代码来阐明概念。 I've read that when you include/prepend a single module multiple times, all further inclusions won't change the place of said module in the ancestry chain.我已经读过,当您多次包含/添加单个模块时,所有进一步的包含都不会改变所述模块在祖先链中的位置。

I wrote some code that works in a way that I did not expect - what actually happens there?我编写了一些以我没想到的方式工作的代码 - 那里实际发生了什么?

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]

I've assumed that when I run Son.ancestors , Son would include Father, Father would include Grandfather and prepend GreatGrandfather and the ancestry tree would be set to [Son, GreatGrandfather, Father, Grandfather] .我假设当我运行Son.ancestors ,Son 将包括父亲,父亲将包括祖父并在 GreatGrandfather 前面加上祖先树,并且祖先树将设置为[Son, GreatGrandfather, Father, Grandfather] Obviously that didn't happen.显然这并没有发生。

Once Son includes Father, it starts to look in the Father module and finds include Grandfather and prepend GratGrandfather .一旦 Son 包含了Father,它就会开始在Father 模块中查找并找到include Grandfather并在prepend GratGrandfather Does it actually 'go into' Grandfather where it includes GreatGrandfather, and only then executes the prepend GreatGrandfather line (and ignores it because it already exists in the ancestry)?其实是否“进入” Grandfather那里包括曾祖父,然后才执行prepend GreatGrandfather线(因为它已经在祖先存在可以忽略它)?

Truth be told, I doubt I will get much use out of it, but it won't hurt to know how exactly the modules 'chain' each other.说实话,我怀疑我会从中得到多少用处,但知道这些模块如何确切地“链接”在一起并没有什么坏处。

@edit - I've played around with it a bit more, and it doesn't seem that my intuition is right in either case. @edit - 我已经玩过更多了,似乎我的直觉在任何一种情况下都不正确。 I've included a picture of the two ways I thought it could go, instruction after instruction, about creating the inheritance hierarchy - the one that appears to occur in the picture goes against the original example given, so neither #1 or #2 can be happening.我已经包含了我认为可以采用的两种方式的图片,一个接一个的指令,关于创建继承层次结构 - 图片中出现的那个与给出的原始示例背道而驰,所以 #1 或 #2 都不能正在发生。

Modified example code (only GreatGrandfather changed)修改示例代码(仅曾祖父更改)

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

在此处输入图片说明

in summary - I still have no idea how it happens总而言之 - 我仍然不知道它是如何发生的

Module#prepend_feature 模块#prepend_feature

Ruby's default implementation is to overlay the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors.如果此模块尚未添加到 mod 或其祖先之一,Ruby 的默认实现是将此模块的常量、方法和模块变量覆盖到 mod。

But you already add GreatGrandfather to Father through Grandfather.但是您已经通过祖父将曾祖父添加到父亲。

This way it would work as you expect:这样它就会像你期望的那样工作:

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]

Update更新

1.You cant modify example like this: 1.您不能像这样修改示例:

module GreatGrandfather
  include Grandfather
end

module Grandfather
  include GreatGrandfather
end

cause when you define GreatGrandfather Grandfather is not defined.原因当您定义 GreatGrandfather 时,Grandfather 未定义。

2.This is, what happens when you add modules to another modules. 2.This is, 当你将模块添加到另一个模块时会发生什么。 Comments illustrate, what happens with module hierarchy in time:注释说明了模块层次结构在时间上会发生什么:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM