{"id":20080633,"url":"https://github.com/bluzky/as_fsm","last_synced_at":"2025-05-05T23:31:19.880Z","repository":{"id":48359663,"uuid":"129372389","full_name":"bluzky/as_fsm","owner":"bluzky","description":"A finite state machine implementation for elixir","archived":false,"fork":false,"pushed_at":"2021-07-30T04:40:57.000Z","size":28,"stargazers_count":15,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-25T23:24:25.709Z","etag":null,"topics":["elixir","finite-state-machine","fsm"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/as_fsm","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bluzky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-04-13T08:25:07.000Z","updated_at":"2025-01-22T00:44:43.000Z","dependencies_parsed_at":"2022-08-29T21:31:25.488Z","dependency_job_id":null,"html_url":"https://github.com/bluzky/as_fsm","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluzky%2Fas_fsm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluzky%2Fas_fsm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluzky%2Fas_fsm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluzky%2Fas_fsm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bluzky","download_url":"https://codeload.github.com/bluzky/as_fsm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252593020,"owners_count":21773388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","finite-state-machine","fsm"],"created_at":"2024-11-13T15:29:23.925Z","updated_at":"2025-05-05T23:31:19.551Z","avatar_url":"https://github.com/bluzky.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Elixir Finite state machine\n\nThis package is inspired by [ecto_fsm](https://github.com/bluzky/ecto_fsm) package\n\nThis package allows to use [finite state machine pattern](https://en.wikipedia.org/wiki/Finite-state_machine) in elixir. \n\n\n\u003e I have rewritten this library to make code simple and easier to use\n**Install**\n\n```elixir\ndef deps do\n  [\n    {:as_fsm, \"~\u003e 2.0.0\"}\n  ]\nend\n```\n\n ## Usage\n\n  **First you to define FSM module**\n  ```elixir\n  defmodule TaskFsm do\n    use AsFsm, repo: MyApp.Repo\n    # by default state is check from column `state` of struct\n    # you can specify your own with\n    # use AsFsm, repo: MyApp.Repo, column: :status\n\n    # define your event\n    defevent(:start, from: :idle, to: :running)\n    defevent(:pause, from: :running, to: :paused)\n    defevent(:stop, from: [:running, :paused], to: :idle)\n\n    # you can define some hook\n    # it is automatically invoked if defined\n\n    def before_start(context) do\n      # do something then return context\n      context\n    end\n\n    def on_start(context) do\n      # do something then return context\n      context\n    end\n  end\n  ```\n\n  All appropriate event function will be generated. In this example we have\n  ```elixir\n  def start(context), do: ....\n  def paus(context), do: ....\n  def stop(context), do: ....\n  ```\n\n  **Then use it**\n  - Trigger an even transition\n  ```elixir\n  my_task\n  |\u003e TaskFsm.new_context(other_params)\n  |\u003e TaskFsm.start()\n  ```\n\n  - Or trigger by name\n  ```elixir\n  my_task\n  |\u003e TaskFsm.new_context(other_params)\n  |\u003e TaskFsm.trigger(:start)\n  ```\n\n## Understand the context\n\n  ```elixir\n  @type :: %Context{\n    struct: struct(),\n    state: any(),\n    valid?: boolean(),\n    error: String.t() | nil,\n    multi: Ecto.Multi.t() | nil\n  }\n  ```\n  - `struct` is your data\n  - `state` any data you want to pass to transition, it could be parameter from client\n  - `valid?` if it is true, then data will be persisted\n  - `error` error message in case `valid?` is false\n  - `multi` is an `Ecto.Multi` you can pass a multi to `new_context()`, it make sure all action you do in a transaction\n\n  ## Event hook\n  For each event you can define 2 hook\n  - `before_hook` you can define this hook to check for some condition before doing transation\n  - `on_hook` this is your hook to do some logic on transaction\n\n  These 2 hooks must return a context. If you want to stop this transition, set `valid?` to false and return the context.\n\n## Custom persist struct\n  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}`\n\n  ```elixr\n  def persist(struct, new_state, _context) do\n    # do your update logic\n    # or write log here\n  end\n  ```\n  \n## Options\n\n- Custom property name by default property name is :state\n```elixir\ndefmodule ExampleFsm do\n\n  use AsFsm,\n    column: :status,\nend\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluzky%2Fas_fsm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbluzky%2Fas_fsm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluzky%2Fas_fsm/lists"}