Как вы находите все модули и классы внутри модуля, рекурсивно? - PullRequest
7 голосов
/ 24 марта 2012

Если у вас есть:

module A
  class B
  end
end

Вы можете найти B и аналогичные классы через A.constants.Однако в Ruby 1.9.3 вы не можете получить B, если он находится в другом модуле.В Ruby 1.8.7 вы можете.

module A
  module Aa
    class B
    end
  end
end

Как вы получаете B с первого уровня A?В качестве вывода я хотел бы получить массив констант, который включает все классы, такие как B, но в любом месте модуля A.

Ответы [ 2 ]

14 голосов
/ 24 марта 2012
class Module
  def all_the_modules
    [self] + constants.map {|const| const_get(const) }
      .select {|const| const.is_a? Module }
      .flat_map {|const| const.all_the_modules }
  end
end

A.all_the_modules
# => [A, A::Aa, A::Aa::B]

Этот код сломается, если у вас есть круговые пространства имен, иначе A::Aa::B.const_set(:A, A).

0 голосов
/ 20 ноября 2018

Я получал переполнение стека, когда пытался Reactormonk ответить на большие библиотеки, такие как RSpec. Вот решение, которое должно отфильтровывать циклические ссылки и внешние ссылки, проверяя, действительно ли «потомки» являются потомками родительского модуля, через который мы перебираем:

def parent_of(mod)
  parent_name = mod.name =~ /::[^:]+\Z/ ? $`.freeze : nil
  Object.const_get(parent_name) if parent_name
end

def all_modules(mod)
  [mod] + mod.constants.map { |c| mod.const_get(c) }
  .select {|c| c.is_a?(Module) && parent_of(c) == mod } 
  .flat_map {|m| all_modules(m) }
end

(Метод parent_of() адаптирован из модуля # parent ActiveSupport, который, похоже, не работает надежно для библиотечных классов.)

* * 1010
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...