forked from seven1m/30-days-of-elixir
-
Notifications
You must be signed in to change notification settings - Fork 1
/
18-gen_server.exs
108 lines (86 loc) · 2.19 KB
/
18-gen_server.exs
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# I wanted to learn about the GenServer, so:
# 1. first wrote a function to return prime factors of a given number
# 2. then wrapped that in a "server" that handles both sync and async calls
defmodule PrimeFactors do
@moduledoc """
Calculate prime factors of any number given.
"""
@doc """
Given a number, return a list of prime factors.
"""
def prime_factors(number, div \\ 2, factors \\ []) do
cond do
prime?(number) ->
[number | factors]
rem(number, div) == 0 ->
prime_factors(div(number, div), 2, [div | factors])
true ->
prime_factors(number, div + 1, factors)
end
end
@doc """
Given a number, return true if the number is prime.
"""
def prime?(2), do: true
def prime?(number) do
prime?(number, :math.sqrt(number) |> :erlang.trunc)
end
defp prime?(_, 1), do: true
defp prime?(number, div) do
if rem(number, div) == 0 do
false
else
prime?(number, div - 1)
end
end
end
defmodule PrimeFactorsServer do
@moduledoc """
Wrap the PrimeFactors.prime_factors functionality in a server.
"""
use GenServer
import PrimeFactors
def start_link do
:gen_server.start_link({:local, :prime_factors}, __MODULE__, [], [])
end
def init(_args) do
{:ok, []}
end
# synchronous
def handle_call(:flush, _from, context) do
{:reply, context, []}
end
def handle_call(num, _from, context) do
{:reply, prime_factors(num), context}
end
# asynchronous
def handle_cast(num, context) do
{:noreply, [{num, prime_factors(num)} | context]}
end
end
ExUnit.start
defmodule PrimeFactorsTest do
use ExUnit.Case
import PrimeFactors
test "prime_factors" do
assert prime_factors(10) == [5, 2]
assert prime_factors(100) == [5, 5, 2, 2]
end
test "prime?" do
assert(prime?(2))
assert(prime?(11))
assert(not prime?(8))
end
test "async" do
{:ok, pid} = PrimeFactorsServer.start_link
:gen_server.cast(pid, 10)
:gen_server.cast(pid, 100)
:gen_server.cast(pid, 1000)
assert :gen_server.call(pid, :flush) == [
{1000, [5, 5, 5, 2, 2, 2]},
{100, [5, 5, 2, 2]},
{10, [5, 2]}
]
assert :gen_server.call(pid, :flush) == []
end
end