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.