Module: Workflow

Defined in:
lib/workflow.rb

Overview

See also README.markdown for documentation

Defined Under Namespace

Modules: ActiveRecordInstanceMethods, RemodelInstanceMethods, WorkflowClassMethods, WorkflowInstanceMethods Classes: Event, NoTransitionAllowed, Specification, State, TransitionHalted, WorkflowDefinitionError, WorkflowError

Class Method Summary collapse

Class Method Details

.create_workflow_diagram(klass, target_dir = '.', graph_options = 'rankdir="LR", size="7,11.6", ratio="fill"') ⇒ 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 graph of the workflow."
  task :workflow => :environment do # needs access to the Rails environment
    Workflow::create_workflow_diagram(Order)
  end
end

You can influence the placement of nodes by specifying additional meta information in your states and transition descriptions. You can assign higher ‘doc_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 => {:doc_weight => 8}
end

Parameters:

  • klass

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

  • target_dir (String) (defaults to: '.')

    Directory, where to save the dot and the pdf files

  • graph_options (String) (defaults to: 'rankdir="LR", size="7,11.6", ratio="fill"')

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



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/workflow.rb', line 338

def self.create_workflow_diagram(klass, target_dir='.', graph_options='rankdir="LR", size="7,11.6", ratio="fill"')
  workflow_name = "#{klass.name.tableize}_workflow".gsub('/', '_')
  fname = File.join(target_dir, "generated_#{workflow_name}")
  File.open("#{fname}.dot", 'w') do |file|
    file.puts %Q|
digraph #{workflow_name} {
graph [#{graph_options}];
node [shape=box];
edge [len=1];
    |

    klass.workflow_spec.states.each do |state_name, state|
      file.puts %Q{  #{state.name} [label="#{state.name}"];}
      state.events.each do |event_name, event|
        meta_info = event.meta
        if meta_info[:doc_weight]
          weight_prop = ", weight=#{meta_info[:doc_weight]}"
        else
          weight_prop = ''
        end
        file.puts %Q{  #{state.name} -> #{event.transitions_to} [label="#{event_name.to_s.humanize}" #{weight_prop}];}
      end
    end
    file.puts "}"
    file.puts
  end
  `dot -Tpdf -o'#{fname}.pdf' '#{fname}.dot'`
  puts "
Please run the following to open the generated file:

open '#{fname}.pdf'

"
end

.included(klass) ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/workflow.rb', line 297

def self.included(klass)
  klass.send :include, WorkflowInstanceMethods
  klass.extend WorkflowClassMethods
  if Object.const_defined?(:ActiveRecord)
    if klass < ActiveRecord::Base
      klass.send :include, ActiveRecordInstanceMethods
      klass.before_validation :write_initial_state
    end
  elsif Object.const_defined?(:Remodel)
    if klass < Remodel::Entity
      klass.send :include, RemodelInstanceMethods
    end
  end
end