Module: Workflow::Draw

Defined in:
lib/workflow/draw.rb

Class Method Summary collapse

Class Method Details

.workflow_diagram(klass, options = {}) ⇒ Object

Generates a `dot` graph of the workflow. Prerequisite: the `dot` binary. (Download from www.graphviz.org/) You can use this method in your own Rakefile like this:

namespace :doc do
  desc "Generate a workflow graph for a model passed e.g. as 'MODEL=Order'."
  task :workflow => :environment do
    require 'workflow/draw'
    Workflow::Draw::workflow_diagram(ENV['MODEL'].constantize)
  end
end

You can influence the placement of nodes by specifying additional meta information in your states and transition descriptions. You can assign higher `weight` value to the typical transitions in your workflow. All other states and transitions will be arranged around that main line. See also `weight` in the graphviz documentation. Example:

state :new do
  event :approve, :transitions_to => :approved, :meta => {:weight => 8}
end

Parameters:

  • klass

    A class with the Workflow mixin, for which you wish the graphical workflow representation

  • target_dir (String)

    Directory, where to save the dot and the pdf files

  • graph_options (String)

    You can change graph orientation, size etc. See graphviz documentation


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
# File 'lib/workflow/draw.rb', line 31

def self.workflow_diagram(klass, options={})
  # TODO: find some replacement for ActiveSupport::Inflector.tableize
  # or make it usage optional
  options = {
    # :name => "#{klass.name.tableize}_workflow".gsub('/', '_'),
    :name => "#{klass.name}_workflow".gsub('/', '_'),
    :path => '.',
    :orientation => "landscape",
    :ratio => "fill",
    :format => 'png',
    :font => 'Helvetica'
  }.merge options

  require 'ruby-graphviz'
  graph = ::GraphViz.new('G', :rankdir => options[:orientation] == 'landscape' ? 'LR' : 'TB', :ratio => options[:ratio])

  # Add nodes
  klass.workflow_spec.states.each do |_, state|
    node = state.draw(graph)
    node.fontname = options[:font]

    state.events.flat.each do |event|
      edge = event.draw(graph, state)
      edge.fontname = options[:font]
    end
  end

  # Generate the graph
  filename = File.join(options[:path], "#{options[:name]}.#{options[:format]}")

  graph.output options[:format] => filename

  puts "
  Please run the following to open the generated file:

  open '#{filename}'
  "
  graph
end