Teste se uma classe Ruby é uma subclasse de outra classe


187

Eu gostaria de testar se uma classe herda de outra classe, mas parece não existir um método para isso.

class A
end

class B < A
end

B.is_a? A 
=> false

B.superclass == A
=> true

Uma implementação trivial do que eu quero seria:

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

mas eu esperaria que isso já existisse.


2
A.class #=> Class. É por isso que B.is_a? Aretorna falso.
Wen

que tal #kind_of?
akostadinov

1
kind_of?testa se um objeto é uma instância de uma classe. Não se o objeto herda de uma classe.
Confusion

5
kind_of?é um alias deis_a?
coreyward

Respostas:


355

Basta usar o <operador

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

ou use o <=operador

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

13
@ Brian Porque is_a?traduz para é instância de . Bnão é uma instância de A, B.newé embora ( B.new.is_a? A # => true).
Marcel Jackwerth

4
Hmm, sintaxe estranha (não teria sido meu primeiro palpite), mas obrigado pelo esclarecimento!
Brian Armstrong

2
Para obter documentação, consulte API / módulo principal / # < .
Webwurst

2
Meu relacionamento de amor / ódio com Ruby continua… Por que fornecer uma função diferente para um operador usado para declarar relacionamentos de classe E fornecer duas maneiras diferentes de fazer isso?
Ben Gotow

4
@BenGotow - 1. Como <não é um operador, é um método. 2. Porque <verifica apenas uma subclasse e <= também inclui self.
superluminary

59

Também disponível:

B.ancestors.include? A

Isso difere um pouco da resposta (mais curta) do B < Aporque Bestá incluído em B.ancestors:

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

B < B
#=> false

B.ancestors.include? B
#=> true

Se isso é desejável ou não, depende do seu caso de uso.


24
Mais legível: B <= B(mesmo resultado que B.ancestors.include? B).
Marcel Jackwerth

Atualização: a solução imediatamente anterior funciona com 1.9+, enquanto não há "antepassados?" em 1.9.

8
Isso não confundirá pessoas que não estão familiarizadas com a sintaxe '<' e, por esse motivo, prefiro.
Asfand Qazi

2
@SimonLepkin Provavelmente não "um tempo", a menos que você possa experimentar microssegundos passando. ;) Sim, nos bastidores, os métodos include?e passam pela cadeia de ancestrais . Ele faz isso em C, com certeza mais rápido do que percorrer o array Ruby ... mas praticamente os dois devem ser indistinguíveis. <
21815 Phrogz

1
@JunanChakma Com base em como a palavra em inglês "antepassados" é definida, concordo que o valor de retorno não deve ser incluído B. Mas sim. A documentação do método diz: "Retorna uma lista de módulos incluídos / anexados no mod ( incluindo o próprio mod )". (ênfase minha). Acho que inclui sua própria classe por conveniência ao usar .include?, mas isso é apenas especulação da minha parte.
Phrogz
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.