Last active
March 29, 2018 03:38
-
-
Save fimars/4e47fe741ba974dc2918d1a200081b79 to your computer and use it in GitHub Desktop.
Elixir Meta PG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Further Exploration | |
# | |
# We journeyed from simple control flow transformations all the way through a mini testing framework. Along the way, | |
# you learned all the tools necessary to define your own macros and perform AST transformations in a responsible way. | |
# Next, we’ll discover a few advanced compile-time code-generation tech- niques to create highly performant and | |
# maintainable programs. | |
# | |
# On your own, explore ways you can enhance your Assertion test framework and define new macro constructs. Here are a few | |
# basic experiments to get you started: | |
# • Implement assert for every operator in Elixir. | |
# • Add Boolean assertions, such as assert true. | |
# • Implement a refute macro for refutations. | |
# And some that are more advanced: | |
# • Run test cases in parallel within Assertion.Test.run/2 via spawned processes. | |
# • Add reports for the module. Include pass/fail counts and execution time. | |
defmodule Assertion do | |
defmacro __using__(_options \\ []) do | |
quote do | |
import unquote(__MODULE__) | |
Module.register_attribute __MODULE__, :tests, accumulate: true | |
@before_compile unquote(__MODULE__) | |
end | |
end | |
defmacro __before_compile__(_env) do | |
quote do | |
def run, do: Assertion.Test.run(@tests, __MODULE__) | |
end | |
end | |
defmacro test(description, do: test_block) do | |
test_func = String.to_atom(description) | |
quote do | |
@tests {unquote(test_func), unquote(description)} | |
def unquote(test_func)(), do: unquote(test_block) | |
end | |
end | |
defmacro assert({operator, _, [lhs, rhs]}) do | |
quote bind_quoted: [operator: operator, lhs: lhs, rhs: rhs] do | |
Assertion.Test.assert(operator, lhs, rhs) | |
end | |
end | |
defmacro assert(bool) do | |
quote do | |
Assertion.Test.assert(unquote(bool)) | |
end | |
end | |
end | |
defmodule Assertion.Test do | |
def run(tests, module) do | |
Enum.each tests, fn {test_func, description} -> | |
case apply(module, test_func, []) do | |
:ok -> IO.write "." | |
{:fail, reason} -> IO.puts """ | |
===================================================== | |
FAILURE: #{description} | |
===================================================== | |
#{reason} | |
""" | |
end | |
end | |
end | |
def assert(true) do | |
:ok | |
end | |
def assert(false) do | |
{:fail, """ | |
Expected: true | |
Get: false | |
""" | |
} | |
end | |
def assert(:==, lhs, rhs) when lhs == rhs do | |
:ok | |
end | |
def assert(:==, lhs, rhs) do | |
{:fail, """ | |
Expected: #{lhs} | |
to be equal to: #{rhs} | |
""" | |
} | |
end | |
def assert(:>, lhs, rhs) when lhs > rhs do | |
:ok | |
end | |
def assert(:>, lhs, rhs) do | |
{:fail, """ | |
Expected: #{lhs} | |
to be greater than: #{rhs} | |
""" | |
} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment