我有几个定义嵌套模块的文件,比如说:
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。我有几个类,我在每个类上创建带有classNames的logger。在YAML配置中,需要再次指出所有已定义的记录器名称以进一步配置。我正在尝试使用通用代码来提取模块层次结构下的所有类并进行动态配置。
关于我对log4r的方法(或任何更简单的方法)的任何输入也不胜感激。
答案 0 :(得分: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 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]
答案 1 :(得分: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]
答案 2 :(得分:0)
sawa的答案还可以,你也可以使用像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
希望它有所帮助。