Graphing Objects in Memory with Ruby
Jan 13, 2007 @ 9:01 pmI was debugging Mechanize the other day, and thought it would be handy to have a graph of objects in memory and they’re relationship with each other. So I put together a simple script that outputs a Graphviz file illustrating what the object points to. Here’s the code:
require 'ograph'
require 'rubygems'
require 'mechanize'
mech = WWW::Mechanize.new
mech.get('http://google.com/')
puts ObjectGraph.graph(mech, /^WWW/)
and the output:
Right now it only supports Arrays, but should be easily extensible to support all other Enumerable types. Here’s the code for ObjectGraph:
class ObjectGraph
def self.graph(target, class_name = /./)
stack = [target]
object_links = []
seen_objects = []
seen_hash = {}
while stack.length > 0
object = stack.pop
next if seen_hash.key? object.object_id
seen_hash[object.object_id] = 1
if object.is_a?(Enumerable) && ! object.is_a?(String)
object.each { |iv|
if iv.class.to_s =~ class_name || object.is_a?(Enumerable)
object_links.push([object.object_id, iv.object_id])
stack.push(iv)
end
}
else
object.instance_variables.each do |iv_sym|
iv = object.instance_variable_get iv_sym
if iv.class.to_s =~ class_name || iv.is_a?(Enumerable)
object_links.push([object.object_id, iv.object_id])
stack.push(iv)
end
end
end
seen_objects.push([object.object_id, object.class])
end
s = <<END
digraph g {
graph [ rankdir = "LR" ];
node [ fontsize = "8"
shape = "ellipse"
];
edge [ ];
END
seen_objects.each { |id, klass|
s += <<END
"#{id}" [
label = "<f0> #{id}|#{klass}"
shape = "record"
]
END
}
object_links.each_with_index { |(from, to), i|
s += "\"#{from}\":f0 -> \"#{to}\":f0 [ id = #{i} ]\n"
}
s += "}\n"
s
end
end
Update: added Enumerable support, so Hashes are now graphed.