Skip to content

Latest commit

 

History

History
92 lines (67 loc) · 3.34 KB

README.md

File metadata and controls

92 lines (67 loc) · 3.34 KB

Lines of Code Code Status Dependency Status 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"