Module: Apollo

Defined in:
lib/apollo.rb,
lib/apollo/event.rb,
lib/apollo/state.rb,
lib/apollo/state_set.rb,
lib/apollo/specification.rb,
lib/apollo/active_record_extensions.rb

Overview

Copyright 2010 Travis D. Warlick, Jr.

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Original work from Workflow:

Copyright (c) 2008-2009 Vodafone
Copyright (c) 2007-2008 Ryan Allen, FlashDen Pty Ltd

Defined Under Namespace

Modules: ActiveRecordExtensions, ClassMethods, InstanceMethods Classes: ApolloDefinitionError, ApolloError, Event, NoTransitionAllowed, Specification, State, StateNotFound, StateSet, TransitionHalted

Constant Summary collapse

VERSION =

The current version

File.read(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'VERSION')).strip

Class Method Summary collapse

Class Method Details

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

Generates a ‘dot` graph of the state machine. Prerequisite: the `dot` binary. You can use it in your own Rakefile like this:

namespace :doc do
  desc "Generate a graph of the state machine."
  task :state_machine do
    Apollo::create_state_diagram(Order.new)
  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 state machine. 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, :to => :approved, :meta => {:doc_weight => 8}
end

Parameters:

  • klass

    A class with the Apollo mixin, for which you wish the graphical state machine representation

  • target_dir (String)

    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



262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/apollo.rb', line 262

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

    klass.state_machine.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.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



224
225
226
227
228
229
230
231
232
233
234
# File 'lib/apollo.rb', line 224

def self.included(klass)
  klass.send :include, InstanceMethods
  klass.extend ClassMethods
  if Object.const_defined?(:ActiveRecord)
    if klass < ActiveRecord::Base
      klass.send :include, ActiveRecordExtensions::InstanceMethods
      klass.extend ActiveRecordExtensions::ClassMethods
      klass.before_validation :write_initial_state
    end
  end
end