class StateMachines::Machine

Public Class Methods

draw(class_names, options = {}) click to toggle source

Draws the state machines defined in the given classes using GraphViz. The given classes must be a comma-delimited string of class names.

Configuration options:

  • :file - A comma-delimited string of files to load that contain the state machine definitions to draw

  • :path - The path to write the graph file to

  • :format - The image format to generate the graph in

  • :font - The name of the font to draw state names in

# File lib/state_machines/graphviz/monkeypatch.rb, line 14
def draw(class_names, options = {})
  raise ArgumentError, 'At least one class must be specified' unless class_names && class_names.split(',').any?

  # Load any files
  if files = options.delete(:file)
    files.split(',').each { |file| require file }
  end

  class_names.split(',').each do |class_name|
    # Navigate through the namespace structure to get to the class
    klass = Object
    class_name.split('::').each do |name|
      klass = klass.const_defined?(name) ? klass.const_get(name) : klass.const_missing(name)
    end

    # Draw each of the class's state machines
    klass.state_machines.each_value do |machine|
      machine.draw(options)
    end
  end
end

Public Instance Methods

draw(graph_options = {}) click to toggle source

Draws a directed graph of the machine for visualizing the various events, states, and their transitions.

This requires both the Ruby graphviz gem and the graphviz library be installed on the system.

Configuration options:

  • :name - The name of the file to write to (without the file extension). Default is “#{owner_class.name}_#{name}”

  • :path - The path to write the graph file to. Default is the current directory (“.”).

  • :format - The image format to generate the graph in. Default is “png'.

  • :font - The name of the font to draw state names in. Default is “Arial”.

  • :orientation - The direction of the graph (“portrait” or “landscape”). Default is “portrait”.

  • :human_names - Whether to use human state / event names for node labels on the graph instead of the internal name. Default is false.

# File lib/state_machines/graphviz/monkeypatch.rb, line 56
def draw(graph_options = {})
  name = graph_options.delete(:name) || "#{owner_class.name}_#{self.name}"
  draw_options = {:human_name => false}
  draw_options[:human_name] = graph_options.delete(:human_names) if graph_options.include?(:human_names)

  graph = Graph.new(name, graph_options)

  # Add nodes / edges
  states.by_priority.each { |state| state.draw(graph, draw_options) }
  events.each { |event| event.draw(graph, draw_options) }

  # Output result
  graph.output
  graph
end