获取从给定 Class 派生的 类 的列表
Get list of classes derived from given Class
我想知道是否可以从给定的 Class
.
中获取 classes 的列表
我明白了,有一个回调 Class::inherited
,它将“在创建当前 class 的子 class 时调用。”这种方法有两个问题:
- 当我不是这个 class 的生产者时(也就是说,我必须对其进行 monkeypatch,)我通常无法确保我的 monkeypatch 会在第一个派生 class 即将创建。
- 在完美世界中,我会得到 classes 的列表,不管它们是否已经初始化,而 回调实际上是在 class 正在实例化.
我明白,RTTI 可能不是检索我需要的信息的最佳方式(因为上面的 2.)。有人会建议另一种方法吗?静态代码分析?任何?
如果有任何想法,我将不胜感激。说,我的目录中有所有感兴趣的代码(换句话说,我对 my classes 感兴趣,它们仅来自一些预定义的 Class,例如 ApplicationController
s 在我的 Rails 应用程序中。)
尝试:
ApplicationController.subclasses
您可以使用 ObjectSpace::each_object:
def derived_classes(klass)
ObjectSpace.each_object(Class).with_object([]) { |k,a| a << k if k < klass }
end
class A ; end
class AA < A ; end
class AB < A ; end
class AC < A ; end
class AAA < AA; end
class AAB < AA; end
class ABA < AB; end
class ABB < AB; end
derived = derived_classes(A)
#=> [AC, AA, AB, AAA, AAB, ABA, ABB]
编辑:
唉,这不是我们所需要的,但让我提供一种方法,一旦派生的 类 被识别出来,它可能会有用:
def order_classes(top, derived)
children = derived.select { |k| k.superclass == top }
return top if children.empty?
{ top=>children.each_with_object([]) { |k,a|
a << order_classes(k, derived-children) } }
end
order_classes(A, derived)
#=> {A=>[AC, {AA=>[AAA, AAB]}, {AB=>[ABA, ABB]}]}
您可以使用 Class#< 和 ObjectSpace#each_object。
class A; end
class B < A; end
class C < A; end
class CC < C; end
ObjectSpace.each_object(Class).select{|c| c < A}
# => [C, B, CC]
class Class
def subclasses
ObjectSpace.each_object(Class).select{|c| c < self}
end
end
A.subclasses
# => [C, B, CC]
我不确定如何命名,inferior_classes,子类,derived_classes,children_rec,后代?
使用 TracePoint 怎么样?让我知道以下代码是否符合您的目的 -
class DerivedClassObserver
def initialize(classes)
@classes, @subclasses = classes, {}
end
def start
@trace_point = TracePoint.new(:class) do |tp|
tp.self.ancestors.map do |ancestor|
if ancestor != tp.self && @classes.include?(ancestor.name)
(@subclasses[ancestor.name] ||= []) << tp.self.name
end
end
end
@trace_point.enable
end
def stop
@trace_point.disable
end
def subclasses(class_name)
@subclasses[class_name]
end
end
用法示例
observer = DerivedClassObserver.new %w|A AA|
observer.start
# Borrowed example from @Cary
class A ; end
class AA < A ; end
class AB < A ; end
class AC < A ; end
class AAA < AA; end
class AAB < AA; end
class ABA < AB; end
class ABB < AB; end
observer.stop
puts "A subclasses #{observer.subclasses('A').join(', ')}"
# => A subclasses AA, AB, AC, AAA, AAB, ABA, ABB
puts "AA subclasses #{observer.subclasses('AA').join(', ')}"
# => AA subclasses AAA, AAB
谢谢
丑陋的解决方案,适用于测试:
def derived from
Dir["#{Rails.root}/**/*.rb"].map do |f|
File.read(f).match(/(\S+)\s*<\s*#{from}\s/) &&
end.compact
end
▶ derived User
#⇒ [Admin, Editor]
我想知道是否可以从给定的 Class
.
我明白了,有一个回调 Class::inherited
,它将“在创建当前 class 的子 class 时调用。”这种方法有两个问题:
- 当我不是这个 class 的生产者时(也就是说,我必须对其进行 monkeypatch,)我通常无法确保我的 monkeypatch 会在第一个派生 class 即将创建。
- 在完美世界中,我会得到 classes 的列表,不管它们是否已经初始化,而 回调实际上是在 class 正在实例化.
我明白,RTTI 可能不是检索我需要的信息的最佳方式(因为上面的 2.)。有人会建议另一种方法吗?静态代码分析?任何?
如果有任何想法,我将不胜感激。说,我的目录中有所有感兴趣的代码(换句话说,我对 my classes 感兴趣,它们仅来自一些预定义的 Class,例如 ApplicationController
s 在我的 Rails 应用程序中。)
尝试:
ApplicationController.subclasses
您可以使用 ObjectSpace::each_object:
def derived_classes(klass)
ObjectSpace.each_object(Class).with_object([]) { |k,a| a << k if k < klass }
end
class A ; end
class AA < A ; end
class AB < A ; end
class AC < A ; end
class AAA < AA; end
class AAB < AA; end
class ABA < AB; end
class ABB < AB; end
derived = derived_classes(A)
#=> [AC, AA, AB, AAA, AAB, ABA, ABB]
编辑:
唉,这不是我们所需要的,但让我提供一种方法,一旦派生的 类 被识别出来,它可能会有用:
def order_classes(top, derived)
children = derived.select { |k| k.superclass == top }
return top if children.empty?
{ top=>children.each_with_object([]) { |k,a|
a << order_classes(k, derived-children) } }
end
order_classes(A, derived)
#=> {A=>[AC, {AA=>[AAA, AAB]}, {AB=>[ABA, ABB]}]}
您可以使用 Class#< 和 ObjectSpace#each_object。
class A; end
class B < A; end
class C < A; end
class CC < C; end
ObjectSpace.each_object(Class).select{|c| c < A}
# => [C, B, CC]
class Class
def subclasses
ObjectSpace.each_object(Class).select{|c| c < self}
end
end
A.subclasses
# => [C, B, CC]
我不确定如何命名,inferior_classes,子类,derived_classes,children_rec,后代?
使用 TracePoint 怎么样?让我知道以下代码是否符合您的目的 -
class DerivedClassObserver
def initialize(classes)
@classes, @subclasses = classes, {}
end
def start
@trace_point = TracePoint.new(:class) do |tp|
tp.self.ancestors.map do |ancestor|
if ancestor != tp.self && @classes.include?(ancestor.name)
(@subclasses[ancestor.name] ||= []) << tp.self.name
end
end
end
@trace_point.enable
end
def stop
@trace_point.disable
end
def subclasses(class_name)
@subclasses[class_name]
end
end
用法示例
observer = DerivedClassObserver.new %w|A AA|
observer.start
# Borrowed example from @Cary
class A ; end
class AA < A ; end
class AB < A ; end
class AC < A ; end
class AAA < AA; end
class AAB < AA; end
class ABA < AB; end
class ABB < AB; end
observer.stop
puts "A subclasses #{observer.subclasses('A').join(', ')}"
# => A subclasses AA, AB, AC, AAA, AAB, ABA, ABB
puts "AA subclasses #{observer.subclasses('AA').join(', ')}"
# => AA subclasses AAA, AAB
谢谢
丑陋的解决方案,适用于测试:
def derived from
Dir["#{Rails.root}/**/*.rb"].map do |f|
File.read(f).match(/(\S+)\s*<\s*#{from}\s/) &&
end.compact
end
▶ derived User
#⇒ [Admin, Editor]