Насколько я понимаю, что:
include
и prepend
устанавливает частичное отношение (отношение предка) между соответствующими модулями / классами на каждом шаге и
- Отношение предка не может быть опровергнуто на более позднем этапе.
Давайте начнем с:
module M1; end
module M2; end
module M3; end
class Base; end
и следуйте каждому шагу. Первые три шага должны быть тривиальными:
Base.ancestors
#=> [Base, Object, Kernel, BasicObject]
M1.prepend M3
M1.ancestors
# => [M3, M1]
M2.prepend M3
M2.ancestors
#=> [M3, M2]
Теперь ваш первый важный шаг - Base.include M1
. Это вставит предков M1
(всего [M3, M1]
чанка) справа от Base
до Object
:
Base.include M1
Base.ancestors
#=> [Base, M3, M1, Object, Kernel, BasicObject]
Следующий шаг - Base.prepend M2
. Это попытается вставить предков M2
(всего блока [M3, M2]
) слева от Base
. Но обратите внимание, что это может вызвать противоречивую связь между Base
и M3
.
Base.prepend M2
Base.ancestors
#=> Cannot be [M3, M2, Base, M3, M1, Object, Kernel, BasicObject]
Поскольку уже было установлено, что M3
отображается справа от Base
, лучшее, что он может сделать для размещения [M3, M2]
, это разместить его справа от Base
:
Base.prepend M2
Base.ancestors
#=> [Base, M3, M2, M1, Object, Kernel, BasicObject]
Может показаться, что размещение M2
справа от Base
противоречит намерению Base.prepend M2
. Но это может быть отменено / изменено, чтобы соответствовать на месте, тогда как уже установленное отношение между Base
и M3
не может быть отменено в более позднем месте.
На самом деле, когда нет способа удовлетворить уже установленные отношения, возникает ошибка:
module M4; end
module M5; end
M4.include M5
M5.include M4 #>> ArgumentError: cyclic include detected