Eu posso facilmente subir a hierarquia de classes no Ruby:
String.ancestors # [String, Enumerable, Comparable, Object, Kernel]
Enumerable.ancestors # [Enumerable]
Comparable.ancestors # [Comparable]
Object.ancestors # [Object, Kernel]
Kernel.ancestors # [Kernel]
Existe alguma maneira de descer a hierarquia também? Eu gostaria de fazer isso
Animal.descendants # [Dog, Cat, Human, ...]
Dog.descendants # [Labrador, GreatDane, Airedale, ...]
Enumerable.descendants # [String, Array, ...]
mas não parece haver um descendants
método.
(Essa pergunta surge porque eu quero encontrar todos os modelos em um aplicativo Rails que descendem de uma classe base e listá-los; eu tenho um controlador que pode trabalhar com qualquer modelo e gostaria de poder adicionar novos modelos sem precisar modificar o controlador.)
singleton_class
em vez deClass
torná-lo muito mais rápido (ver fonte da apidock.com/rails/Class/descendants )ObjectSpace
não a terá.Object
eBasicObject
, curioso para saber o que elas aparecem?p ObjectSpace.each_object(Class)
imprimirá todas as classes. Você também pode obter os descendentes de qualquer classe que desejar substituindo seu nomeself
na linha de código do métodoSe você usa Rails> = 3, você tem duas opções. Use
.descendants
se você desejar mais de um nível de profundidade de classes para crianças ou use.subclasses
para o primeiro nível de classes para crianças.Exemplo:
fonte
Ruby 1.9 (ou 1.8.7) com iteradores encadeados bacanas:
Ruby pré-1.8.7:
Use-o assim:
fonte
ObjectSpace.each_object(::Class)
- isso manterá o código funcionando quando você tiver um YourModule :: Class definido.Substitua o método de classe chamado herdado . Esse método receberia a subclasse quando criada, que você pode rastrear.
fonte
Como alternativa (atualizado para o ruby 1.9+):
Maneira compatível com Ruby 1.8:
Observe que isso não funcionará para módulos. Além disso, YourRootClass será incluído na resposta. Você pode usar a Matriz # - ou outra maneira de removê-la.
fonte
ObjectSpace.each_object(class<<MyClass;self;end) {|it| puts it}
class<<some_obj;self;end
retorna a singleton_class de um objeto. Em 1.9+, você pode usarsome_obj.singleton_class
(atualizei minha resposta para refletir isso). Todo objeto é uma instância de sua singleton_class, que também se aplica a classes. Como each_object (SomeClass) retorna todas as instâncias de SomeClass, e SomeClass é uma instância de SomeClass.singleton_class, cada um dos objetos (SomeClass.singleton_class) retornará SomeClass e todas as subclasses.Embora o uso do ObjectSpace funcione, o método da classe herdada parece ser mais adequado aqui na documentação Ruby herdada (subclasse)
O espaço de objetos é essencialmente uma maneira de acessar tudo e qualquer coisa que esteja usando atualmente a memória alocada, portanto, a iteração sobre cada um de seus elementos para verificar se é uma sublassa da classe Animal não é o ideal.
No código abaixo, o método herdado da classe Animal implementa um retorno de chamada que adicionará qualquer subclasse recém-criada à sua matriz descendente.
fonte
Eu sei que você está perguntando como fazer isso na herança, mas você pode conseguir isso diretamente no Ruby espaçando o nome da classe (
Class
ouModule
)É muito mais rápido dessa maneira do que comparar com todas as classes,
ObjectSpace
como as outras soluções propostas.Se você realmente precisa disso em uma herança, pode fazer algo assim:
referências aqui: http://www.eq8.eu/blogs/13-ruby-ancestors-descendants-and-other-annoying-relatives
atualizar
no final, tudo o que você precisa fazer é isso
obrigado @saturnflyer pela sugestão
fonte
(Rails <= 3.0) Como alternativa, você pode usar o ActiveSupport :: DescendantsTracker para executar a ação. Da fonte:
Como ele é modularizado de maneira adequada, você pode simplesmente 'escolher' esse módulo específico para o seu aplicativo Ruby.
fonte
O Ruby Facets possui descendentes da classe #,
Ele também suporta um parâmetro de distância geracional.
fonte
Uma versão simples que fornece uma matriz de todos os descendentes de uma classe:
fonte
#subclasses
é do Rails ActiveSupport.Você pode
require 'active_support/core_ext'
e usar odescendants
método Confira o documento e experimente IRB ou alavanca. Pode ser usado sem Rails.fonte
using Rails
em um sentido holístico.O Rails fornece um método de subclasses para cada objeto, mas não está bem documentado e não sei onde está definido. Retorna uma matriz de nomes de classe como seqüências de caracteres.
fonte
O uso da gema descendants_tracker pode ajudar. O exemplo a seguir é copiado do documento da gema:
Esta gema é usada pela joia virtus popular , então acho que é bastante sólida.
fonte
Este método retornará um hash multidimensional de todos os descendentes de um objeto.
fonte
Se você tiver acesso ao código antes do carregamento de qualquer subclasse, poderá usar o método herdado .
Caso contrário (o que não é um caso, mas pode ser útil para quem encontrou este post), basta escrever:
Desculpe se perdi a sintaxe, mas a ideia deve estar clara (não tenho acesso ao ruby no momento).
fonte