Today I’m happy to announce the release of AlterEgo, a state-pattern library for Ruby. AlterEgo was born about a year ago, when I found a need to formalize state-based behavior in Ruby objects. I surveyed the existing libraries at the time (a set which, IIRC, consisted of just acts_as_state_machine), and found they didn’t do quite what I wanted. Other solutions were focused on defining states and transitions, not on providing the kind of delegation-based behavior switching that the Gang of Four State Pattern describes. So I wrote AlterEgo, and it has been serving us well at “MDLogix”:http://mdlogix.com ever since. I’ve been wanting to open-source it for a while, but this month I finally got around to getting approval and doing the necessary extraction and packaging.

There’s plenty of explanation and documentation at the “AlterEgo project site”:http://alter-ego.rubyforge.org , so I won’t go into depth here. In a nutshell, AlterEgo is a library you include into your classes in order to give them state-based “personalities”. Here’s the canonical example:

  class TrafficLight
    include AlterEgo

    state :proceed, :default => true do
      handle :color do
    "green"
      end
      transition :to => :caution, :on => :cycle!
    end

    state :caution do
      handle :color do
    "yellow"
      end
      transition :to => :stop, :on => :cycle!
    end

    state :stop do
      handle :color do
    "red"
      end 
      transition :to => :proceed, :on => :cycle!
    end
  end

  light = TrafficLight.new
  light.color                     # => "green"
  light.cycle!
  light.color                     # => "yellow"
  light.cycle!
  light.color                     # => "red"
  light.cycle!
  light.color                     # => "green"

Under the covers this is all accomplished with a proxy module and method forwarding. The underlying model, as well as much of the terminology used in the API, is based on the State Pattern as described in the book Design Patterns:

A “context” object – the class you want to have state-based behavior – always has a reference to one and only one “state” object. When “requests” – methods calls – are received, they are delegated to the current state object, which handles them in whatever way is appropriate for that state. In AlterEgo, we take advantage of Ruby’s dynamic nature to execute these “handlers” in the context of the original context object – so we can write them as if they were instance methods of the context object, with full access to instance variables, private methods, etc.

For more information, documentation, and information about how to contribute, see “the project site”:http://alter-ego.rubyforge.org.

Published by Avdi Grimm

7 Comments

  1. This looks pretty nice. I was curious tho, have you looked at Mixology? I was thinking that the state blocks could setup anonymous modules, and instead of the handle blocks you could use normal methods. Each module would correspond to a specific state and get mixed into the object as part of each state transition.

    Reply
    • It's an approach I've considered, and I may move towards it, although I'm pretty sure I want to stay compatible with explicit state classes. One of the items on the TODO list, however, is being able to define ordinary ordinary methods in state { } blocks instead of using #handle.

      Reply
  2. Looks very clean and nice!

    Reply
  3. Looks very clean and nice!

    Reply
  4. Looks very clean and nice!

    Reply
  5. Looks very clean and nice!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *