Пусть `super` вызывает родительский класс над включенным модулем - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть класс Boy, который наследует класс Person и включает в себя модуль BipedalPerson, и Bipedal имеют версии #two_legs.

module Bipedal
  def two_legs(name)
    puts "#{name} has exactly two limbs used for walking."
  end
end

class Person
  def two_legs(name)
    puts "#{name} has two human legs."
  end
end

class Boy < Person
  include Bipedal
  attr_accessor :name
  def initialize(name)
    @name = name
  end

  def two_legs
    super(@name)
  end
end

Поскольку модуль Bipedal включен в Boy, Bipedal#two_legs имеет приоритет над Person#two_legs.Когда я вызываю super для экземпляра Boy, модуль Bipedal имеет приоритет над родительским классом Person.

johnny = Boy.new('Johnny')
johnny.two_legs
# >> "Johnny has exactly two limbs used for walking."

. Я хочу использовать одну версию в одном месте, а другую вдругой.У Bipedal есть другие вещи, поэтому я не могу комментировать include Bipedal.Есть ли какой-нибудь стандартный способ позволить Boy#two_legs или super использовать версию родительского класса вместо версии модуля следующим образом?

johnny.two_legs
# >> "Johnny has two human legs."

Я придумал это:

Boy.superclass.instance_method(:two_legs).bind(self).call(@name)

, который работает вместо super(@name), но сложнее, чем я ожидал.

Опять же, вопрос в том, существует ли стандартный способ заставить родительский класс иметь приоритет над модулем при вызовеsuper

Ответы [ 3 ]

0 голосов
/ 27 ноября 2018

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

SemiBipedal = Bipedal.dup
SemiBipedal.remove_method(:two_legs)

class Boy < Person
  include SemiBipedal
  #...
end

Конечно, johnny.is_a? Bipedal больше не будет верными Boy.ancestors будет иметь SemiBipedal вместо Bipedal в индексе 1, но это может не иметь значения.

0 голосов
/ 29 ноября 2018

Можно использовать метод Метод # super_method дважды.Этот метод Ruby для садового сорта, я полагаю, будет рассматриваться как "стандартный способ" позволить Boy#two_legs вызывать Person#two_legs, а не Bipedal#two_legs.

class Boy < Person
  include Bipedal
  attr_accessor :name
  def initialize(name)
    @name = name
  end
  def two_legs
    method(:two_legs).super_method.super_method.call(@name)
  end
end

willie = Boy.new('Willie')
willie.two_legs
Willie has two human legs.

. Обратите внимание на следующее.

willie.method(:two_legs).super_method.owner
  #=> Bipedal
willie.method(:two_legs).super_method.super_method.owner
  #=> Person
0 голосов
/ 27 ноября 2018

Нет, стандартного способа принудительного вызова super нет, чтобы выгуливать предков в определенном порядке.Они идут в заранее определенном порядке.Посмотрите на документацию по вызову методов :

Когда вы отправляете сообщение, Ruby ищет метод, который соответствует имени сообщения для получателя.Методы хранятся в классах и модулях, поэтому поиск по методам обходит их, а не сами объекты.

Вот порядок поиска методов для класса или модуля получателя R:

  • Предварительно добавленные модули R в обратном порядке
  • Для метода сопоставления в R
  • Включенные модули R в обратном порядке

ЕслиR - это класс с суперклассом, это повторяется с суперклассом R до тех пор, пока не будет найден метод.

Как только совпадение найдено, поиск метода останавливается.

Так как ваш класс Boy включает в себя модуль Bipedal напрямую, и поскольку во включенных модулях поиск выполняется до суперкласса, и поскольку поиск останавливается, как только найдено совпадение, суперкласс Person никогда не проверяется.

То же самое верно при использовании уточнений , потому что поиск всегда поражает включенные модули перед проверкой суперкласса.

Если вы переместите include Bipedal в класс Person, тогда он будет работать так, как уВы ожидаете, потому что Boy не включает модуль напрямую, поэтому он в конечном итоге будет искать суперкласс, где он найдет определенный метод.

Могут быть и другие творческие способы достижения этой цели, например Boy.superclass... пример, который вы привели, но вы спросили, возможно ли изменить поведение поиска при вызове super, а ответ - нет, согласно документации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...