Skip to content

Instantly share code, notes, and snippets.

@guilleiguaran
Last active December 1, 2015 03:09
Show Gist options
  • Select an option

  • Save guilleiguaran/e757425ea8777d9c6384 to your computer and use it in GitHub Desktop.

Select an option

Save guilleiguaran/e757425ea8777d9c6384 to your computer and use it in GitHub Desktop.

Revisions

  1. guilleiguaran revised this gist Dec 1, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion contracts.ex
    Original file line number Diff line number Diff line change
    @@ -31,7 +31,7 @@ defmodule Contracts do
    var!(result) = unquote(content)
    var!(result)
    end
    end |> Macro.to_string |> IO.puts
    end # |> Macro.to_string |> IO.puts
    end

    def __on_definition__(env, function) do
  2. guilleiguaran created this gist Dec 1, 2015.
    53 changes: 53 additions & 0 deletions contracts.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,53 @@
    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
    16 changes: 16 additions & 0 deletions contracts_test.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    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