Build Status

Switcher is lightweight event-driven state machine.

Basic usage:

class Package
  include Switcher::Object

  def initialize(weight)
    @sent_weight = weight.to_f
    @tracking_number = nil
  end

  switcher :delivery do
    state :requested do
      on :send, switch_to: :sent do |ev, num|
        @tracking_number = num
      end
    end

    state :sent do
      before :receive, call: :check_number

      on :receive do |ev, number, weight|
        if weight < (@weight - 0.3)
          ev.switch_to :stolen
        else
          ev.switch_to :received
        end
      end

      after :receive do |ev|
        unpack if delivery_received?
      end

      on :miss, switch_to: :missed
    end

    state :received
    state :stolen
    state :missed
  end

  def check_number(ev, number, weight)
    ev.stop if number.to_s != @tracking_number
  end

  def unpack
    puts "TADA!"
  end
end

package = Package.new(4.2)

package.delivery # => :requested
package.can_send? # => true
package.send! "AB123456CD"
package.delivery # => :sent
package.receive!(3.5, "CD654321AB")
package.delivery # => :sent
package.receive!(4.1, "AB123456CD")
# > TADA!

package.delivery # => :received
package.delivery_prev # => :sent
package.delivery_received? # => true
package.can_miss? # => false

Usage with Active Record:

class User < ActiveRecord::Base
  include Switcher::ActiveRecord

  switcher :membership do
    state :guest do
      on :approve, switch_to: :member
    end
    state :member do
      on :ban, switch_to: :banned do |ev, reason|
        ev.stop unless reason
        ban_reason = reason
      end
    end
    state :banned do
      on :unban, switch_to: :member
      after :unban do
        ban_reason = nil
      end
    end
  end
end

user = User.find(5)
user.ban! "Stupid bastard"
user.membership # => :banned
user.save

More examples:

TODO:

  • 1.8 compat
  • Refactoring
  • Events without state
  • Ability to define validations, associations etc. in state (ability to call static methods from object)

Adapters TODO:

  • ActiveModel
  • Virtus
  • Mongoid