Verifica se una classe Ruby è una sottoclasse di un'altra classe


187

Vorrei testare se una classe eredita da un'altra classe, ma non sembra esistere un metodo per questo.

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

Un'implementazione banale di ciò che voglio sarebbe:

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

ma mi aspetto che questo esista già.


2
A.class #=> Class. Questo è il motivo per cui B.is_a? Arestituisce false.
Wen,

che direkind_of?
Akostadinov il

1
kind_of?verifica se un oggetto è un'istanza di una classe. Non se l'oggetto eredita da una classe.
Confusione,

5
kind_of?è un alias diis_a?
coreyward,

Risposte:


355

Basta usare l' <operatore

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

o utilizzare l' <=operatore

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

13
@Brian Perché si is_a?traduce in è istanza di . Bnon è un'istanza di A, B.newè però ( B.new.is_a? A # => true).
Marcel Jackwerth,

4
Hmm, strana sintassi (non sarebbe stata la mia prima ipotesi), ma grazie per il chiarimento!
Brian Armstrong,

2
Per la documentazione consultare Core API / Module / # < .
webwurst,

2
La mia relazione di amore / odio con Ruby continua ... Perché fornire una funzione diversa per un operatore utilizzato per dichiarare le relazioni di classe E fornire due modi diversi di farlo?
Ben Gotow,

4
@BenGotow - 1. Poiché <non è un operatore, è un metodo. 2. Perché <controlla solo una sottoclasse e <= include anche self.
superluminario,

59

Anche disponibile:

B.ancestors.include? A

Questo differisce leggermente dalla risposta (più breve) di B < Aperché Bè incluso in B.ancestors:

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

B < B
#=> false

B.ancestors.include? B
#=> true

Se questo è desiderabile dipende dal caso d'uso.


24
Più leggibile: B <= B(stesso risultato di B.ancestors.include? B).
Marcel Jackwerth,

Aggiornamento: la soluzione immediatamente precedente funziona con 1.9+ mentre non ci sono "antenati?" in 1.9.

8
Questo non confonderà le persone che non hanno familiarità con la sintassi '<', e per questo motivo la preferisco.
Asfand Qazi,

2
@SimonLepkin Probabilmente non "un po '", a meno che non si verifichino microsecondi. ;) Sì, dietro le quinte i metodi include?e passano attraverso la catena degli antenati . Lo fa in C, quindi sicuramente più veloce del loop attraverso l'array Ruby ... ma praticamente i due dovrebbero essere indistinguibili. <
Phrogz,

1
@JunanChakma In base a come viene definita la parola inglese "antenati", sono d'accordo che il valore restituito non dovrebbe includere B. Ma lo fa. La documentazione del metodo dice "Restituisce un elenco di moduli inclusi / anteposti in mod ( incluso mod stesso )". (enfasi mia). Immagino che includa la sua classe per comodità durante l'uso .include?, ma questa è solo una speculazione da parte mia.
Phrogz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.