0.01
No commit activity in last 3 years
No release in over 3 years
A simple & intuitive state machine
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

 Project Readme

Lines of Code Maintainability Build Status Coverage Status Downloads

StateJacket

StateJacket provides an intuitive approach to building complex state machines by isolating the concerns of the state transition system & state machine.

Install

gem install state_jacket

Example

Let's define states & transitions (i.e. the state transition system) & a state machine for a turnstyle.

Turnstyle

State Transition System

system = StateJacket::StateTransitionSystem.new
system.add :opened => [:closed, :errored]
system.add :closed => [:opened, :errored]
system.lock # prevent further changes

system.to_h.inspect  # => {"opened"=>["closed", "errored"], "closed"=>["opened", "errored"], "errored"=>nil}
system.transitioners # => ["opened", "closed"]
system.terminators   # => ["errored"]

system.can_transition? :opened => :closed  # => true
system.can_transition? :closed => :opened  # => true
system.can_transition? :errored => :opened # => false
system.can_transition? :errored => :closed # => false

State Machine

Define the events that trigger transitions defined by the state transition system (i.e. the state machine).

machine = StateJacket::StateMachine.new(system, state: "closed")
machine.on :open, :closed => :opened
machine.on :close, :opened => :closed
machine.lock # prevent further changes

machine.to_h.inspect # => {"open"=>[{"closed"=>"opened"}], "close"=>[{"opened"=>"closed"}]}
machine.events       # => ["open", "close"]

machine.state            # => "closed"
machine.is_event? :open  # => true
machine.is_event? :close # => true
machine.is_event? :other # => false

machine.can_trigger? :open # => true
machine.can_trigger? :close # => false

machine.state         # => "closed"
machine.trigger :open # => "opened"
machine.state         # => "opened"

# you can also pass a block when triggering events
machine.trigger :close do |from_state, to_state|
  # custom logic can be placed here
  from_state # => "opened"
  to_state   # => "closed"
end

machine.state # => "closed"

# this is a noop because can_trigger?(:close) is false
machine.trigger :close # => nil

machine.state # => "closed"

begin
  machine.trigger :open do |from_state, to_state|
    raise # the transition isn't performed if an error occurs in the block
  end
rescue
end

machine.state # => "closed"