2013-08-20 4 views
0

У меня есть несколько файлов, определяющих вложенные модули, говорят:Получение всех классов, определенных в рамках модуля

File1:

module A 
    module B 
    class B1 
     class B1Error < Exception ; end 
    end 
    end 
end 

Файл 2:

module A 
    module B 
    class B2 
     class B2Error < Exception ; end 
     class B2_inner 
     end 
    end 
    end 
end 

Мне нужен способ, чтобы получить все классов, определенных в данном модуле.

def get_all_classes_under_module_hier(hier) 
    ??? 
end 
get_all_classes_under_module_hier(A::B) 
#=> A::B::B1, A::B::B1::B1Error, A::B::B2, A::B::B2::B2Error, A::B::B2::B2_inner. 

Как я могу достичь цели?

Причина, по которой мне это нужно: я пытаюсь использовать log4r. У меня есть несколько классов, и я создаю журнал с именами классов по каждому из них. В конфигурации YAML необходимо снова указать все определенные имена журналов для дальнейшей настройки. Я пытаюсь использовать общий код, чтобы вытащить все классы в иерархии модулей и иметь динамическую конфигурацию.

Любые данные, касающиеся моего подхода к log4r (или любого более простого способа), также приветствуются.

ответ

0

Вы можете использовать либо Module::nesting, как показано ниже:

Возвращает список модулей вложенными в точке вызова.

module A 
    module B 
    class B2 
     class B1Error < Exception ; $b = Module.nesting ;end 
     class B2_inner 
     $a = Module.nesting 
     end 
    end 
    end 
end 

$a # => [A::B::B2::B2_inner, A::B::B2, A::B, A] 
$b # => [A::B::B2::B1Error, A::B::B2, A::B, A] 

или

Module::constants

возвращает массив имен всех констант, доступных из точки вызова.

module A 
    module B 
    class B2 
     class B1Error < Exception ;end 
     class B2_inner 
     $a = Module.constants 
     end 
    end 
    end 
end 

$a - Module.constants 
# => [:B1Error, :B2_inner, :B2, :B] 
ответ
0
def get_all_modules_under_module_hier(hier) 
    a = hier 
    .constants 
    .map{|e| hier.const_get(e)} 
    .select{|e| e.kind_of?(Module)} 
    a + a.flat_map{|klass| get_all_classes_under_module_hier(klass)} 
end 
def get_all_classes_under_module_hier(hier) 
    get_all_modules_under_module_hier(hier) 
    .select{|e| e.instance_of?(Class)} 
end 

get_all_classes_under_module_hier(A::B) 
# => [A::B::B1, A::B::B2, A::B::B1::B1Error, A::B::B2::B2Error, A::B::B2::B2_inner] 
0

Саввы в порядке, а также вы можете использовать метод, как this динамически создавать регистратор для каждого класса.

Однако я предпочитаю не получать все классы под модулем. В состоянии создать регистратор для каждого отдельного класса, вы можете делать все, как следует.

module Kernel 

    ####### 
    private 
    ####### 

    def logger 
    Log4r::Logger[logger_name] 
    end 

    def logger_name 
    clazz = self.class 
    unless clazz.respond_to? :logger_name 
     name = clazz.module_eval 'self.name' 
     clazz.define_singleton_method(:logger_name) { name } 
    end 
    clazz.logger_name 
    end 

end 

module A 
    module B 
    class C 

     def hello 
     logger.debug logger_name 
     end 

    end 
    end 
end 

A::B::C.new.hello 

Для классов в рамках конкретного модуля вы можете написать фильтр в методе logger_name, например:

module Kernel 

    ####### 
    private 
    ####### 

    def logger 
    Log4r::Logger[logger_name] 
    end 

    def logger_name 
    clazz = self.class 
    unless clazz.respond_to? :logger_name 
     name = clazz.module_eval 'self.name' 
     name = 'root' unless name.start_with?('A::B') 
     clazz.define_singleton_method(:logger_name) { name } 
    end 
    clazz.logger_name 
    end 

end 

module A 
    module B 

    class C 

     def hello 
     logger.debug logger_name 
     end 

     class << self 
     def hello 
      logger.debug logger_name 
     end 
     end 

    end 
    end 

    class D 
    def hello 
     logger.debug logger_name 
    end 
    end 
end 

A::B::C.new.hello # A::B::C 
A::B::C.hello # A::B::C 
A::D.new.hello # root 

А также, вы можете кэшировать регистратор:

def logger 
    _logger = Log4r::Logger[logger_name] 
    self.class.send(:define_method, :logger) { _logger } 
    self.class.define_singleton_method(:logger) { _logger } 
    return _logger 
end 

Надежда помогает.

Смежные вопросы