Files
elixir-koans/lib/execute.ex
2018-05-22 21:46:54 +01:00

57 lines
1.4 KiB
Elixir

defmodule Execute do
def run_module(module, callback \\ fn _result, _module, _koan -> nil end) do
Enum.reduce_while(module.all_koans, :passed, fn koan, _ ->
module
|> run_koan(koan)
|> hook(module, koan, callback)
|> continue?
end)
end
defp hook(result, module, koan, callback) do
callback.(result, module, koan)
result
end
defp continue?(:passed), do: {:cont, :passed}
defp continue?(result), do: {:halt, result}
def run_koan(module, name, args \\ []) do
parent = self()
spawn(fn -> exec(module, name, args, parent) end)
listen_for_result(module, name)
end
def listen_for_result(module, name) do
receive do
:ok -> :passed
%{error: _} = failure -> {:failed, failure, module, name}
_ -> listen_for_result(module, name)
end
end
defp exec(module, name, args, parent) do
result = apply(module, name, args)
send(parent, expand(result, module))
Process.exit(self(), :kill)
end
defp expand(:ok, _), do: :ok
defp expand(error, module) do
{file, line} =
System.stacktrace()
|> Enum.drop_while(&(!in_koan?(&1, module)))
|> List.first()
|> extract_file_and_line
%{error: error, file: file, line: line}
end
defp in_koan?({module, _, _, _}, koan), do: module == koan
defp extract_file_and_line({_, _, _, [file: file, line: line]}) do
{file, line}
end
end