我想知道是否有可能获得从给定Class
派生的类列表。
我知道,有一个回调Class::inherited
,“只要创建当前类的子类就会调用它。”这种方法存在两个问题:
我理解,RTTI可能不是检索我需要的信息的最佳方式(因为上面的2.)。有人会提出另一种方法吗?静态代码分析?任何?
我真的很感激任何想法。说,我在我的目录中拥有所有感兴趣的代码(换句话说,我对我的类感兴趣,仅从一些预定义的类派生,例如我的Rails应用程序中的ApplicationController
。 )
答案 0 :(得分:6)
如何使用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
由于
答案 1 :(得分:2)
您可以使用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]}]}
答案 2 :(得分:0)
尝试:
ApplicationController.subclasses
答案 3 :(得分:0)
你可以使用Class#&lt;和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,subclasses,derived_classes,children_rec,descendants?
答案 4 :(得分:0)
丑陋的解决方案,适用于测试:
def derived from
Dir["#{Rails.root}/**/*.rb"].map do |f|
File.read(f).match(/(\S+)\s*<\s*#{from}\s/) && $1
end.compact
end
▶ derived User
#⇒ [Admin, Editor]