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 keysfrom
andto
,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 statenext_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