Created
March 2, 2009 01:06
-
-
Save fairchild/72562 to your computer and use it in GitHub Desktop.
output a graphviz dot file to visualize objet space heirarchy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class String | |
| def to_underscored | |
| self.gsub(/::/, '_') #:: has special meaning in graphviz, so we replace it | |
| end | |
| def evaled | |
| eval self | |
| end | |
| end | |
| class ObjectGrapher | |
| # Return a hash of the mathing objects and the class heritage of those objects in a hash | |
| def collect_heritage(opts={}) | |
| options= {:base_class=>Module, :name_space=>'PoolParty'}.merge(opts) | |
| class_heritage_hash = Hash.new | |
| module_heritage_hash = Hash.new | |
| included_modules_hash = Hash.new | |
| ObjectSpace.each_object(options[:base_class]) do |obj| | |
| # next if !(obj.is_a?(Module) || obj.is_a?(Class)) | |
| next if options[:skip_errno] and obj.name =~ /^Errno/ | |
| next if options[:regex] and obj.to_s.match(/#{ options[:regex] }/).nil? | |
| if obj.class==Module and obj.instance_of? Module | |
| module_heritage_hash["#{obj.to_s.to_underscored}"] = Array.new | |
| mods = obj.to_s.split(/::/) | |
| mods.each_with_index{|m,i| module_heritage_hash["#{obj.to_s.to_underscored}"] << mods[i..mods.size].join('_')} | |
| included_modules_hash["#{obj.to_s.to_underscored}"] = obj.included_modules.collect{|m| m.to_s.to_underscored} | |
| elsif obj.class==Class | |
| puts obj if obj.to_s.nil? | |
| class_heritage_hash["#{obj.to_s.to_underscored}"] = parents(obj) #.reject!{|r| r.to_s.strip.length<1} | |
| included_modules_hash["#{obj.to_s.to_underscored}"] = obj.included_modules.collect{|m| m.to_s.to_underscored} | |
| else | |
| puts obj | |
| end | |
| end | |
| {'classes' => class_heritage_hash, 'included_modules' => included_modules_hash, 'modules' => module_heritage_hash} | |
| end | |
| # return an array of the given objects parents | |
| def parents(obj, heritage=[]) | |
| klass = (obj.is_a?(Class)) ? obj : obj.class | |
| heritage << klass.to_s.to_underscored | |
| if klass.superclass | |
| parents(klass.superclass, heritage) | |
| else | |
| return heritage | |
| end | |
| end | |
| def diagram(opts={}, include_modules=false) | |
| require opts[:lib] if opts[:lib] | |
| File.open('object_tree.dot', 'w') do |f| | |
| f.puts header | |
| f.puts | |
| collected_hash = collect_heritage(opts) | |
| collected_hash.each do |kind, classes| | |
| next if kind == 'included_modules' && !include_modules | |
| f.puts "//#{kind}--------------------" | |
| options = kind=='classes' ? {'color' => 'blue'} : {'color' => 'green'} | |
| # write node definitions first | |
| classes.each do |k,v| | |
| if include_modules && collected_hash['included_modules'][k] | |
| options['label'] = "{#{collected_hash['included_modules'][k].join('|')}}" | |
| end | |
| f.puts dot_element_string(k, opts.merge(options)) | |
| end | |
| # now write out the heirarchy | |
| classes.each do |klass, heritage| | |
| f.puts "#{heritage.join(' -> ')};" if !heritage.blank? | |
| if include_modules | |
| included_modules_to_dot_elements(klass, collected_hash['included_modules'][klass], opts).each{|m| f.puts m} | |
| end | |
| end | |
| end | |
| f.puts footer | |
| end | |
| end | |
| def included_modules_to_dot_elements(klass, modules, opts) | |
| if !modules.blank? | |
| modules.collect{|m| "#{klass} <- #{m}" if m.match(opts[:regex]) }.compact | |
| else | |
| [] | |
| end | |
| end | |
| def dot_element_string(node, opts={}) | |
| options= {'label'=>node, | |
| 'color'=>'blue'}.merge(opts) | |
| node_format_string = options.collect {|k,v| "#{k.to_s}=\"#{v}\""}.join(',') | |
| "#{node} [#{node_format_string}];" | |
| end | |
| def header | |
| str=<<EOF | |
| digraph G { | |
| concentrate = true; | |
| node [fontsize=8,height=0.2, shape=Mrecord]; | |
| layers=\"classes\"; | |
| EOF | |
| end | |
| def footer | |
| "}" | |
| end | |
| end | |
| require 'poolparty' #require the lib to add it to the object space | |
| $options = {:base_class=>Module, :regex=>'PoolParty'} | |
| ObjectGrapher.new.diagram($options) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment