Skip to content

Commit

Permalink
testing cyclic graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
tenderlove committed Nov 12, 2010
1 parent 85cffe8 commit 3742185
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 16 deletions.
59 changes: 43 additions & 16 deletions lib/awkward/visitor.rb
@@ -1,41 +1,74 @@
module Awkward
class Visitor
Node = Struct.new :object
class Node < Struct.new :object # :nodoc:
def name
object.class.name
end

private
def escape string
string.gsub '"', '\"'
end
end

Edge = Struct.new :name, :left, :right

attr_reader :nodes
attr_reader :edges

def initialize
@nodes = []
@stack = []
@edges = []
@callstack = []
@seen = {}
end

def nodes
@seen.values
end

def accept o
return cycle(o) if @seen[o.object_id]
return connect(@stack.last, @seen[o.object_id]) if @seen.key? o.object_id

node = Node.new o

@seen[o.object_id] = node

@nodes.push node
connect(@stack.last, node) unless @callstack.empty?

cycle o
@stack.push node

send "visit_#{o.class.name.gsub('::', '_')}", o

@stack.pop
end

def to_dot
dot = <<-eodot
digraph "Graph" {
node [width=0.375,height=0.25,shape=box];
eodot

nodes.each do |node|
dot.concat <<-eonode
#{node.object_id} [label="#{node.name}"];
eonode
end

edges.each do |edge|
dot.concat <<-eoedge
#{edge.left.object_id} -> #{edge.right.object_id} [label="#{edge.name}"];
eoedge
end
dot + "}"
end

private

def visit_Hash o
o.each do |k,v|
edge(:key) { accept k }
edge(:value) { accept v }
o.each_with_index do |(k,v),i|
edge("key: #{i}") { accept k }
edge("value: #{i}") { accept v }
end
end

Expand All @@ -55,14 +88,8 @@ def edge sym
@callstack.pop
end

def escape string
string.gsub '"', '\"'
end

def cycle o
if last = @nodes.last && @callstack.last
@edges << Edge.new(@callstack.last, last.object_id, o.object_id)
end
def connect from, to
@edges << Edge.new(@callstack.last, from, to)
end
end
end
23 changes: 23 additions & 0 deletions test/test_awkward.rb
Expand Up @@ -19,4 +19,27 @@ def test_edges
awkward.accept @tree
assert_equal 7, awkward.edges.length
end

def test_edges_have_nodes
awkward = Awkward::Visitor.new
awkward.accept @tree
nodes = awkward.edges.map { |e| [e.left, e.right] }.flatten.uniq
expected = awkward.nodes
assert_equal expected.sort_by(&:object_id), nodes.sort_by(&:object_id)
end

def test_to_dot
awkward = Awkward::Visitor.new
awkward.accept @tree
awkward.to_dot
end

def test_cyclic
foo = {}
foo[:a] = { :b => { :c => foo } }

awkward = Awkward::Visitor.new
awkward.accept foo
awkward.to_dot
end
end

0 comments on commit 3742185

Please sign in to comment.