Packages
fnord
0.8.27
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/task_server.ex
defmodule TaskServer do
defstruct [
:next_id,
:lists
]
@type task :: %{
id: non_neg_integer | binary,
outcome: :todo | :done | :failed,
data: any,
result: any
}
@type t :: %__MODULE__{
next_id: non_neg_integer,
lists: %{
non_neg_integer => list(task)
}
}
use GenServer
# ----------------------------------------------------------------------------
# Client API
# ----------------------------------------------------------------------------
@spec start_link(any) :: GenServer.on_start()
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
@spec start_list() :: non_neg_integer
def start_list() do
GenServer.call(__MODULE__, :start_list)
end
@spec get_list(non_neg_integer) :: list(task) | {:error, :not_found}
def get_list(list_id) do
GenServer.call(__MODULE__, {:get_list, list_id})
end
@spec add_task(non_neg_integer, binary, any) :: :ok
def add_task(list_id, task_id, task_data) do
GenServer.cast(__MODULE__, {:add_task, list_id, task_id, task_data})
end
@spec complete_task(non_neg_integer, binary, any) :: :ok
def complete_task(list_id, task_id, result) do
GenServer.cast(__MODULE__, {:complete_task, list_id, task_id, :done, result})
end
@spec fail_task(non_neg_integer, binary, any) :: :ok
def fail_task(list_id, task_id, msg) do
GenServer.cast(__MODULE__, {:complete_task, list_id, task_id, :failed, msg})
end
@spec as_string(non_neg_integer | list(task), boolean) :: binary
def as_string(subject, detail? \\ false)
def as_string(list_id, detail?) when is_integer(list_id) do
list_id
|> get_list()
|> case do
{:error, :not_found} -> "List #{list_id} not found"
tasks -> as_string(tasks, detail?)
end
end
def as_string([], _), do: ""
def as_string([task | tasks], detail?) do
as_string(task, detail?) <> "\n" <> as_string(tasks, detail?)
end
def as_string(%{id: id, outcome: :todo}, _), do: "- [ ] #{id}"
def as_string(%{id: id, outcome: :done}, false), do: "- [✓] #{id}"
def as_string(%{id: id, outcome: :failed}, false), do: "- [✗] #{id}"
def as_string(%{id: id, outcome: :done, result: result}, true) do
"- [✓] #{id}: #{result}"
end
def as_string(%{id: id, outcome: :failed, result: result}, true) do
"- [✗] #{id}: #{result}"
end
# ----------------------------------------------------------------------------
# Server Callbacks
# ----------------------------------------------------------------------------
def init(_) do
{:ok, %__MODULE__{next_id: 1, lists: %{}}}
end
def handle_call(:start_list, _from, %{lists: lists, next_id: next_id} = state) do
{:reply, next_id,
%{
state
| lists: Map.put(lists, next_id, []),
next_id: next_id + 1
}}
end
def handle_call({:get_list, list_id}, _from, state) do
state.lists
|> Map.get(list_id)
|> case do
nil ->
{:reply, {:error, :not_found}, state}
tasks ->
tasks
|> Enum.reverse()
|> then(&{:reply, &1, state})
end
end
def handle_cast({:add_task, list_id, task_id, task_data}, state) do
# does not create lists on demand: ignore invalid list IDs
case Map.fetch(state.lists, list_id) do
:error ->
{:noreply, state}
{:ok, tasks} ->
task = %{
id: task_id,
data: task_data,
outcome: :todo,
result: nil
}
new_list = [task | tasks]
{:noreply, %{state | lists: Map.put(state.lists, list_id, new_list)}}
end
end
def handle_cast({:complete_task, list_id, task_id, outcome, result}, state) do
state
|> Map.get(:lists, %{})
|> Map.fetch(list_id)
|> case do
:error ->
{:noreply, state}
{:ok, tasks} ->
tasks
|> Enum.map(fn
%{id: ^task_id} = task -> %{task | outcome: outcome, result: result}
task -> task
end)
|> then(&{:noreply, %{state | lists: Map.put(state.lists, list_id, &1)}})
end
end
end