Files
elixir-koans/lib/execute.ex
Jay Hayes c6f2738fc7 Refactor error expansion to locate errors in koan module
The previous strategy wasn't robust enough to detect typos in function
calls. For example, if you misremembered String.duplicate/2 as
String.repeat/2 the koan runner would hang and have to be restarted.
This is because the stacktrace for an error like that doesn't have line
numbers. To avoid the problem, we detect the first pieces of the
stracktrace that is in the koan module. I can't decide if that's a
perfect solution, but it seemed to work in my testing. Hoping to get
other's feedback.
2016-06-11 08:43:37 -05:00

55 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