Machinery

Build Status Coverage Status Ebert

Machinery

Machinery is a State Machine library for structs in general that integrates with Pheonix out of the box. It also aims to have (when implemented with Phoenix) an optional build-in GUI that will represent each resource’s state.

DISCLAMER

Machinery is under heavy development, this README does’t match the docs for the current released version 0.2.0, you can check the docs on the proper released Machinery Docs

Installing

The package can be installed by adding machinery to your list of dependencies in mix.exs:

def deps do
  [
    {:machinery, "~> 0.2.0"}
  ]
end

Declaring States

Declare the states you need pasing it as an argment when importing Machinery on the module that will control your states transitions.

Machinery expects a Keyword as argument with two keys states and transitions.

  • states: A List of Atoms representing each state.
  • transitions: A List of Maps, including two keys from and to, to might be an Atom or a List of Atoms.

Example

defmodule YourProject.UserStateMachine do
  use Machinery,
    # The first state declared will be considered the intial state
    states: [:created, :partial, :complete],
    transitions: %{
      created: [:partial, :complete],
      partial: :completed
    }
end

Changing States

To transit a struct into another state, you just need to call Machinery.transition_to/2

Machinery.transition_to/2

It takes two arguments:

  • struct: The struct you want to transit to another state
  • next_event: An atom representing the next state you want the struct to transition to
Machinery.transition_to(your_struct, :next_state)
# {:ok, updated_struct}

Example:

user = Accounts.get_user!(1)
UserStateMachine.transition_to(user, :partial)

Guard functions, before and after callbacks will be checked automatically.

Guard functions

Create guard conditions by adding signatures of the guard_transition/2 function, pattern matching the desired state you want to guard.

Guard conditions should return a boolean:

  • true: Guard clause will allow the transition.
  • false: Transition won’t be allowed.
defmodule YourProject.UserStateMachine do
  use Machinery,
    # The first state declared will be considered the intial state
    states: [:created, :partial, :complete],
    transitions: %{
      created: [:partial, :complete],
      partial: :completed
    }

  def guard_transition(struct, :complete) do
   Map.get(struct, :missing_fields) == false
  end
end

Before and After callbacks

You can also use before and after callbacks to handle desired side effects and reactions to a specific state transition, the implementation is pretty similar to guard functions, you can just declare before_transition/2 and `after_transition/2. Before and After callbacks should return the struct being manipulated. elixir defmodule YourProject.UserStateMachine do use Machinery, # The first state declared will be considered the intial state states: [:created, :partial, :complete], transitions: %{ created: [:partial, :complete], partial: :completed } def before_transition(struct, :partial) do # ... overall desired side effect struct end def after_transition(struct, :completed) do # ... overall desired side effect struct end end