ruby のオブジェクトの継承関係を tree っぽく表示することが出来るようになります。
class ObjectTree
SPACE_SIZE = 8
T_LINE = '├─────'
I_LINE = '│'
L_LINE = '└─────'
def self.create(klass)
new(klass)
end
def initialize(klass)
@queue = []
walk(klass)
end
def to_s
@queue.join
end
private
def output_node(klass)
klass.instance_of?(Class) ? "<C> #{klass}\n" : "<M> #{klass}\n"
end
def get_line(end_line: nil, space: '')
end_line ? "#{space}#{L_LINE} " : "#{space}#{T_LINE} "
end
def get_space(end_line: nil)
end_line ? ' ' * SPACE_SIZE : I_LINE + ' ' * (SPACE_SIZE - 1)
end
def walk(klass, space = '', path: [])
path << klass
@queue << output_node(klass)
modules = get_modules(klass, path.reverse)
while sub = modules.shift
@queue << get_line(end_line: modules.empty?, space: space)
walk(sub, space + get_space(end_line: modules.empty?), path: path.dup)
end
end
def get_modules(klass, path)
ObjectSpace.each_object(Module).map do |k|
l = k.ancestors
if l.each_cons(path.size).include?(path)
(l[l.index(k)..l.index(klass)] - path).last
end
end.compact.uniq.sort_by(&:to_s)
end
end
puts ObjectTree.create(Numeric)
実行結果
<C> Numeric
├───── <C> Complex
├───── <C> Float
├───── <C> Integer
└───── <C> Rational
Ruby のバージョンが 2.4 以前だと結果が異なります。(Integer に統一される前)
<C> Numeric
├───── <C> Complex
├───── <C> Float
├───── <C> Integer
│ ├───── <C> Bignum
│ └───── <C> Fixnum
└───── <C> Rational
BasicObject の結果はちょっと大きかったので gist に貼り付けておきます
Gem にしました
gem のほうは結果に色がついてちょっとだけ見やすくなっています。
こんな感じで使えるようになります
sample.rb
require "object_tree"
module D
end
module E
end
class A
include D
end
class B < A
end
class C < A
include E
end
class F < B
include E
end
puts ObjectTree.create(D)
結果
<M> D
└───── <C> A
├───── <C> B
│ └───── <M> E
│ └───── <C> F
└───── <M> E
└───── <C> C