Last active
December 1, 2015 03:09
-
-
Save guilleiguaran/e757425ea8777d9c6384 to your computer and use it in GitHub Desktop.
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
defmodule Contracts do | |
defmacro __using__(_opts) do | |
quote do | |
Module.register_attribute(__MODULE__, :requires, accumulate: true) | |
Module.register_attribute(__MODULE__, :ensures, accumulate: true) | |
@contracts %{} | |
import Kernel, except: [def: 2] | |
import Contracts, only: [def: 2] | |
end | |
end | |
defmacro def(definition, do: content) do | |
function_name = case definition do | |
{:when, _, [{name, _, _params} | _guards] } -> name | |
{name, _, _} -> name | |
end | |
contracts = Module.get_attribute(__CALLER__.module, :contracts) | |
precondition = contracts[function_name][:requires] | |
IO.inspect precondition | |
quote do | |
Contracts.__on_definition__(__ENV__, unquote(function_name)) | |
#contracts = Module.get_attribute(__ENV__.module, :contracts) | |
#precondition = contracts[unquote(function_name)][:requires] | |
#IO.inspect unquote(quote do: precondition) | |
Kernel.def(unquote(definition)) do | |
unless unquote(precondition), do: raise "Contract not met: blame the client" | |
var!(result) = unquote(content) | |
var!(result) | |
end | |
end # |> Macro.to_string |> IO.puts | |
end | |
def __on_definition__(env, function) do | |
mod = env.module | |
requires = Module.get_attribute(mod, :requires) |> List.first |> Code.string_to_quoted! | |
ensures = Module.get_attribute(mod, :ensures) |> List.first |> Code.string_to_quoted! | |
contract = %{requires: requires, ensures: ensures} | |
contracts = Module.get_attribute(mod, :contracts) | |
unless Map.has_key?(contracts, function) do | |
Module.put_attribute(mod, :contracts, Map.put(contracts, function, contract)) | |
end | |
Module.delete_attribute(mod, :requires) | |
Module.delete_attribute(mod, :ensures) | |
end | |
end |
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
defmodule ContractsTest do | |
use ExUnit.Case | |
defmodule TestMod do | |
use Contracts | |
@requires "x > 0" | |
def inv(x) do | |
-x | |
end | |
end | |
test "with bad args" do | |
TestMod.inv(1) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment