No commit activity in last 3 years
No release in over 3 years
InterstateMachine is a simple state machine which use interactors to trigger transitions
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.14
~> 9.1
~> 10.0
~> 3.6
~> 0.15
~> 1.3

Runtime

 Project Readme

Maintainability Test Coverage

InterstateMachine

When state machine meets interactor. InterstateMachine is a simple state machine which use interactors to trigger transitions. Long story short, an object receives an event which is a interactor and you can do fantastic things with interactors. What is an interactor? "An interactor is a simple, single-purpose object."

Installation

gem install interstate_machine

Gemfile

gem 'interstate_machine', '~> 1.0.0'

Usage

class Order
  include InterstateMachine

  attr_accessor :state

  initial_state :cart

  transition_table :cart, :payment, :complete do
    on event: :next do |event|
      allow event: event, transition_to: [:payment], from: [:cart]
    end
    on event: :complete, transition_to: [:complete], from: [:payment]
  end
end

When including InterstateMachine in an ActiveRecord class, it does not need any attr_accessor to store the state. transition_table is where the state machine rules and states are defined. Each event represent an Interactor that is called to process the transition.

on can take a block which defines different transition(rules) for the same event or a single transition

In addition to the class where you define the state machine, you also need to create interactors for each event.

In this case we have an event next that could trigger many transitions(:cart, :address, :payment and so on) so we define an interactors for each of them. NextPayment, Complete. Yes, when an event triggers a transition to a single state and it's not a block, you have to name the class like the event name.

In a normal checkout you proably have something like NextAddress, NextDelivery, NextPayment, NextConfirm, Complete

class NextPayment
  include Interactor

  before :ensure_line_item

  def call
    # update order totals ..
  end

  private

  def ensure_line_item
    context.fail!(error: 'you need to add a product!') unless context.object.line_items.present?
  end
end

Note: You can use all the interactor magic (before, around, after) hooks. Whoop!

You can access the class where you have included InterstateMachine with context.object

When transition is allowed:

order = Order.new
order.add(line_item)
order.next
#=> :payment

When transition can't happen because something wrong executing the event

order = Order.new
order.next
#=> 'you need to add a product!'

When transition is no allowed

order = Order.new
order.state
#=> :cart
order.complete
#=> RuntimeError Exception:

Contributing

Feel free to play around, fork, add, pull request, and get a hug. If you decide to pull request please add tests