Prueba si una clase Ruby es una subclase de otra clase

187

Me gustaría probar si una clase hereda de otra clase, pero no parece existir un método para eso.

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

Una implementación trivial de lo que quiero sería:

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

pero esperaría que esto ya exista.

Confusión
fuente
2
A.class #=> Class. Es por eso que B.is_a? Adevuelve falso.
Wen
¿qué pasakind_of?
akostadinov
1
kind_of?prueba si un objeto es una instancia de una clase. No si el objeto hereda de una clase.
Confusión
55
kind_of?es un alias deis_a?
coreyward

Respuestas:

355

Solo usa el <operador

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

o usar el <=operador

B <= A # => true
A <= A # => true
Marcel Jackwerth
fuente
13
@Brian Porque se is_a?traduce en es instancia de . Bno es una instancia de A, B.newes aunque ( B.new.is_a? A # => true).
Marcel Jackwerth
44
Hmm, sintaxis extraña (no habría sido mi primera suposición), pero gracias por la aclaración.
Brian Armstrong
2
Para obtener documentación, consulte Core API / Module / # < .
webwurst
2
Mi relación de amor / odio con Ruby continúa ... ¿Por qué proporcionar una función diferente para un operador utilizado para declarar relaciones de clase Y proporcionar dos formas diferentes de hacerlo?
Ben Gotow
44
@BenGotow - 1. Porque <no es un operador, es un método. 2. Porque <solo busca una subclase, y <= también incluye self.
superluminario
59

También disponible:

B.ancestors.include? A

Esto difiere ligeramente de la respuesta (más corta) de B < Aporque Bestá incluida en B.ancestors:

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

B < B
#=> false

B.ancestors.include? B
#=> true

Si esto es deseable o no depende de su caso de uso.

Phrogz
fuente
24
Más legible: B <= B(mismo resultado que B.ancestors.include? B).
Marcel Jackwerth
Actualización: ¿La solución inmediatamente anterior funciona con 1.9+ mientras que no hay "antepasados"? en 1.9.
8
Esto no confundirá a las personas que no estén familiarizadas con la sintaxis '<', y por eso la prefiero.
Asfand Qazi
2
@SimonLepkin Probablemente no sea "un tiempo", a menos que pueda experimentar microsegundos pasando. ;) Sí, detrás de escena, los métodos include?y recorren la cadena de antepasados . Hace esto en C, seguramente más rápido que recorrer la matriz de Ruby ... pero prácticamente los dos deberían ser indistinguibles. <
Phrogz
1
@JunanChakma Según la forma en que se define la palabra inglesa "antepasados", estoy de acuerdo en que el valor de retorno no debe incluir B. Pero lo hace. La documentación del método dice: "Devuelve una lista de módulos incluidos / incluidos en el mod ( incluido el mod )". (énfasis mío). Supongo que incluye su propia clase por conveniencia cuando se usa .include?, pero eso es solo especulación de mi parte.
Phrogz