Проверьте, является ли класс Ruby подклассом другого класса

187

Я хотел бы проверить, наследует ли класс другой класс, но, похоже, не существует метода для этого.

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

Тривиальная реализация того, что я хочу, будет:

class Class
  def is_subclass_of?(clazz)
    return true if superclass == clazz
    return false if self == Object
    superclass.is_subclass_of?(clazz)
  end
end

но я ожидаю, что это уже существует.

Спутанность сознания
источник
2
A.class #=> Class, Вот почему B.is_a? Aвозвращает false.
Вэнь
а как жеkind_of?
акостадинов
1
kind_of?проверяет, является ли объект экземпляром класса. Не наследует ли объект от класса.
Беспорядок
5
kind_of?это псевдонимis_a?
coreyward

Ответы:

355

Просто используйте <оператор

B < A # => true
A < A # => false

или воспользуйтесь <=оператором

B <= A # => true
A <= A # => true
Марсель Джекверт
источник
13
@Brian Потому что is_a?переводится как экземпляр . Bне является экземпляром A, B.newхотя ( B.new.is_a? A # => true).
Марсель Джекверт
4
Хм, странный синтаксис (не был бы моим первым предположением), но спасибо за разъяснение!
Брайан Армстронг
2
Для документации см. Core API / Module / # < .
webwurst
2
Мои отношения любви / ненависти с Руби продолжаются ... Зачем предоставлять оператору другую функцию, используемую для объявления отношений класса И два разных способа сделать это?
Бен Готов
4
@BenGotow - 1. Потому что <не оператор, это метод. 2. Потому что <проверяет только подкласс, а <= также включает себя.
Сверхсветовой
59

Так же доступно:

B.ancestors.include? A

Это немного отличается от (более короткого) ответа, B < Aпотому что Bвключено в B.ancestors:

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

B < B
#=> false

B.ancestors.include? B
#=> true

Желательно ли это, зависит от вашего варианта использования.

Phrogz
источник
24
Более читабельно: B <= B(тот же результат, что и B.ancestors.include? B).
Марсель Джекверт
Обновление: непосредственно предшествующее решение работает с 1.9+, в то время как нет "предков?" в 1.9.
8
Это не смущает людей, не знакомых с синтаксисом «<», и по этой причине я предпочитаю его.
Асфанд Кази
2
@SimonLepkin Вероятно, не «на время», если только вы не испытываете микросекунды. ;) Да, за кулисами методы include?и проходят через цепочку предков . Он делает это в C, так что, безусловно, быстрее, чем цикл по массиву Ruby ... но практически оба должны быть неразличимы. <
Phrogz
1
@JunanChakma Исходя из того, как определено английское слово «предки», я согласен, что возвращаемое значение не должно включать B. Но это так. Документация по методу гласит: «Возвращает список модулей, включенных / добавленных в мод ( включая сам мод )». (акцент мой). Я предполагаю, что он включает в себя собственный класс для удобства использования .include?, но это всего лишь предположение с моей стороны.
Phrogz