Skip to content

Instantly share code, notes, and snippets.

@fairchild
Created March 2, 2009 01:06
Show Gist options
  • Select an option

  • Save fairchild/72562 to your computer and use it in GitHub Desktop.

Select an option

Save fairchild/72562 to your computer and use it in GitHub Desktop.
output a graphviz dot file to visualize objet space heirarchy
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