Extracted watcher and runner into supervision tree.

This commit is contained in:
Nathan Walker
2017-04-26 21:38:22 -05:00
parent 3c73ea00fa
commit 372d7f70ac
6 changed files with 78 additions and 55 deletions

View File

@@ -16,34 +16,6 @@ defmodule Display do
{:noreply, %{state | clear_screen: false}}
end
def handle_cast({:invalid, koan, modules}, state) do
Notifications.invalid_koan(koan, modules)
|> IO.puts
{:noreply, state}
end
def handle_cast({:show_failure, failure, module, name}, state) do
format(failure, module, name)
|> IO.puts
{:noreply, state}
end
def handle_cast({:show_compile_error, error}, state) do
Failure.show_compile_error(error)
|> IO.puts
{:noreply, state}
end
def handle_cast(:congratulate, state) do
Notifications.congratulate
|> IO.puts
{:noreply, state}
end
def handle_cast(:clear_screen, state = %{clear_screen: true}) do
IO.puts(ANSI.clear)
IO.puts(ANSI.home)
@@ -55,19 +27,23 @@ defmodule Display do
end
def invalid_koan(koan, modules) do
GenServer.cast(__MODULE__, {:invalid, koan, modules})
Notifications.invalid_koan(koan, modules)
|> IO.puts
end
def show_failure(failure, module, name) do
GenServer.cast(__MODULE__, {:show_failure, failure, module, name})
format(failure, module, name)
|> IO.puts
end
def show_compile_error(error) do
GenServer.cast(__MODULE__, {:show_compile_error, error})
Failure.show_compile_error(error)
|> IO.puts
end
def congratulate do
GenServer.cast(__MODULE__, :congratulate)
Notifications.congratulate
|> IO.puts
end
def clear_screen do

View File

@@ -7,7 +7,9 @@ defmodule ElixirKoans do
children = [
worker(Display, []),
worker(Tracker, [])
worker(Tracker, []),
worker(Runner, []),
worker(Watcher, [])
]
opts = [strategy: :one_for_one, name: ElixirKoans.Supervisor]

View File

@@ -7,8 +7,6 @@ defmodule Mix.Tasks.Meditate do
def run(args) do
Application.ensure_all_started(:elixir_koans)
Code.compiler_options(ignore_module_conflict: true)
{:ok, watcher} = Watcher.start
Process.monitor(watcher)
Options.start(args)
@@ -22,17 +20,12 @@ defmodule Mix.Tasks.Meditate do
|> Runner.modules_to_run
Tracker.set_total(modules)
Tracker.notify_on_complete(self())
Runner.run(modules)
if Tracker.complete? do
Display.congratulate
exit(:normal)
end
receive do
{:DOWN, _references, :process, ^watcher, _reason} -> nil
end
Tracker.wait_until_complete()
Display.congratulate()
end
defp ok?(koan) do

View File

@@ -1,4 +1,5 @@
defmodule Runner do
use GenServer
def koan?(koan) do
Keyword.has_key?(koan.__info__(:exports), :all_koans)
@@ -27,14 +28,38 @@ defmodule Runner do
def modules_to_run, do: Options.initial_koan |> modules_to_run
def modules_to_run(start_module), do: Enum.drop_while(modules(), &(&1 != start_module))
def run(modules) do
Display.clear_screen()
modules
|> Enum.take_while( &(run_module(&1) == :passed))
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def run_module(module) do
def handle_cast({:run, modules}, _) do
flush()
send(self(), :run_modules)
{:noreply, modules}
end
def handle_info(:run_modules, []) do
{:noreply, []}
end
def handle_info(:run_modules, [module | rest]) do
Display.clear_screen()
case run_module(module) do
:passed ->
send(self(), :run_modules)
{:noreply, rest}
_ ->
{:noreply, []}
end
end
def run(modules) do
GenServer.cast(__MODULE__, {:run, modules})
end
defp run_module(module) do
module
|> Execute.run_module(&track/3)
|> display
@@ -48,4 +73,12 @@ defmodule Runner do
:failed
end
defp display(_), do: :passed
defp flush do
receive do
_ -> flush()
after
0 -> :ok
end
end
end

View File

@@ -1,12 +1,19 @@
defmodule Tracker do
alias __MODULE__
defstruct total: 0, koans: MapSet.new(), visited_modules: MapSet.new()
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))
@@ -17,6 +24,19 @@ defmodule Tracker do
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

View File

@@ -1,14 +1,13 @@
defmodule Watcher do
use ExFSWatch, dirs: ["lib/koans"]
def start_link do
start()
end
def callback(file, events) do
if Enum.member?(events, :modified) do
file |> normalize |> reload
if Tracker.complete? do
Display.congratulate
exit(:normal)
end
end
end