Created
September 18, 2017 07:33
-
-
Save schmalz/85d198727191b677944c3b0d63f8b3b8 to your computer and use it in GitHub Desktop.
Designing for Scalability with Erlang/OTP - Ch 6 - Coffee FSM - Elixir/OTP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Coffee do | |
use GenStateMachine, callback_mode: :state_functions | |
# Client API | |
def start_link() do | |
GenStateMachine.start_link(__MODULE__, {}, [name: __MODULE__]) | |
end | |
def stop() do | |
GenStateMachine.stop(__MODULE__) | |
end | |
def tea() do | |
GenStateMachine.cast(__MODULE__, {:selection, :tea, 100}) | |
end | |
def espresso() do | |
GenStateMachine.cast(__MODULE__, {:selection, :espresso, 100}) | |
end | |
def americano() do | |
GenStateMachine.cast(__MODULE__, {:selection, :americano, 150}) | |
end | |
def cappuccino() do | |
GenStateMachine.cast(__MODULE__, {:selection, :cappuccino, 150}) | |
end | |
def pay(amount) do | |
GenStateMachine.cast(__MODULE__, {:pay, amount}) | |
end | |
def cancel() do | |
GenStateMachine.cast(__MODULE__, :cancel) | |
end | |
def cup_removed() do | |
GenStateMachine.cast(__MODULE__, :cup_removed) | |
end | |
# Server Callbacks | |
def init(_) do | |
HW.reboot() | |
HW.display("make your selection") | |
{:ok, :selection, {}} | |
end | |
def selection(:cast, {:selection, brew, price}, _data) do | |
HW.display("please pay ~w", price) | |
{:next_state, :payment, {brew, price, 0}} | |
end | |
def selection(:cast, {:pay, amount}, data) do | |
HW.return_change(amount) | |
{:next_state, :selection, data} | |
end | |
def selection(:cast, _other, data) do | |
{:next_state, :selection, data} | |
end | |
def payment(:cast, {:pay, amount}, {brew, price, paid}) | |
when amount + paid < price do | |
new_paid = amount + paid | |
HW.display("please pay ~w", price - new_paid) | |
{:next_state, :payment, {brew, price, new_paid}} | |
end | |
def payment(:cast, {:pay, amount}, {brew, price, paid}) | |
when amount + paid >= price do | |
new_paid = amount + paid | |
HW.display("preparing ~w", brew) | |
if new_paid > price do | |
HW.return_change(new_paid - price) | |
end | |
HW.drop_cup() | |
HW.prepare(brew) | |
HW.display("remove ~w", brew) | |
{:next_state, :remove, {}} | |
end | |
def payment(:cast, :cancel, {_brew, _price, paid}) do | |
if paid > 0 do | |
HW.return_change(paid) | |
end | |
HW.display("make your selection") | |
{:next_state, :selection, {}} | |
end | |
def payment(:cast, _other, data) do | |
{:next_state, :payment, data} | |
end | |
def remove(:cast, :cup_removed, _data) do | |
HW.display("make your selection") | |
{:next_state, :selection, {}} | |
end | |
def remove(:cast, {:pay, amount}, _data) do | |
HW.return_change(amount) | |
{:next_state, :remove, {}} | |
end | |
def remove(:cast, _other, _data) do | |
{:next_state, :remove, {}} | |
end | |
def terminate(_reason, _state, {_brew, _price, paid}) when paid > 0 do | |
HW.return_change(paid) | |
:ok | |
end | |
def terminate(_reason, _state, {}) do | |
:ok | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule HW do | |
def display(format) do | |
IO.puts("display: " <> format) | |
end | |
def display(format, arg) do | |
:io.format("display: " <> format <> "~n", [arg]) | |
end | |
def return_change(amount) do | |
IO.puts("machine: return #{amount} in change") | |
end | |
def drop_cup() do | |
IO.puts("machine: drop cup") | |
end | |
def prepare(brew) do | |
IO.puts("machine: prepare #{brew}") | |
end | |
def reboot() do | |
IO.puts("machine: reboot hardware") | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This implementation uses the
gen_statem
wrapper GenStateMachine. This rtequired the following to be added to themix.exs
file.