Graphing Objects in Memory with Ruby
2007-01-13 @ 21:01I 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.