lib/dogviz.rb in dogviz-0.0.10 vs lib/dogviz.rb in dogviz-0.0.11
- old
+ new
@@ -1,8 +1,22 @@
require 'ruby-graphviz'
module Dogviz
+ class Process
+ def initialize(processor, description)
+ @processor = processor
+ @description = description
+ end
+ def name
+ @processor.name
+ end
+ end
+ module Flowable
+ def does(action)
+ Process.new(self, action)
+ end
+ end
module Common
def create_id(name, parent)
parts = []
parts << parent.id if parent.respond_to? :id
parts += name.split /\s/
@@ -70,10 +84,17 @@
def on_top_rollup?
rollup? && !under_rollup?
end
end
module Parent
+ def nominate(names_to_values)
+ names_to_values.each {|name, value|
+ self.class.send(:define_method, name) do
+ value
+ end
+ }
+ end
def find_all(&matcher)
raise MissingMatchBlockError.new unless block_given?
@by_name.find_all &matcher
end
def find(name=nil, &matcher)
@@ -102,10 +123,11 @@
end
end
class Thing
include Common
+ include Flowable
attr_reader :parent
attr_reader :name, :id, :pointers, :edge_heads
def initialize(parent, name, options = {})
@parent = parent
@@ -358,10 +380,113 @@
node[key] = value
end
end
end
+ class Flow
+ def initialize(sys, name)
+ @sys = sys
+ @name = name
+ @calls = []
+ end
+
+ def flows(*steps)
+ from = nil
+ to = nil
+ label = nil
+ steps.each do |step|
+ if from.nil?
+ from = ensure_is_thing(step)
+ elsif label.nil? && step.is_a?(String)
+ label = step
+ elsif to.nil?
+ to = ensure_is_thing(step)
+ end
+ unless to.nil?
+ calls << [from, to, label]
+ from = to
+ to = label = nil
+ end
+ end
+ end
+
+ def ensure_is_thing(step)
+ raise "Expected some thing or process: '#{step}' already got: #{calls}" unless step.is_a?(Thing) || step.is_a?(Process)
+ step
+ end
+
+ def output(type_to_file)
+ type = type_to_file.keys.first
+ raise "Only support sequence, not: '#{type}'" unless type == :sequence
+ render.output(type_to_file)
+ end
+
+ def render
+ renderer = SequenceRenderer.new(@name)
+ calls.each do |from, to, label|
+ renderer.render_edge from, to, {label: label}
+ end
+ renderer.rendered
+ end
+ private
+ attr_reader :calls
+ end
+
+
+ class RenderedSequence
+ def initialize(lines)
+ @lines = lines
+ end
+ def output(type_to_file)
+ text = @lines.map(&:strip).join "\n"
+ File.write type_to_file.values.first, text
+ text
+ end
+ end
+
+ class SequenceRenderer
+ attr_reader :lines
+ def initialize(title)
+ @lines = []
+ end
+
+ def render_edge(from, other, options)
+
+ detail = options[:label]
+ receiver_label = other.name
+ sender_label = from.name
+ if other.is_a?(Process)
+ receiver_label = process_start_label(receiver_label)
+ detail = process_annotations(detail)
+ elsif from.is_a?(Process)
+ receiver_label = process_end_label(receiver_label)
+ end
+ lines << "#{sender_label} -> #{receiver_label}: #{detail}"
+ end
+
+ def rendered
+ RenderedSequence.new lines
+ end
+
+ private
+
+ def process_start_label(receiver_label)
+ "+#{receiver_label}"
+ end
+
+ def process_end_label(receiver_label)
+ "-#{receiver_label}"
+ end
+
+ def process_annotations(detail)
+ detail = [detail,
+ 'note right of cook',
+ ' cooks burger',
+ 'end note'].join("\n")
+ end
+ end
+
class System
include Parent
attr_reader :render_hints, :title, :children, :graph
@@ -378,9 +503,13 @@
def output(*args)
render
out = graph.output *args
puts "Created output: #{args.join ' '}" if run_from_command_line?
out
+ end
+
+ def flow(name)
+ Flow.new self, name
end
def render(type=:graphviz)
return @graph if @rendered
raise "dunno bout that '#{type}', only know :graphviz" unless type == :graphviz