Created
December 1, 2016 02:22
Star
You must be signed in to star a gist
TodoList implementation
This file contains 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 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