Sprawdź, czy klasa Ruby jest podklasą innej klasy

187

Chciałbym przetestować, czy klasa dziedziczy po innej klasie, ale wydaje się, że nie istnieje na to metoda.

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

Trywialna implementacja tego, czego chcę, to:

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

ale spodziewałbym się, że to już istnieje.

Dezorientacja
źródło
2
A.class #=> Class. Dlatego B.is_a? Azwraca false.
Wen
co zkind_of?
akostadinov
1
kind_of?sprawdza, czy obiekt jest instancją klasy. Nie, czy obiekt dziedziczy po klasie.
Zamieszanie
5
kind_of?jest aliasis_a?
coreyward

Odpowiedzi:

355

Wystarczy użyć <operatora

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

lub użyj <=operatora

B <= A # => true
A <= A # => true
Marcel Jackwerth
źródło
13
@Brian Ponieważ is_a?tłumaczy się na wystąpienie . Bnie jest instancją A, B.newis is ( B.new.is_a? A # => true).
Marcel Jackwerth
4
Hmm, dziwna składnia (nie byłbym moim pierwszym przypuszczeniem), ale dziękuję za wyjaśnienie!
Brian Armstrong
2
Aby uzyskać dokumentację, patrz Core API / Module / # < .
webwurst
2
Moja relacja miłości / nienawiści z Ruby trwa nadal ... Po co oferować inną funkcję operatorowi używanemu do deklarowania relacji klasowych ORAZ podać dwa różne sposoby na zrobienie tego?
Ben Gotow
4
@BenGotow - 1. Ponieważ <nie jest operatorem, jest to metoda. 2. Ponieważ <sprawdza tylko podklasę, a <= obejmuje również self.
superluminarny
59

Także dostępny:

B.ancestors.include? A

Różni się to nieco od (krótszej) odpowiedzi, B < Aponieważ Bjest zawarte w B.ancestors:

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

B < B
#=> false

B.ancestors.include? B
#=> true

To, czy jest to pożądane, zależy od przypadku użycia.

Phrogz
źródło
24
Bardziej czytelny: B <= B(taki sam wynik jak B.ancestors.include? B).
Marcel Jackwerth,
Aktualizacja: Bezpośrednio poprzedzające rozwiązanie działa z wersją 1.9+, podczas gdy nie ma „przodków?” w 1.9.
8
Nie dezorientuje to ludzi, którzy nie znają składni „<”, i dlatego wolę to.
Asfand Qazi
2
@ SimonLepkin Prawdopodobnie nie „przez jakiś czas”, chyba że minie mikrosekunda. ;) Tak, za kulisami pętlainclude? i <metody przechodzą przez łańcuch przodków . Robi to w C, więc na pewno szybciej niż zapętlanie tablicy Ruby ... ale praktycznie te dwa powinny być nierozróżnialne.
Phrogz,
1
@JananChakma W oparciu o definicję angielskiego słowa „przodkowie” zgadzam się, że wartość zwracana nie powinna zawierać B. Ale tak jest. Dokumentacja metody mówi: „Zwraca listę modułów zawartych / dodanych do modów (w tym samego mod )”. (moje podkreślenie). Domyślam się, że zawiera własną klasę dla wygody użytkowania .include?, ale to tylko spekulacje z mojej strony.
Phrogz