Extracted watcher and runner into supervision tree.
This commit is contained in:
@@ -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
|
||||
|
@@ -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]
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user