mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 7fd053a018
			
		
	
	
		7fd053a018
		
	
	
	
	
		
			
			git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50674 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			95 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| #
 | |
| # 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
 |