44
lib/display.ex
Normal file
44
lib/display.ex
Normal file
@@ -0,0 +1,44 @@
|
||||
defmodule Display do
|
||||
alias IO.ANSI
|
||||
@current_dir File.cwd!
|
||||
|
||||
def show_failure(%{expr: expr}, module, name) do
|
||||
IO.puts("")
|
||||
IO.puts("Now meditate upon #{display_module(module)}")
|
||||
IO.puts("---------------------------------------")
|
||||
IO.puts("Assertion failed in #{source_file(module)}:#{line_number(expr)}")
|
||||
IO.puts(display_koan(name))
|
||||
IO.puts(format_red(Macro.to_string(expr)))
|
||||
end
|
||||
|
||||
def considering(module) do
|
||||
IO.puts("Considering #{display_module(module)}...")
|
||||
end
|
||||
|
||||
def before_run do
|
||||
IO.puts("")
|
||||
IO.puts("")
|
||||
end
|
||||
|
||||
defp line_number({_, [line: line], _}) do
|
||||
line
|
||||
end
|
||||
|
||||
defp source_file(module) do
|
||||
module.__info__(:compile)
|
||||
|> Dict.get(:source)
|
||||
|> Path.relative_to(@current_dir)
|
||||
end
|
||||
|
||||
defp format_red(str) do
|
||||
Enum.join([ANSI.red, str, ANSI.reset], "")
|
||||
end
|
||||
|
||||
defp display_module(module) do
|
||||
Module.split(module) |> List.last
|
||||
end
|
||||
|
||||
defp display_koan(name) do
|
||||
String.replace(to_string(name), Koans.prefix, "")
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,8 @@
|
||||
defmodule Koans do
|
||||
@prefix "koan: "
|
||||
|
||||
defmacro koan(name, body) do
|
||||
compiled_name = :"koan: #{name}"
|
||||
compiled_name = :"#{prefix}#{name}"
|
||||
quote do
|
||||
def unquote(compiled_name)() do
|
||||
try do
|
||||
@@ -19,4 +21,8 @@ defmodule Koans do
|
||||
import ExUnit.Assertions
|
||||
end
|
||||
end
|
||||
|
||||
def prefix do
|
||||
@prefix
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,11 @@ defmodule Mix.Tasks.Meditate do
|
||||
use Mix.Task
|
||||
|
||||
def run(_) do
|
||||
Application.ensure_all_started(:elixir_koans)
|
||||
Code.compiler_options(ignore_module_conflict: true)
|
||||
Watcher.start
|
||||
Runner.run
|
||||
:timer.sleep(:infinity)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,31 +1,32 @@
|
||||
defmodule Runner do
|
||||
alias IO.ANSI
|
||||
|
||||
@modules [
|
||||
Equalities,
|
||||
Lists
|
||||
]
|
||||
|
||||
def run do
|
||||
IO.puts("")
|
||||
Enum.take_while(@modules, fn(mod) ->
|
||||
run(Equalities)
|
||||
end
|
||||
|
||||
def run(start_module) do
|
||||
Display.before_run
|
||||
|
||||
start_idx = Enum.find_index(@modules, &(&1 == start_module))
|
||||
Enum.drop(@modules, start_idx)
|
||||
|> Enum.take_while(fn(mod) ->
|
||||
run_module(mod) == :passed
|
||||
end)
|
||||
end
|
||||
|
||||
def run_module(module) do
|
||||
IO.puts("Considering #{display_module(module)}...")
|
||||
Display.considering(module)
|
||||
|
||||
functions = module.__info__(:functions)
|
||||
|
||||
koans = Enum.map(functions, fn({name, _arity}) -> name end)
|
||||
|> Enum.filter(&koan?/1)
|
||||
koans = extract_koans_from(module)
|
||||
|
||||
passed = Enum.take_while(koans, fn(name) ->
|
||||
run_koan(module, name) == :passed
|
||||
end)
|
||||
|
||||
|
||||
if Enum.count(koans) == Enum.count(passed) do
|
||||
:passed
|
||||
else
|
||||
@@ -37,33 +38,18 @@ defmodule Runner do
|
||||
case apply(module, name, []) do
|
||||
:ok -> :passed
|
||||
error ->
|
||||
show_failure(error, module, name)
|
||||
Display.show_failure(error, module, name)
|
||||
:failed
|
||||
end
|
||||
end
|
||||
|
||||
def show_failure(%{expr: expr}, module, name) do
|
||||
IO.puts("")
|
||||
IO.puts("Now meditate upon #{display_module(module)}")
|
||||
IO.puts("---------------------------------------")
|
||||
IO.puts("Assertion failed!")
|
||||
IO.puts(display_koan(name))
|
||||
IO.puts(format_red(Macro.to_string(expr)))
|
||||
end
|
||||
|
||||
def format_red(str) do
|
||||
Enum.join([ANSI.red, str, ANSI.reset], "")
|
||||
defp extract_koans_from(module) do
|
||||
module.__info__(:functions)
|
||||
|> Enum.map(fn({name, _arity}) -> name end)
|
||||
|> Enum.filter(&koan?/1)
|
||||
end
|
||||
|
||||
defp koan?(fun_name) do
|
||||
String.starts_with?(to_string(fun_name), "koan: ")
|
||||
end
|
||||
|
||||
defp display_module(module) do
|
||||
Module.split(module) |> List.last
|
||||
end
|
||||
|
||||
defp display_koan(name) do
|
||||
String.replace(to_string(name), "koan: ", "")
|
||||
String.starts_with?(to_string(fun_name), Koans.prefix)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
defmodule Watcher do
|
||||
use ExFSWatch, dirs: ["lib/koans"]
|
||||
|
||||
def callback(file, events) do
|
||||
if Enum.member?(events, :modified) do
|
||||
[{mod, _}] = Code.load_file(file)
|
||||
Runner.run(mod)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user