I’ve ported the example to Elixir. It seems to work fine
defmodule CodeLock do
use GenFSM
def start_link(code) do
GenFSM.start_link(__MODULE__, Enum.reverse(code))
end
def button(pid, digit) do
IO.puts "beeep!"
GenFSM.send_event(pid, {:button, digit})
end
def init(code) do
{:ok, :locked, {[], code}}
end
def locked({:button, digit}, {so_far, code}) do
IO.inspect {:state, so_far, code}
case [digit | so_far] do
^code ->
# do_unlock(...)
IO.puts "unlocked!"
{:next_state, :open, {[], code}, 1000}
incomplete when length(incomplete) < length(code) ->
IO.puts "awaiting more digits"
{:next_state, :locked, {incomplete, code}}
_wrong ->
IO.puts "wrong!"
{:next_state, :locked, {[], code}}
end
end
def open(:timeout, state) do
# do_lock(...)
IO.puts "SLAM! locked!"
{:next_state, :locked, state}
end
end
defmodule CodeLockTest do
use ExUnit.Case
test "punch in those numbers and await the timeout" do
{:ok, pid} = CodeLock.start_link([1,2,3,4])
CodeLock.button(pid, 1)
CodeLock.button(pid, 2)
CodeLock.button(pid, 3)
CodeLock.button(pid, 4)
# we should be open by now
# wait for the timer...
:timer.sleep 1100
end
end
The output should look like this
beeep!
beeep!
beeep!
beeep!
{:state, [], [4, 3, 2, 1]}
awaiting more digits
{:state, [1], [4, 3, 2, 1]}
awaiting more digits
{:state, [2, 1], [4, 3, 2, 1]}
awaiting more digits
{:state, [3, 2, 1], [4, 3, 2, 1]}
unlocked!
* * * wait some time * * *
SLAM! locked!