Skip to content

Instantly share code, notes, and snippets.

@peerreynders
Created January 3, 2019 20:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save peerreynders/926b05c04511193b1544e565faa292c7 to your computer and use it in GitHub Desktop.
Save peerreynders/926b05c04511193b1544e565faa292c7 to your computer and use it in GitHub Desktop.
Erlang gen_statem module documentation "state_functions" callback mode example "translated" to Elixir
# file: pushbutton.ex
# Translated from: http://erlang.org/doc/man/gen_statem.html#example
# callback mode: :state_functions
# i.e. one callback function per state, so the each possible
# state has to be represented as a bare atom which directly
# identifies the module function to be called (:gen_fsm like).
#
# This example has two states :on and :off.
# Therefore there is an on/3 and an off/3 callback function.
#
defmodule Pushbutton do
@behaviour :gen_statem
# The registered server name
defp name(),
do: :pushbutton_statem
## API. This example uses a registered name name()
## and does not link to the caller.
def start(),
do: :gen_statem.start({:local, name()}, __MODULE__, [], [])
def push(),
do: :gen_statem.call(name(), :push)
def get_count(),
do: :gen_statem.call(name(), :get_count)
def stop(),
do: :gen_statem.stop(name())
## Mandatory callback functions
# return value is ignored
def terminate(_reason, _state, _data),
do: nil
def code_change(_vsn, state, data, _extra),
do: {:ok, state, data}
# returns {:ok, state, data}
def init([]),
do: {:ok, :off, 0}
def callback_mode(),
do: :state_functions
## state callback(s)
# In :off state -> go to :on state, increment count and reply
# that the resulting status is :on
def off({:call, from}, :push, data),
do: {:next_state, :on, data + 1, {:reply, from, :on}}
def off(event_type, event_content, data),
do: handle_event(event_type, event_content, data)
# In :on state -> go to :off state and reply
# that the resulting state is :off
def on({:call, from}, :push, data),
do: {:next_state, :off, data, [{:reply, from, :off}]}
def on(event_type, event_content, data),
do: handle_event(event_type, event_content, data)
## Handle events common to all states
# reply with the current count
def handle_event({:call, from}, :get_count, data),
do: {:keep_state, data, [{:reply, from, data}]}
# Ignore all other events
def handle_event(_, _, data),
do: {:keep_state, data}
end
$ iex
Erlang/OTP 21 [erts-10.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> c("pushbutton.ex")
[Pushbutton]
iex(2)> Pushbutton.start()
{:ok, #PID<0.109.0>}
iex(3)> Pushbutton.get_count()
0
iex(4)> Pushbutton.push()     
:on
iex(5)> Pushbutton.get_count()
1
iex(6)> Pushbutton.push()     
:off
iex(7)> Pushbutton.get_count()
1
iex(8)> Pushbutton.stop()     
:ok
iex(9)> Pushbutton.push()     
** (exit) exited in: :gen_statem.call(:pushbutton_statem, :push, :infinity) 
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
    (stdlib) gen.erl:228: :gen.do_for_proc/2
    (stdlib) gen_statem.erl:598: :gen_statem.call_dirty/4
iex(9)> 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment