Skip to content

Instantly share code, notes, and snippets.

@dkubb
Created August 9, 2010 18:28
Show Gist options
  • Save dkubb/515866 to your computer and use it in GitHub Desktop.
Save dkubb/515866 to your computer and use it in GitHub Desktop.
Veritas w/Graphiviz
#!/usr/bin/ruby -Ku
# $LOAD_PATH.unshift '/Users/dankubb/Programming/ruby/open-source/veritas/lib'
# $LOAD_PATH.unshift '/Users/dankubb/Programming/ruby/open-source/veritas-optimizer/lib'
require 'veritas'
require 'veritas-optimizer'
require 'graphviz'
include Veritas
class String
def demodulize
self[/[^:]+\z/]
end
end
module Veritas
module Visitor
class Dot
def self.dispatch
@dispatch ||= {}
end
def initialize
@graph = GraphViz.new(:G, :type => :digraph)
end
def accept(object)
visit object
to_dot
end
private
def visit(object)
object.class.ancestors.each do |mod|
method = "visit_#{mod.name.gsub('::', '_')}"
return send(method, object) if respond_to?(method, true)
end
raise NoMethodError, "No visitor for #{object.class.name}"
end
def visit_Veritas_Operation_Unary(unary)
operand = unary.operand
node = @graph.add_node(unary.object_id.to_s, :label => unary.class.name.demodulize, :shape => 'rectangle')
@graph.add_edge(visit(operand), node)
node
end
def visit_Veritas_Operation_Binary(binary)
left, right = binary.left, binary.right
node = @graph.add_node(binary.object_id.to_s, :label => binary.class.name.demodulize, :shape => 'diamond')
@graph.add_edge(visit(left), node)
@graph.add_edge(visit(right), node)
node
end
def visit_Veritas_Algebra_Restriction(restriction)
node = visit_Veritas_Operation_Unary(restriction)
@graph.add_edge(visit(restriction.predicate), node)
node
end
def visit_Veritas_Algebra_Projection(projection)
node = visit_Veritas_Operation_Unary(projection)
node.label = "{ #{projection.class.name.demodulize} | #{projection.header.map { |attribute| "#{attribute.name}: #{attribute.class.name.demodulize}" }.join('|')} }"
node.shape = 'record'
node
end
def visit_Veritas_Algebra_Rename(rename)
node = visit_Veritas_Operation_Unary(rename)
node.label = "{ #{rename.class.name.demodulize} | #{rename.aliases.map { |k,v| "#{k.name} → #{v.name}" }.join(' | ')} }"
node.shape = 'record'
node
end
def visit_Veritas_Attribute(attribute)
@graph.add_node(attribute.object_id.to_s, :label => "#{attribute.name}: #{attribute.class.name.demodulize}", :shape => 'record')
end
def visit_Veritas_Relation(relation)
@graph.add_node(
relation.object_id.to_s,
:label => "{ #{relation.class.name.demodulize} | #{relation.header.map { |attribute| "#{attribute.name}: #{attribute.class.name.demodulize}" }.join(' | ')} }",
:shape => 'record'
)
end
def visit_Object(object)
@graph.add_node(object.object_id.to_s, :label => object.inspect, :shape => 'rectangle')
end
def to_dot
@graph.output('png' => 'visitor.png')
end
end
end
end
visitor = Visitor::Dot.new
header = Relation::Header.new([ [ :id, Integer ], [ :name, String ] ])
body = [ [ 1, 'Dan Kubb' ], [ 2, 'John Doe' ], [ 3, 'Jane Doe' ] ].each
left = Relation.new(header, body)
right = Relation.new(header, body)
relation = left | right
relation = relation & left
relation = relation & right
relation = relation - Relation::Empty.new(header)
relation = relation | Relation::Empty.new(header)
relation = relation * Relation.new([ [ :age, Integer ] ], [ [ 35 ] ])
relation = relation.restrict { |r| r[:name].match(/Kubb/).inverse }.
restrict { |r| r[:name].eq('John Doe') }.
project([ :name ]).
rename(:name => :full_name)
relation = relation.order(relation.header).take(2).reverse.order(relation.header)
#visitor.accept(relation)
visitor.accept(relation.optimize)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment