mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	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
 |