module Workflow
See also README.markdown for documentation
Provides transaction rollback on halt. For now, you can choose between normal halt without any change to ordinary persistence (halt) or halt with transaction rollback (halt_with_rollback!), which will raise an ActiveRecord::Rollback exception. So this only works with ActiveRecord atm.
Public Class Methods
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
@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.rb, line 410 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 klass.new.workflow_diagram(graph_options) end `dot -Tpdf -o'#{fname}.pdf' '#{fname}.dot'` puts "A PDF file was generated at '#{fname}.pdf'" end
# File lib/workflow.rb, line 371 def self.included(klass) klass.send :include, WorkflowInstanceMethods klass.extend WorkflowClassMethods # [ActiveModelPersistence, MongoidPersistence, RemodelPersistence].each do |konst| # if konst.happy_to_be_included_in? klass # raise "including #{konst}" # raise "including #{konst}" # klass.send :include, konst # end # end end
Public Instance Methods
Returns a representation of the state diagram for the calling model as a string in dot language. See Workflow.create_workflow_diagram
for more deails
# File lib/workflow.rb, line 423 def workflow_diagram(graph_options) str = <<-EOS digraph #{self.class} { graph [#{graph_options}]; node [shape=box]; edge [len=1]; EOS self.class.workflow_spec.states.each do |state_name, state| state_meta = state.meta if state == self.class.workflow_spec.initial_state str << %Q{ #{state.name} [label="#{state.name}", shape=circle];\n} else str << %Q{ #{state.name} [label="#{state.name}", shape=#{state_meta[:terminal] ? 'doublecircle' : 'box, style=rounded'}];\n} end state.events.each do |event_name, event| event_meta = event.meta event_meta[:doc_weight] = 6 if event_meta[:main_path] if event_meta[:doc_weight] weight_prop = ", weight=#{event_meta[:doc_weight]}, penwidth=#{event_meta[:doc_weight] / 2 || 0.0}\n" else weight_prop = '' end str << %Q{ #{state.name} -> #{event.transitions_to} [label="#{event_name.to_s.humanize}" #{weight_prop}];\n} end end str << "}\n" return str end