Я легко могу подняться на иерархию классов в Ruby:
String.ancestors # [String, Enumerable, Comparable, Object, Kernel]
Enumerable.ancestors # [Enumerable]
Comparable.ancestors # [Comparable]
Object.ancestors # [Object, Kernel]
Kernel.ancestors # [Kernel]
Есть ли способ спуститься вниз по иерархии? Я хотел бы сделать это
Animal.descendants # [Dog, Cat, Human, ...]
Dog.descendants # [Labrador, GreatDane, Airedale, ...]
Enumerable.descendants # [String, Array, ...]
но, похоже, нет descendants
метода.
(Этот вопрос возникает потому, что я хочу найти все модели в приложении Rails, которые происходят от базового класса, и перечислить их; у меня есть контроллер, который может работать с любой такой моделью, и я хотел бы иметь возможность добавлять новые модели без необходимости изменять контроллер.)
singleton_class
вместо того,Class
чтобы делать это намного быстрее (см. источник на apidock.com/rails/Class/descendants )ObjectSpace
его не будет.Object
иBasicObject
, интересно знать , что они появляются?p ObjectSpace.each_object(Class)
распечатает все классы. Вы также можете получить потомков любого класса, подставив его имяself
в строку кода в методе.Если вы используете Rails> = 3, у вас есть два варианта. Используйте,
.descendants
если вы хотите более одного уровня глубины дочерних классов, или используйте.subclasses
для первого уровня дочерних классов.Пример:
источник
Ruby 1.9 (или 1.8.7) с изящными цепочечными итераторами:
Предварительная версия 1.8.7:
Используйте это так:
источник
ObjectSpace.each_object(::Class)
- это будет поддерживать работоспособность кода, когда у вас определен класс YourModule :: Class.Переопределить метод класса с именем унаследованного . Этот метод будет передан подклассу при его создании, который вы можете отслеживать.
источник
Альтернативно (обновлено для ruby 1.9+):
Ruby 1.8 совместимый способ:
Обратите внимание, что это не будет работать для модулей. Также YourRootClass будет включен в ответ. Вы можете использовать Array # - или другой способ удалить его.
источник
ObjectSpace.each_object(class<<MyClass;self;end) {|it| puts it}
class<<some_obj;self;end
возвращает singleton_class объекта. В 1.9+ вы можете использоватьsome_obj.singleton_class
вместо этого (обновил мой ответ, чтобы отразить это). Каждый объект является экземпляром своего класса singleton_class, который также применяется к классам. Поскольку each_object (SomeClass) возвращает все экземпляры SomeClass, а SomeClass является экземпляром SomeClass.singleton_class, each_object (SomeClass.singleton_class) возвращает SomeClass и все подклассы.Хотя использование ObjectSpace работает, унаследованный метод класса кажется более подходящим здесь унаследованная (подкласс) Ruby документация
Пространство объектов - это, по сути, способ получить доступ ко всему и ко всему, что в настоящее время использует выделенную память, поэтому итерации по каждому из его элементов для проверки того, является ли он подклассом класса Animal, не идеальны.
В приведенном ниже коде унаследованный метод класса Animal реализует обратный вызов, который добавляет любой вновь созданный подкласс в его массив потомков.
источник
Я знаю, что вы спрашиваете, как сделать это в наследовании, но вы можете достичь этого непосредственно в Ruby, указав интервал имен в классе (
Class
илиModule
)Это намного быстрее, чем по сравнению с каждым классом в
ObjectSpace
как предлагают другие решения.Если вам серьезно нужно это в наследство, вы можете сделать что-то вроде этого:
тесты здесь: http://www.eq8.eu/blogs/13-ruby-ancestors-descendants-and-other-annoying-relatives
Обновить
в конце концов, все, что вам нужно сделать, это
спасибо @saturnflyer за предложение
источник
(Rails <= 3.0) В качестве альтернативы вы можете использовать ActiveSupport :: DescendantsTracker, чтобы сделать дело. Из источника:
Поскольку он хорошо модульный, вы можете просто «выбрать вишню» для этого конкретного модуля для вашего приложения Ruby.
источник
В Ruby Facets есть потомки класса #,
Он также поддерживает параметр расстояния поколений.
источник
Простая версия, которая дает массив всех потомков класса:
источник
#subclasses
из Rails ActiveSupport.Вы можете
require 'active_support/core_ext'
и использоватьdescendants
метод. Проверьте документ и сделайте снимок в IRB или pry. Может использоваться без Rails.источник
using Rails
в целостном смысле.Rails предоставляет метод подклассов для каждого объекта, но он плохо документирован, и я не знаю, где он определен. Возвращает массив имен классов в виде строк.
источник
Может помочь использование gem downndants_tracker . Следующий пример скопирован из документа gem:
Этот драгоценный камень используется популярным драгоценным камнем виртус , поэтому я думаю, что он довольно солидный.
источник
Этот метод вернет многомерный хеш всех потомков объекта.
источник
Если у вас есть доступ к коду до загрузки какого-либо подкласса, вы можете использовать унаследованный метод.
Если вы этого не сделаете (что не так, но это может быть полезно для всех, кто нашел этот пост), вы можете просто написать:
Извините, если я пропустил синтаксис, но идея должна быть ясной (в данный момент у меня нет доступа к ruby).
источник