Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions lib/display.ex
Original file line number Diff line number Diff line change
@@ -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
8 changes: 7 additions & 1 deletion lib/koans.ex
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -19,4 +21,8 @@ defmodule Koans do
import ExUnit.Assertions
end
end

def prefix do
@prefix
end
end
4 changes: 4 additions & 0 deletions lib/meditate.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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

48 changes: 17 additions & 31 deletions lib/runner.ex
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
10 changes: 10 additions & 0 deletions lib/watcher.ex
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule Koans.Mixfile do
end

def application do
[applications: [:logger]]
[applications: [:exfswatch, :logger]]
end

defp deps do
Expand Down