geeks

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

Class Method Details

+ (Object) create_workflow_diagram(klass, target_dir = '.', graph_options = 'rankdir="LR", size="7,11.6", ratio="fill"')

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

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

    Directory, where to save the dot and the pdf files

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

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



366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/workflow.rb', line 366

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

+ (Object) included(klass)



325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/workflow.rb', line 325

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