summaryrefslogtreecommitdiff
path: root/tool/make_hgraph.rb
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-05-29 08:39:50 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-05-29 08:39:50 +0000
commit7fd053a01832a4899cca28f62af246592f8e3f59 (patch)
tree43018adb729f0d2da6f179d43d4e005e52228a3f /tool/make_hgraph.rb
parent451fe269e5ab1270a53ac7bdeceabe47fd431f95 (diff)
* tool/make_hgraph.rb: added.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50674 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'tool/make_hgraph.rb')
-rw-r--r--tool/make_hgraph.rb95
1 files changed, 95 insertions, 0 deletions
diff --git a/tool/make_hgraph.rb b/tool/make_hgraph.rb
new file mode 100644
index 0000000..0f38881
--- /dev/null
+++ b/tool/make_hgraph.rb
@@ -0,0 +1,95 @@
+#
+# Make dot file of internal class/module hierarchy graph.
+#
+
+require 'objspace'
+
+module ObjectSpace
+ def self.object_id_of obj
+ if obj.kind_of?(ObjectSpace::InternalObjectWrapper)
+ obj.internal_object_id
+ else
+ obj.object_id
+ end
+ end
+
+ T_ICLASS_NAME = {}
+
+ def self.class_name_of klass
+ case klass
+ when Class, Module
+ # (singleton class).name returns nil
+ klass.name || klass.inspect
+ when InternalObjectWrapper # T_ICLASS
+ if klass.type == :T_ICLASS
+ "#<I:#{class_name_of(ObjectSpace.internal_class_of(klass))}>"
+ else
+ klass.inspect
+ end
+ else
+ klass.inspect
+ end
+ end
+
+ def self.module_refenreces klass
+ h = {} # object_id -> [klass, class_of, super]
+ stack = [klass]
+ while klass = stack.pop
+ obj_id = ObjectSpace.object_id_of(klass)
+ next if h.has_key?(obj_id)
+ cls = ObjectSpace.internal_class_of(klass)
+ sup = ObjectSpace.internal_super_of(klass)
+ stack << cls if cls
+ stack << sup if sup
+ h[obj_id] = [klass, cls, sup].map{|e| ObjectSpace.class_name_of(e)}
+ end
+ h.values
+ end
+
+ def self.module_refenreces_dot klass
+ result = []
+ rank_set = {}
+
+ result << "digraph mod_h {"
+ # result << " rankdir=LR;"
+ module_refenreces(klass).each{|(m, k, s)|
+ # next if /singleton/ =~ m
+ result << "#{m.dump} -> #{s.dump} [label=\"super\"];"
+ result << "#{m.dump} -> #{k.dump} [label=\"klass\"];"
+
+ unless rank = rank_set[m]
+ rank = rank_set[m] = 0
+ end
+ unless rank_set[s]
+ rank_set[s] = rank + 1
+ end
+ unless rank_set[k]
+ rank_set[k] = rank
+ end
+ }
+
+ rs = [] # [[mods...], ...]
+ rank_set.each{|m, r|
+ rs[r] = [] unless rs[r]
+ rs[r] << m
+ }
+
+ rs.each{|ms|
+ result << "{rank = same; #{ms.map{|m| m.dump}.join(", ")}};"
+ }
+ result << "}"
+ result.join("\n")
+ end
+
+ def self.module_refenreces_image klass, file
+ dot = module_refenreces_dot(klass)
+ img = nil
+ IO.popen("dot -Tpng", 'r+'){|io|
+ #
+ io.puts dot
+ io.close_write
+ img = io.read
+ }
+ open(File.expand_path(file), 'w+'){|f| f.puts img}
+ end
+end