Почему одноэлементный метод модуля не виден в нижестоящих собственных классах, где он смешивается?

Я понимаю обычный путь поиска метода, т.е. class, superclass/module, all the way up to BasicObject, Я думал, что это верно и для одноэлементной версии цепочки, но не похоже, что вы смешиваете модуль в мета-цепочке. Буду признателен, если кто-то может объяснить, почему в следующем примере Automobile модуля banner метод вызывается вместо его одноэлементной версии, когда я включаю этот модуль в собственный класс Vehicle.

module Automobile
  def banner
    "I am a regular method of Automobile"
  end

  class << self
    def banner
      "I am a singleton method of Automobile"
    end
  end
end

class Vehicle 
  def banner
    "I am an instance method of Vehicle"
  end

  class << self
    include Automobile
    def banner
      puts "I am a singleton method of Vehicle"
      super
    end
  end
end

class Car < Vehicle
  def banner
    "I am an instance method of Car"
  end

  class << self
    def banner
      puts "I am a singleton method of Car"
      super
    end
  end
end

puts Car.banner

# I am a singleton method of Car
# I am a singleton method of Vehicle
# I am a regular method of Automobile

2 ответа

Решение

Прежде всего, include не включает методы собственного класса, как вы могли ожидать. Рассматривать:

module Foo
  class << self
    def do_something
      puts "Foo's eigenclass method does something"
    end
  end
end

module Bar
  include Foo
end

puts Bar.do_something
# undefined method `do_something' for Bar:Module (NoMethodError)

Обратите внимание, что это согласуется с поведением классически определенных методов класса:

module Foo
  def self.do_something
    puts "Foo's class method does something"
  end
end

module Bar
  include Foo
end

puts Bar.do_something
# undefined method `do_something' for Bar:Module (NoMethodError)

Распространенной идиомой является определение методов класса в подмодуле, а затем запуск вызова extend когда модуль включен:

module Foo
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def do_something
      puts "Foo::ClassMethod's instance method does something"
    end
  end
end

module Bar
  include Foo
end

puts Bar.do_something
# Foo::ClassMethod's instance method does something

Второе, что нужно отметить, это то, что вы действительно включаете методы экземпляра Automobile в собственный класс VehicleТаким образом, методы экземпляра Automobile превратиться в (собственный) класс методов Vehicle,

Ваш Car класс в принципе не имеет ничего общего со всем этим. Единственное, что следует здесь отметить, это то, что наследование классов также делает методы класса доступными, тогда как include не. Пример:

class Foo
  def self.do_something
    puts "Foo's class method does something"
  end
end

class Bar < Foo
end

puts Bar.do_something
# "Foo's class method does something"

Прежде всего, класс - это объект, так же как и другие объекты, он также имеет свой собственный суперкласс; во-вторых, сам Eigenclass является нормальным классом, только анонимным и невидимым; в-третьих, суперкласс собственного класса производного класса является собственным классом базового класса; В-четвертых, include включает методы экземпляра (не одноэлементные методы) из включенного модуля, делает их методами экземпляра объекта-получателя класса.

В вашем примере есть две параллельные цепочки наследования

Автомобиль <Автомобиль <...

Собственный класс автомобиля <Собственный класс автомобиля <Автомобиль <...

Сделайте следующий тест на irb:

class Object
  def eigenclass
    class << self
      self
    end
  end
end

Car.ancestors # => [Car, Vehicle, Object, Kernel, BasicObject]
Car.eigenclass.ancestors # => [Automobile, Class, Module, Object, Kernel, BasicObject]
Vehicle.eigenclass.ancestors # => [Automobile, Class, Module, Object, Kernel, BasicObject]
Car.eigenclass.superclass.equal? Vehicle.eigenclass # => true

Ты видишь, Automobile находится в цепочке наследования собственного класса. Но, к сожалению, ancestor Метод не возвращает невидимые собственные классы, тем не менее они фактически находятся во второй цепочке.

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