Skip to content

Instantly share code, notes, and snippets.

@peerreynders
Created January 3, 2019 20:53
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/de1f0f0d00f7afe9216a853c489fcc17 to your computer and use it in GitHub Desktop.
Save peerreynders/de1f0f0d00f7afe9216a853c489fcc17 to your computer and use it in GitHub Desktop.
Erlang gen_statem module documentation "handle_event_function" callback mode example "translated" to Elixir
# file: pushbutton.ex
# Translated from: http://erlang.org/doc/man/gen_statem.html#example
# callback mode: :handle_event_function
# i.e. one callback function handle_event/4 for all states
#
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: :handle_event_function
## handle_event/4 callback function
# In :off state -> go to :on state, increment count and reply
# that the resulting status is :on
def handle_event({:call, from}, :push, :off, data),
do: {:next_state, :on, data + 1, {:reply, from, :on}}
# In :on state -> go to :off state and reply
# that the resulting state is :off
def handle_event({:call, from}, :push, :on, data),
do: {:next_state, :off, data, [{:reply, from, :off}]}
## Handle events common to all states
# reply with the current count
def handle_event({:call, from}, :get_count, state, data),
do: {:next_state, state, data, [{:reply, from, data}]}
# Ignore all other events
def handle_event(_, _, state, data),
do: {:next_state, 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