Testen Sie, ob eine Ruby-Klasse eine Unterklasse einer anderen Klasse ist


187

Ich möchte testen, ob eine Klasse von einer anderen Klasse erbt, aber dafür scheint es keine Methode zu geben.

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

Eine triviale Implementierung dessen, was ich will, wäre:

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

aber ich würde erwarten, dass dies bereits existiert.


2
A.class #=> Class. Aus diesem Grund wird B.is_a? Afalse zurückgegeben.
— Wen

was ist mitkind_of?
— Akostadinov

1
kind_of?Testet, ob ein Objekt eine Instanz einer Klasse ist. Nicht, ob das Objekt von einer Klasse erbt.
— Verwirrung

5
kind_of?ist ein Alias ​​vonis_a?
— coreyward

Antworten:


355

Verwenden Sie einfach den <Operator

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

oder verwenden Sie den <=Operator

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

13
@Brian Weil is_a?übersetzt in eine Instanz von . Bist keine Instanz von A, B.newis obwohl ( B.new.is_a? A # => true).
— Marcel Jackwerth

4
Hmm, seltsame Syntax (wäre nicht meine erste Vermutung gewesen), aber danke für die Klarstellung!
— Brian Armstrong

2
Dokumentation finden Sie unter Core API / Module / # < .
— Webwurst

2
Meine Hassliebe zu Ruby geht weiter… Warum sollte ein Operator, der zum Deklarieren von Klassenbeziehungen verwendet wird, eine andere Funktion bereitstellen UND zwei verschiedene Möglichkeiten bereitstellen?
— Ben Gotow

4
@BenGotow - 1. Da <kein Operator ist, handelt es sich um eine Methode. 2. Weil <nur nach einer Unterklasse sucht und <= auch self enthält.
— Superleuchte

59

Auch verfügbar:

B.ancestors.include? A

Dies unterscheidet sich geringfügig von der (kürzeren) Antwort von, B < Aweil Benthalten ist in B.ancestors:

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

B < B
#=> false

B.ancestors.include? B
#=> true

Ob dies wünschenswert ist oder nicht, hängt von Ihrem Anwendungsfall ab.


24
Besser lesbar: B <= B(gleiches Ergebnis wie B.ancestors.include? B).
— Marcel Jackwerth

Update: Die unmittelbar vorhergehende Lösung funktioniert mit 1.9+, während es keine "Vorfahren" gibt. in 1.9.

8
Dies wird Leute nicht verwirren, die mit der '<' - Syntax nicht vertraut sind, und aus diesem Grund bevorzuge ich sie.
— Asfand Qazi

2
@SimonLepkin Wahrscheinlich nicht "eine Weile", es sei denn, es treten Mikrosekunden auf. ;) Ja, hinter den Kulissen durchlaufen die Methoden include?und die Ahnenkette . Dies geschieht in C, also sicherlich schneller als das Durchlaufen des Ruby-Arrays ... aber praktisch sollten die beiden nicht zu unterscheiden sein. <
— Phrogz

1
@JunanChakma Basierend auf der Definition des englischen Wortes "Vorfahren" stimme ich zu, dass der Rückgabewert nicht enthalten sein sollte B. Aber es tut. In der Methodendokumentation heißt es: "Gibt eine Liste der in mod enthaltenen / vorangestellten Module zurück ( einschließlich mod selbst )." (Hervorhebung von mir). Ich vermute, es enthält eine eigene Klasse, um die Verwendung zu vereinfachen .include?, aber das ist nur Spekulation meinerseits.
— Phrogz
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.