Skip to content

Instantly share code, notes, and snippets.

@JulianLeviston
Created December 1, 2016 02:22
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save JulianLeviston/4b6c5d07a95ec3ecb84619c95e8d2ef5 to your computer and use it in GitHub Desktop.
TodoList implementation
defmodule TodoServer do
def start do
spawn(fn -> loop(TodoList.new) end)
end
def add_entry(todo_server, new_entry) do
send(todo_server, {:add_entry, new_entry})
end
def entries(todo_server, date) do
send(todo_server, {:entries, self, date})
receive do
{:todo_entries, entries} ->
entries
after 5000 ->
{:error, :timeout}
end
end
def update_entry(todo_server, id, updater_fun) do
send(todo_server, {:update_entry, id, updater_fun})
end
def update_entry(todo_server, %{id: _} = updated_entry) do
send(todo_server, {:update_entry, updated_entry})
end
def delete_entry(todo_server, id) do
send(todo_server, {:delete_entry, id})
end
defp process_message(todo_list, {:add_entry, new_entry}) do
TodoList.add_entry(todo_list, new_entry)
end
defp process_message(todo_list, {:entries, caller, date}) do
send(caller, {:todo_entries, TodoList.entries(todo_list, date)})
todo_list
end
defp process_message(todo_list, {:update_entry, id, updater_fun}) do
TodoList.update_entry(todo_list, id, updater_fun)
end
defp process_message(todo_list, {:update_entry, updated_entry}) do
TodoList.update_entry(todo_list, updated_entry)
end
defp process_message(todo_list, {:delete_entry, id}) do
TodoList.delete_entry(todo_list, id)
end
defp loop(todo_list) do
new_todo_list = receive do
message ->
process_message(todo_list, message)
end
loop(new_todo_list)
end
end
defmodule TodoList do
defstruct [auto_id: 1, entries: Map.new]
def new(entries \\ []) do
entries |>
Enum.reduce(
%TodoList{},
fn(entry, todo_list) ->
add_entry(todo_list, entry)
end
)
end
def add_entry(
%TodoList{entries: entries, auto_id: auto_id} = todo_list,
entry
) do
entry = Map.put(entry, :id, auto_id)
new_entries = entries |> Map.put(auto_id, entry)
%TodoList{todo_list |
entries: new_entries,
auto_id: auto_id + 1
}
end
def entries(%TodoList{entries: entries}, date) do
entries
|> Stream.filter(fn({_, entry}) ->
entry.date == date
end)
|> Enum.map(fn({_, entry}) ->
entry
end)
end
def update_entry(todo_list, %{id: id} = new_entry) do
todo_list
|> update_entry(id, fn(_) -> new_entry end)
end
def update_entry(
%TodoList{entries: entries} = todo_list,
entry_id,
updater_fun
) do
case entries[entry_id] do
nil ->
todo_list
old_entry ->
id = old_entry.id
new_entry = %{id: ^id} = updater_fun.(old_entry)
new_entries = Map.put(entries, new_entry.id, new_entry)
%TodoList{todo_list | entries: new_entries}
end
end
def delete_entry(
%TodoList{entries: entries} = todo_list,
entry_id
) do
new_entries = Enum.filter(entries, fn({id, _}) -> id != entry_id end)
%TodoList{todo_list | entries: new_entries}
end
# dev helper for grabbing some quick data when we reload the module for testing
def test_entries() do
new
|> add_entry(%{date: {2013, 12, 19}, title: "Dentist"})
|> add_entry(%{date: {2013, 12, 20}, title: "Greengrocer"})
|> add_entry(%{date: {2013, 12, 21}, title: "Doctor"})
|> add_entry(%{date: {2013, 12, 21}, title: "Candlestick Maker"})
end
end
defmodule TodoList.CsvImporter do
def import(filename) do
case File.read(filename) do
{:ok, content} ->
content |> to_todo_list
{:error, message} ->
IO.puts("Error!: #{message}")
end
end
def to_todo_list(content) do
content
|> to_lines
|> Stream.map(&line_to_date_and_title/1)
|> Stream.reject(&is_not_valid_data/1)
|> Stream.map(&date_and_title_to_todo_map/1)
|> TodoList.new
end
def to_lines(content) do
content
|> String.split("\n")
end
def line_to_date_and_title(line) do
line
|> String.split(",")
end
def date_and_title_to_todo_map([string_date, title]) do
date = date_tuple_from_string(string_date)
%{date: date, title: title}
end
def date_tuple_from_string(string_date) do
[year, month, day] =
String.split(string_date, "/")
|> Stream.map(&Integer.parse/1)
|> Enum.map(fn({parsed, _}) -> parsed end)
{year, month, day}
end
def is_valid_data([_, _]), do: true
def is_valid_data(_), do: false
def is_not_valid_data(args), do: !is_valid_data(args)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment