What is apollo?

In Greek and Roman mythology, Apollo (in Greek, Ἀπόλλων—Apóllōn or Ἀπέλλων—Apellōn), is one of the most important and diverse of the Olympian deities. The ideal of the kouros (a beardless youth), Apollo has been variously recognized as a god of light and the sun; truth and prophecy; archery; medicine, healing and plague; music, poetry, and the arts; and more. Apollo is the son of Zeus and Leto, and has a twin sister, the chaste huntress Artemis. Wikipedia: Dionysus (2010/04/23)

Apollo is an fork of Workflow.


Features & Issues

This is a brand new project, so if you find bugs or use cases that would helpful to satisfy, post an Issue on Github.

This project is intended to be a very eclectic mix of helpful tools, so please feel free to send pull requests. That said, make absolutely sure your modifications are well tested. The hodge-podge nature of this project may make it prone to issues, so no code will be pulled-in that is not fully_tested.

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.

Documentation Warning

Beware that the below documentation has NOT been validated for the changes from Workflow to Apollo.

What is workflow?

Workflow is a finite-state-machine-inspired API for modeling and interacting with what we tend to refer to as 'apollo'.

A lot of business modeling tends to involve apollo-like concepts, and the aim of this library is to make the expression of these concepts as clear as possible, using similar terminology as found in state machine theory.




class Article
  include Apollo
  apollo do
    state :new do
      event :submit, :to => :awaiting_review
    state :awaiting_review do
      event :review, :to => :being_reviewed
    state :being_reviewed do
      event :accept, :to => :accepted
      event :reject, :to => :rejected
    state :accepted
    state :rejected

Nice, isn't it!


article = Article.new
article.accepted? # => false
article.new? # => true


=> #<Apollo::State:0x7f1e3d6731f0 @events={
  :submit=>#<Apollo::Event:0x7f1e3d6730d8 @action=nil, 
    @to=:awaiting_review, @name=:submit, @meta={}>}, 
  name:new, meta{}


article.awaiting_review? # => true

Events are actually instance methods on a apollo, and depending on the state you're in, you'll have a different set of events used to transition to other states.


gem install apollo

Alternatively you can just download the lib/apollo.rb and put it in the lib folder of your Rails or Ruby application.



$ irb
require 'rubygems'
require 'apollo'


Transition event handler

The best way is to use convention over configuration and to define a method with the same name as the event. Then it is automatically invoked when event is raised. For the Article apollo defined earlier it would be:

class Article
  def reject


You can also define event handler accepting/requiring additional arguments:

class Article
  def review(reviewer = '')

article2 = Article.new
article2.review!('Homer Simpson') # => [Homer Simpson] is now reviewing the article

The old, deprecated way


event :review, :to => :being_reviewed do |reviewer|
  # store the reviewer


Integration with ActiveRecord

Apollo library can handle the state persistence fully automatically. You only need to define a string field on the table called apollo_state and include the apollo mixin in your model class as usual:

class Order < ActiveRecord::Base
  include Apollo
  apollo do
    # list states and transitions here

On a database record loading all the state check methods e.g. article.state, article.awaiting_review? are immediately available. For new records or if the apollo_state field is not set the state defaults to the first state declared in the apollo specification. In our example it is :new, so Article.new.new? returns true and Article.new.approved? returns false.


You can change this behaviour by overriding persist_apollo_state method.

Custom apollo database column


class LegacyOrder < ActiveRecord::Base
  include Apollo

  apollo_column :foo_bar # use this legacy database column for
                           # persistence

Single table inheritance

Single table inheritance is also supported. Descendant classes can either inherit the apollo definition from the parent or override with its own definition.

Custom apollo state persistence

If you do not use a relational database and ActiveRecord, you can still integrate the apollo very easily. To implement persistence you just need to override load_apollo_state and persist_apollo_state(new_value) methods. Lets see an example for using CouchDB, a document oriented database.

Integration with CouchDB


require 'couchtiny'
require 'couchtiny/document'
require 'apollo'

class User < CouchTiny::Document
  include Apollo
  apollo do
    state :submitted do
      event :activate_via_link, :to => :proved_email
    state :proved_email

  def load_apollo_state

  def persist_apollo_state(new_value)
    self[:apollo_state] = new_value

Please also have a look at the full source code.

Accessing your apollo specification

You can easily reflect on apollo specification programmatically - for the whole class or for the current object. Examples:

article2.current_state.events # lists possible events from here
article2.current_state.events[:reject].to # => :rejected


# list all events for all states
Article.apollo_spec.states.values.collect &:events


class MyProcess
  include Apollo
  apollo do
puts MyProcess.apollo_spec.states[:supplemental].meta[:importance] # => 1

The apollo library itself uses this feature to tweak the graphical representation of the apollo. See below.

Advanced transition hooks


We already had a look at the declaring callbacks for particular apollo events. If you would like to react to all transitions to/from the same state in the same way you can use the on_entry/on_exit hooks. You can either define it with a block inside the apollo definition or through naming convention, e.g. for the state :pending just define the method on_pending_exit(new_state, event, *args) somewhere in your class.



apollo do
  state :one do
    event :increment, :to => :two
  state :two
  on_transition do |from, to, triggering_event, *event_args|
    Log.info "#{from} -> #{to}"


If you want to halt the transition conditionally, you can just raise an exception. There is a helper called halt!, which raises the Apollo::TransitionHalted exception. You can provide an additional halted_because parameter.

def reject(reason)
    unless reason =~ /important/i


Hook order

The whole event sequence is as follows:

* event specific action
* on_transition (if action did not halt)
* on_exit
* PERSIST WORKFLOW STATE, i.e. transition
* on_entry

Documenting with diagrams

You can generate a graphical representation of your apollo for documentation purposes. S. Apollo::create_apollo_diagram.


Copyright 2010 Travis D. Warlick, Jr.

You may obtain a copy of the License at


Unless required by applicable law or agreed to in writing, software
See the License for the specific language governing permissions and
limitations under the License.

The original work from Workflow

Author: Vladimir Dobriakov, http://www.innoq.com/blog/vd, http://blog.geekq.net/

Copyright (c) 2008-2009 Vodafone


Based on the work of Ryan Allen and Scott Barron

Licensed under MIT license, see the MIT-LICENSE file.

Earlier versions

The workflow library was originally written by Ryan Allen.

The version 0.3 was almost completely (including ActiveRecord integration, API for accessing apollo specification, method_missing free implementation) rewritten by Vladimir Dobriakov keeping the original apollo DSL spirit.