From 3eeed18e0cb71f5a56995c2d6a67eff0af618deb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 18:05:38 -0700 Subject: adding a dot visitor to make our lives easier --- lib/arel.rb | 1 + lib/arel/select_manager.rb | 5 +++ lib/arel/visitors/dot.rb | 108 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 lib/arel/visitors/dot.rb diff --git a/lib/arel.rb b/lib/arel.rb index 8465d8e658..e63e205779 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -18,3 +18,4 @@ require 'arel/sql_literal' #### require 'arel/visitors/to_sql' +require 'arel/visitors/dot' diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 6420142fa0..c9484295d8 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -25,5 +25,10 @@ module Arel @head.limit = limit self end + + def insert stuff + viz = Visitors::Dot.new + puts viz.accept stuff + end end end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb new file mode 100644 index 0000000000..6fd2728839 --- /dev/null +++ b/lib/arel/visitors/dot.rb @@ -0,0 +1,108 @@ +module Arel + module Visitors + class Dot + class Node # :nodoc: + attr_accessor :name, :id, :fields + + def initialize name, id, fields = [] + @name = name + @id = id + @fields = fields + end + end + + class Edge < Struct.new :name, :from, :to # :nodoc: + end + + def initialize + @nodes = [] + @edges = [] + @node_stack = [] + @edge_stack = [] + @seen = {} + end + + def accept object + visit object + to_dot + end + + private + def visit_Arel_Table o + visit_edge o, "name" + end + + def visit_Arel_Attribute o + visit_edge o, "relation" + visit_edge o, "name" + end + alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute + alias :visit_Arel_Attributes_String :visit_Arel_Attribute + alias :visit_Arel_Attributes_Time :visit_Arel_Attribute + + def visit_String o + @node_stack.last.fields << o + end + alias :visit_Time :visit_String + alias :visit_NilClass :visit_String + + def visit_Hash o + o.each_with_index do |(k,v),i| + edge("key_#{i}") { visit k } + edge("value_#{i}") { visit v } + end + end + + def visit_edge o, method + edge(method) { visit o.send(method) } + end + + def visit o + if node = @seen[o.object_id] + @edge_stack.last.to = node + return + end + + node = Node.new(o.class.name, o.object_id) + @seen[node.id] = node + @nodes << node + with_node node do + send "visit_#{o.class.name.gsub('::', '_')}", o + end + end + + def edge name + edge = Edge.new(name, @node_stack.last) + @edge_stack.push edge + @edges << edge + yield + @edge_stack.pop + end + + def with_node node + if edge = @edge_stack.last + edge.to = node + end + + @node_stack.push node + yield + @node_stack.pop + end + + def to_dot + "digraph \"ARel\" {\nnode [width=0.375,height=0.25,shape=record];\n" + + @nodes.map { |node| + label = "#{node.name}" + + node.fields.each_with_index do |field, i| + label << "|#{field}" + end + + "#{node.id} [label=\"#{label}\"];" + }.join("\n") + "\n" + @edges.map { |edge| + "#{edge.from.id} -> #{edge.to.id} [label=\"#{edge.name}\"];" + }.join("\n") + "\n}" + end + end + end +end -- cgit v1.2.3