试图找到包含模块的所有 类
Trying to find all classes that include a module
在深入探讨问题之前,我将尝试解释一下我的代码库的结构。 这个问题与评论中的链接问题不同,因为它涉及模块 classes 中包含的模块列表。不直接在 classes 上或在 1 级模块中
1) 可能有一个 class X,其定义为:
module ParentModule
class X
end
end
2) 在不同的模块下也可能有一个嵌套的 class :
module ParentModule
module ChildModule
class Y
end
end
end
3) 也可能只有一个模块,里面有一些 classes:
module ParentModule
module OtherModule
def some_awesome_method
..does something
end
end
end
我正在尝试在我的 ParentModule
中获取包含 OtherModule
的 classes 的列表。这是我目前所拥有的,运行良好:
include_resources = ->(klass) {
begin
klass_string = klass.to_s
klass_resource = klass_string.constantize
klass_string if klass_resource.included_modules.include?(OtherModule)
rescue NameError # skip all bad naming and other irrelevant constant loading mishaps
next
end
}
所以,如果我这样做 ParentModule.constants.find_all(&include_resources)
,我会得到包含 OtherModule
的 classes 的列表,太棒了!但不幸的是,它无法找到嵌套在子模块下的 class,如 #2 示例所示。所以我尝试这样做:
include_resources = ->(klass) {
begin
klass_string = klass.to_s
klass_resource = klass_string.constantize
if klass_resource.class == Module
return "ParentModule::#{klass_string}".constants.find_all do |module_klass|
module_klass.constantize.included_modules.include?(OtherModule)
end
end
klass_string if klass_resource.included_modules.include?(OtherModule)
rescue NameError # skip all bad naming and other irrelevant constant loading mishaps
next
end
}
不幸的是,这个 returns 是同一个列表。
[注意:@engineersmnky 说明了一种使用 flat_map
消除对 matching_classes
参数的需要的方法。我发现它更难理解,但它是 flat_map
的完美用法和有价值的解决方案。代码发布在 https://repl.it/@engineersmnky/IllinformedMountainousAnkole ]
以下代码使用递归来降低模块的倒置树。结果(在最后打印)是正确的,并且在两个模块中包含 classes。 (我编写了一个最小模块和 class 层次结构以用作示例。)
#!/usr/bin/env ruby
module ParentModule
module OtherModule; end
class ParentClassYes; include OtherModule; end
class ParentClassNo; end
module ChildModule
class ChildClassYes; include OtherModule; end
class ChildClassNo; end
end
end
def classes_for_module_tree(the_module, matching_classes = [])
the_module.constants.each_with_object(matching_classes) \
do |const, matching_classes|
value = the_module.const_get(const)
if value.is_a?(Class)
if value.included_modules.include?(ParentModule::OtherModule)
matching_classes << value
end
elsif value.is_a?(Module)
# Here is where we call this method recursively. We suspend collecting
# matches for this module, call the method to process the newly found
# (sub)module, then use the array returned by that invocation to resume
# processing this module.
matching_classes = classes_for_module_tree(value, matching_classes)
end
end
matching_classes
end
p classes_for_module_tree(ParentModule)
# prints: [ParentModule::ParentClassYes, ParentModule::ChildModule::ChildClassYes]
在深入探讨问题之前,我将尝试解释一下我的代码库的结构。 这个问题与评论中的链接问题不同,因为它涉及模块 classes 中包含的模块列表。不直接在 classes 上或在 1 级模块中
1) 可能有一个 class X,其定义为:
module ParentModule
class X
end
end
2) 在不同的模块下也可能有一个嵌套的 class :
module ParentModule
module ChildModule
class Y
end
end
end
3) 也可能只有一个模块,里面有一些 classes:
module ParentModule
module OtherModule
def some_awesome_method
..does something
end
end
end
我正在尝试在我的 ParentModule
中获取包含 OtherModule
的 classes 的列表。这是我目前所拥有的,运行良好:
include_resources = ->(klass) {
begin
klass_string = klass.to_s
klass_resource = klass_string.constantize
klass_string if klass_resource.included_modules.include?(OtherModule)
rescue NameError # skip all bad naming and other irrelevant constant loading mishaps
next
end
}
所以,如果我这样做 ParentModule.constants.find_all(&include_resources)
,我会得到包含 OtherModule
的 classes 的列表,太棒了!但不幸的是,它无法找到嵌套在子模块下的 class,如 #2 示例所示。所以我尝试这样做:
include_resources = ->(klass) {
begin
klass_string = klass.to_s
klass_resource = klass_string.constantize
if klass_resource.class == Module
return "ParentModule::#{klass_string}".constants.find_all do |module_klass|
module_klass.constantize.included_modules.include?(OtherModule)
end
end
klass_string if klass_resource.included_modules.include?(OtherModule)
rescue NameError # skip all bad naming and other irrelevant constant loading mishaps
next
end
}
不幸的是,这个 returns 是同一个列表。
[注意:@engineersmnky 说明了一种使用 flat_map
消除对 matching_classes
参数的需要的方法。我发现它更难理解,但它是 flat_map
的完美用法和有价值的解决方案。代码发布在 https://repl.it/@engineersmnky/IllinformedMountainousAnkole ]
以下代码使用递归来降低模块的倒置树。结果(在最后打印)是正确的,并且在两个模块中包含 classes。 (我编写了一个最小模块和 class 层次结构以用作示例。)
#!/usr/bin/env ruby
module ParentModule
module OtherModule; end
class ParentClassYes; include OtherModule; end
class ParentClassNo; end
module ChildModule
class ChildClassYes; include OtherModule; end
class ChildClassNo; end
end
end
def classes_for_module_tree(the_module, matching_classes = [])
the_module.constants.each_with_object(matching_classes) \
do |const, matching_classes|
value = the_module.const_get(const)
if value.is_a?(Class)
if value.included_modules.include?(ParentModule::OtherModule)
matching_classes << value
end
elsif value.is_a?(Module)
# Here is where we call this method recursively. We suspend collecting
# matches for this module, call the method to process the newly found
# (sub)module, then use the array returned by that invocation to resume
# processing this module.
matching_classes = classes_for_module_tree(value, matching_classes)
end
end
matching_classes
end
p classes_for_module_tree(ParentModule)
# prints: [ParentModule::ParentClassYes, ParentModule::ChildModule::ChildClassYes]