Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/bluzky/as_fsm

A finite state machine implementation for elixir
https://github.com/bluzky/as_fsm

elixir finite-state-machine fsm

Last synced: 3 months ago
JSON representation

A finite state machine implementation for elixir

Awesome Lists containing this project

README

        

# Elixir Finite state machine

This package is inspired by [ecto_fsm](https://github.com/bluzky/ecto_fsm) package

This package allows to use [finite state machine pattern](https://en.wikipedia.org/wiki/Finite-state_machine) in elixir.

> I have rewritten this library to make code simple and easier to use
**Install**

```elixir
def deps do
[
{:as_fsm, "~> 2.0.0"}
]
end
```

## Usage

**First you to define FSM module**
```elixir
defmodule TaskFsm do
use AsFsm, repo: MyApp.Repo
# by default state is check from column `state` of struct
# you can specify your own with
# use AsFsm, repo: MyApp.Repo, column: :status

# define your event
defevent(:start, from: :idle, to: :running)
defevent(:pause, from: :running, to: :paused)
defevent(:stop, from: [:running, :paused], to: :idle)

# you can define some hook
# it is automatically invoked if defined

def before_start(context) do
# do something then return context
context
end

def on_start(context) do
# do something then return context
context
end
end
```

All appropriate event function will be generated. In this example we have
```elixir
def start(context), do: ....
def paus(context), do: ....
def stop(context), do: ....
```

**Then use it**
- Trigger an even transition
```elixir
my_task
|> TaskFsm.new_context(other_params)
|> TaskFsm.start()
```

- Or trigger by name
```elixir
my_task
|> TaskFsm.new_context(other_params)
|> TaskFsm.trigger(:start)
```

## Understand the context

```elixir
@type :: %Context{
struct: struct(),
state: any(),
valid?: boolean(),
error: String.t() | nil,
multi: Ecto.Multi.t() | nil
}
```
- `struct` is your data
- `state` any data you want to pass to transition, it could be parameter from client
- `valid?` if it is true, then data will be persisted
- `error` error message in case `valid?` is false
- `multi` is an `Ecto.Multi` you can pass a multi to `new_context()`, it make sure all action you do in a transaction

## Event hook
For each event you can define 2 hook
- `before_hook` you can define this hook to check for some condition before doing transation
- `on_hook` this is your hook to do some logic on transaction

These 2 hooks must return a context. If you want to stop this transition, set `valid?` to false and return the context.

## Custom persist struct
You can define your own function to persist struct state. This function is run within Multi so that it must return `{:ok, data} | {:error, reason}`

```elixr
def persist(struct, new_state, _context) do
# do your update logic
# or write log here
end
```

## Options

- Custom property name by default property name is :state
```elixir
defmodule ExampleFsm do

use AsFsm,
column: :status,
end
```