1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
require 'graphviz'
class Object
def to_graph_node
"node#{object_id}"
end
def to_graph_label
inspect.dot_escape
end
def add_to_graph(graph)
graph.add_node(to_graph_node, :label => to_graph_label)
end
end
class Array
def to_graph_label
"{#{map { |e| e.to_graph_label }.join('|')}}"
end
end
class String
DOT_ESCAPE = %w( \\ < > { } )
DOT_ESCAPE_REGEXP = Regexp.compile("(#{Regexp.union(*DOT_ESCAPE).source})")
def dot_escape
gsub(DOT_ESCAPE_REGEXP) {|s| "\\#{s}" }
end
end
class Multimap
def to_graph_label
label = []
@hash.each_key do |key|
label << "<#{key.to_graph_node}> #{key.to_graph_label}"
end
"#{label.join('|')}|<default>"
end
def add_to_graph(graph)
hash_node = super
@hash.each_pair do |key, container|
node = container.add_to_graph(graph)
graph.add_edge("#{hash_node.name}:#{key.to_graph_node}", node)
end
unless default.nil?
node = default.add_to_graph(graph)
graph.add_edge("#{hash_node.name}:default", node)
end
hash_node
end
def to_graph
g = GraphViz::new('G')
g[:nodesep] = '.05'
g[:rankdir] = 'LR'
g.node[:shape] = 'record'
g.node[:width] = '.1'
g.node[:height] = '.1'
add_to_graph(g)
g
end
def open_graph!
to_graph.output(:png => '/tmp/graph.png')
system('open /tmp/graph.png')
end
end
if __FILE__ == $0
$: << 'lib'
require 'multimap'
map = Multimap['a' => 100, 'b' => [200, 300]]
map.open_graph!
end
|