Прояснение метода перекрытия рубиновой смеси

Я только что столкнулся с таким поведением, которого я действительно не понимаю.

module M
  def foo
    "module_foo"
  end
end

class C
  def foo
    "class_foo"
  end
  include M
end

puts C.new.foo

Почему C.new.foo действительно возвращает class_foo? Я был почти уверен, что метод должен быть переопределен модулем. Другое дело, заменив "class_foo" на super делает C.new.foo return ` "module_foo"

Это похоже на то, что модуль каким-то образом включен до определения метода экземпляра класса. Не могли бы вы прояснить?

Ответ 1

От программирования раздела Ruby на mixins:

Фактически, смешанные модули эффективно ведут себя как суперклассы.

Итак, что вы переживаете, это нормально. ваш модуль M является суперклассом вашего класса C

Поэтому ваш метод foo в классе C переопределяет метод foo в модуле M

Ответ 2

Здесь как ruby ​​выполняет поиск метода:

  • класс однопользовательских приемников;
  • класс приемника;
  • любые включенные модули;
  • повторите поиск в супер-классе приемника;
  • если метод вообще не найден, вызов method_missing;

Здесь вы можете найти более подробную информацию: http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html

Поэтому, чтобы найти метод, Ruby входит в класс приемника, и оттуда он поднимается на цепочку предков до тех пор, пока не найдет метод. Это поведение также называется "одним шагом вправо, а затем вверх", правило: перейдите на один шаг вправо в класс приемника, а затем вверх цепь предков, пока вы не найдете метод. Когда вы включаете модуль в классе (или даже в другом модуле), Ruby создает анонимный класс, который обертывает модуль и вставляет анонимный класс в цепочке, чуть выше самого включенного класса.