Skip to content

Instantly share code, notes, and snippets.

@taiansu
Last active February 11, 2020 06:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taiansu/8ef352250d9d7a3c4dc22ed8ca7688b0 to your computer and use it in GitHub Desktop.
Save taiansu/8ef352250d9d7a3c4dc22ed8ca7688b0 to your computer and use it in GitHub Desktop.
:gen_statem official example in elixir http://erlang.org/doc/design_principles/statem.html
defmodule CodeLock do
@behaviour :gen_statem
@name :code_lock
# Client API
def start_link(code) do
:gen_statem.start_link({:local, @name}, __MODULE__, code, [])
end
def button(button) do
:gen_statem.cast(@name, {:button, button})
end
# Callbacks
def callback_mode, do: :state_functions
def init(code) do
do_lock()
data = %{code: code, length: length(code), buttons: []}
{:ok, :locked, data}
end
def terminate(_reason, state, _data) do
if state != :locked, do: do_lock()
:ok
end
def code_change(_vsn, state, data, _extra), do: {:ok, state, data}
# State functions
def locked(:cast, {:button, button}, %{code: code, length: length, buttons: buttons} = data) do
new_buttons =
if length(buttons) < length do
buttons
else
tl(buttons)
end ++ [button]
if new_buttons == code do
do_unlock()
{:next_state, :open, %{data | buttons: []}, [{:state_timeout, 5000, :lock}]}
else
{:next_state, :locked, %{data | buttons: new_buttons}}
end
end
def locked(:timeout, _, data) do
{:next_state, :locked, %{data | buttons: []}}
end
def open(:state_timeout, :lock, data) do
do_lock()
{:next_state, :locked, data}
end
def open(:cast, {:button, _}, data) do
{:next_state, :open, data}
end
# Display functions
def do_lock, do: IO.puts("Lock")
def do_unlock, do: IO.puts("Unlock")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment