72 lines
1.5 KiB
Elixir
72 lines
1.5 KiB
Elixir
defmodule Tracker do
|
|
alias __MODULE__
|
|
|
|
defstruct total: 0,
|
|
koans: MapSet.new(),
|
|
visited_modules: MapSet.new(),
|
|
on_complete: :noop
|
|
|
|
def start_link do
|
|
Agent.start_link(fn -> %Tracker{} end, name: __MODULE__)
|
|
end
|
|
|
|
def notify_on_complete(pid) do
|
|
Agent.update(__MODULE__, fn state -> %{state | on_complete: pid} end)
|
|
end
|
|
|
|
def set_total(modules) do
|
|
total =
|
|
modules
|
|
|> Enum.flat_map(& &1.all_koans)
|
|
|> Enum.count()
|
|
|
|
Agent.update(__MODULE__, fn _ -> %Tracker{total: total} end)
|
|
end
|
|
|
|
def completed(module, koan) do
|
|
Agent.update(__MODULE__, &mark_koan_completed(&1, module, koan))
|
|
|
|
if complete?() do
|
|
Agent.cast(__MODULE__, fn state ->
|
|
send(state.on_complete, {self(), :complete})
|
|
state
|
|
end)
|
|
end
|
|
end
|
|
|
|
def wait_until_complete() do
|
|
pid = Process.whereis(Tracker)
|
|
|
|
receive do
|
|
{^pid, :complete} -> :ok
|
|
end
|
|
end
|
|
|
|
defp mark_koan_completed(state, module, koan) do
|
|
%{
|
|
state
|
|
| koans: MapSet.put(state.koans, koan),
|
|
visited_modules: MapSet.put(state.visited_modules, module)
|
|
}
|
|
end
|
|
|
|
def visited do
|
|
summarize()[:visited_modules]
|
|
end
|
|
|
|
def complete? do
|
|
%{total: total, current: completed} = summarize()
|
|
total == completed
|
|
end
|
|
|
|
def summarize do
|
|
state = Agent.get(__MODULE__, & &1)
|
|
|
|
%{
|
|
total: state.total,
|
|
current: MapSet.size(state.koans),
|
|
visited_modules: MapSet.to_list(state.visited_modules)
|
|
}
|
|
end
|
|
end
|