Перезапись методов экземпляра с помощью нескольких включений

Возьмите следующий код в Ruby 3.3.0:

module A
  def print
    puts "A"
  end
end

module B
  def print
    puts "B"
  end
end

class C
end

c_instance = C.new

C.send(:include, A)
c_instance.print

C.send(:include, B)
c_instance.print

C.send(:include, A)
c_instance.print

Я ожидал, что он напечатает:

A
B
A

Но он распечатывает

A
B
B

Почему это?

Обратите внимание, что C.send(:include, A) можно упростить до C.include A.

Cary Swoveland 01.07.2024 03:10
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
0
1
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Руби игнорирует второй звонок. Из документации Ruby :

Реализация Ruby по умолчанию заключается в добавлении констант, методов и переменных модуля этого модуля в mod, если этот модуль еще не был добавлен в mod или в один из его предков. См. также Модуль#include.

Это цитата из описания метода append_features, который используется в методе include.

Да, вполне логично, модуль уже находится внутри цепочки предков. Большое спасибо!

Alexander Presber 29.06.2024 20:16

Возможно, это не ответит на ваш вопрос напрямую, но вы можете использовать ancestors, чтобы проверить окончательную цепочку наследования.

C.ancestors
# => [C, B, A, Object, Kernel, BasicObject]

Существует множество способов реализации динамического метапрограммирования в Ruby. На этот раз вас смутил :include, в следующий раз вас может смутить :prepend или даже другие виды загадочного наследования. Вы даже можете использовать

c_instance.method(:print).source_location

что, черт возьми, внутри этого метода

Другие вопросы по теме