module Workflow::Draw

Public Class Methods

workflow_diagram(klass, options={}) click to toggle source

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

@param klass A class with the Workflow mixin, for which you wish the graphical workflow representation @param [String] target_dir Directory, where to save the dot and the pdf files @param [String] graph_options You can change graph orientation, size etc. See graphviz documentation

# 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