-
Notifications
You must be signed in to change notification settings - Fork 1
/
counter.ex
74 lines (56 loc) · 1.79 KB
/
counter.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
defmodule Counter do
use GenServer
@moduledoc """
Basic counter implemented as a GenServer.
See the test in the corresponding directory. You can also play with this
using iex. Note the similarities and differences between this and
rolling your own as in `ProcessFun`.
Using the GenServer module as a Struct (like a map with defined keys) is
a usual pattern. This is probably overkill as there is only one value,
but it's good pattern and GenServers often accrue further state as
functionality evolves.
EXERCISE 1
Implement `decrement/1`. Remove the skip tag from the corresponding
test in the test module.
EXERCISE 2
Implement `increment_after/2`. Remove the skip tag from the corresponding
test in the test module.
"""
@enforce_keys [:value]
defstruct value: nil
@type t :: %Counter{value: integer()}
def start_link(initial_value) do
GenServer.start_link(__MODULE__, initial_value)
end
def init(initial_value) do
## second tuple value is the initial statee of the GenServer
{:ok, %Counter{value: initial_value}}
end
@spec increment(pid()) :: :ok
def increment(pid) do
# cast is asynchronous
GenServer.cast(pid, :increment)
end
@spec decrement(pid()) :: :ok
def decrement(_pid) do
## IMPLEMENT ME
:ok
end
@spec increment_after(pid, non_neg_integer()) :: :ok
def increment_after(_pid, milliseconds) when milliseconds >= 0 do
## IMPLEMENT ME
# hint Process.send_after/2
:ok
end
@spec value(pid()) :: integer()
def value(pid) do
# Call is synchronous
GenServer.call(pid, :query_value)
end
def handle_call(:query_value, _from, state = %{value: value}) do
{:reply, value, state}
end
def handle_cast(:increment, state = %{value: value}) do
{:noreply, %{state | value: value + 1}}
end
end