Hello! Going through Sasa Juric’s Elixir in Action. In 6.2.8 we’re implementing a GenServer. Please ignore the two modules in one
defmodule TodoServer do
use GenServer
def start do
GenServer.start(TodoServer, nil)
end
def add_entry(todo_server, new_entry) do
GenServer.cast(todo_server, {:add_entry, new_entry})
end
def entries(todo_server, date) do
GenServer.call(todo_server, {:entries, date})
end
@impl GenServer
def init(_) do
{:ok, TodoList.new()}
end
@impl GenServer
def handle_cast({:add_entry, new_entry}, todo_list) do
new_state = TodoList.add_entry(todo_list, new_entry)
{:noreply, new_state}
end
@impl GenServer
def handle_call({:entries, date}, _, todo_list) do
{
:reply,
TodoList.entries(todo_list, date),
todo_list
}
end
end
defmodule TodoList do
defstruct auto_id: 1, entries: %{}
def new(entries \\ []) do
Enum.reduce(
entries,
%TodoList{},
&add_entry(&2, &1)
)
end
def add_entry(todo_list, entry) do
entry = Map.put(entry, :id, todo_list.auto_id)
new_entries = Map.put(todo_list.entries, todo_list.auto_id, entry)
%TodoList{todo_list | entries: new_entries, auto_id: todo_list.auto_id + 1}
end
def entries(todo_list, date) do
todo_list.entries
|> Stream.filter(fn {_, entry} -> entry.date == date end)
|> Enum.map(fn {_, entry} -> entry end)
end
def update_entry(todo_list, %{} = new_entry) do
update_entry(todo_list, new_entry.id, fn _ -> new_entry end)
end
def update_entry(todo_list, entry_id, updater_fun) do
case Map.fetch(todo_list.entries, entry_id) do
:error ->
todo_list
{:ok, old_entry} ->
new_entry = updater_fun.(old_entry)
new_entries = Map.put(todo_list.entries, new_entry.id, new_entry)
%TodoList{todo_list | entries: new_entries}
end
end
def delete_entry(todo_list, entry_id) do
%TodoList{todo_list | entries: Map.delete(todo_list.entries, entry_id)}
end
end
In iex, I’ll try-
iex(1)> todo_server = TodoServer.start()
{:ok, #PID<0.116.0>}
iex(2)> TodoServer.add_entry(todo_server, %{date: ~D[2018-12-20], title: "Shopping"})
To then receive a match error-
** (FunctionClauseError) no function clause matching in GenServer.cast/2
The following arguments were given to GenServer.cast/2:
# 1
{:ok, #PID<0.116.0>}
# 2
{:add_entry, %{date: ~D[2018-12-20], title: "Shopping"}}
Attempted function clauses (showing 4 out of 4):
def cast({:global, name}, request)
def cast({:via, mod, name}, request)
def cast({name, node}, request) when is_atom(name) and is_atom(node)
def cast(dest, request) when is_atom(dest) or is_pid(dest)
(elixir 1.12.0) lib/gen_server.ex:1045: GenServer.cast/2
I understand I’m not giving correct function clause parameters to match with GenServer.cast/2
, just can’t quite tell from the context or the docs what I should be feeding it!
Thanks for any help