Finity

Finity tries to be an extremly lightweight state machine implementation with an easily readable syntax which is essential if you have tens or hundreds of transitions. It is inspired by transitions, a great state machine implementation tightly integrated with ActiveRecord by Jakub Kuźma and Timo Rößner.

The goal of Finity is to provide a state machine implementation which is as slim and fast as possible while maintaining a beautiful and readable syntax. If you need ActiveModel/ActiveRecord integration,transitions is your weapon of choice. However, if you only need a plain state machine implementation which is optimized for readability and efficiency, give Finity a spin.

Installation

If you use Rails, include this into your Gemfile and run bundle install via command line:

gem 'finity'

If you're not using Rails, you can install Finity with gem via command line:

gem install finity

Usage

Finity can transform any class into a state machine. The only thing you have to do is to include it and define some transitions. For example, consider a state machine modelling the different states of reading the contents of a file:

class Readfile
  include Finity

  finity :init => :opened do

    state :opened,
      :enter => proc { @file = File.open '...' }

    state :reading,
      :enter => proc { process @file.readline }

    state :closed,
      :enter => proc { @file.close '...' }

    event :read do
      transitions :from => [:opened, :reading], :to => :reading,
        :if => proc { not @file.eof? },
        :do => proc { log 'Reading next line of file' }

      transitions :from => [:opened, :reading], :to => :reading,
        :do => proc { log 'Reached end of file' }
    end

    event :close do
      transitions :from => [:opened, :reading], :to => :closed,
        :do => proc { log 'Closing file handle' }
    end
  end
end

States

A state is defined by its name and can define transition functions upon entering and leaving the state. These functions can be either referenced as Symbols, Strings, Procs or Lambda:

state :some_state,
  :enter => proc { do_something and some_other_thing },
  :leave => :execute_leave_action!

Events and Transitions

Events are like states defined by their names and can trigger several transitions from several states to other states. The transitions are evaluated in the order they are defined. If a valid transition is found, the execution is stopped and the transition performed:

event :some_event do
  transitions :from => [:some_state, :another_state], :to => :another_state,
    :if => proc { is_some_condition_true? },
    :do => :execute_something_upon_transition

  transitions :from => [:some_state], :to => :another_state,
    :do => :execute_something_else
end

Transitions can be guarded by decision functions (:if) and execute another function upon successful matching (:do). Transitions are triggered by the method event! which is defined for the including object. Many other state machine implementations define one method for each event and for each state, however, Finity tries to be as minimally invasive as possible:

object = SomeClassIncludingFinity.new
if object.state? :some_state
  object.event! :some_event
end