runexec

runexec

Proof-of-concept Elixir Contracts

I was toying around to see if I could possibly get something similar to Clojure-style pre/post enforcement. This is what I came up with and would like your input. Thanks.


Example Usage

  defmodule Example do
    require Contract

    def reverse_abc(x) do
      # Contract pre processing
      pre_must_be_abc = fn -> x == "abc" end
      pre = [
        pre_must_be_abc,
      ]

      # Contract post processing
      post_must_be_cba = fn x -> x == "cba" end
      post_must_be_string = fn x -> is_binary x end
      post = [
        post_must_be_cba,
        post_must_be_string,
      ]

      # Contract
      # The arguments here are `[x]` and do not represent the current value of `x`
      reverse_abc_contract = Contract.new([x], [pre: pre, post: post], String.reverse(x))

      # Encorce Contract
      reverse_abc_contract.(x)
    end
  end

Basic Implementation

    defmodule Contract do

    defmodule EnforcePreError do
      defexception message: "Argument(s) Failed Pre Processing Requrements."
    end

    defmacro enforce(:pre, list, expr) do
      quote do
        valid? =
          Enum.map(unquote(list), fn f -> f.() end)
          |> Enum.all?(&(&1 == true))

        case valid? do
          true -> unquote(expr)
          _ -> raise EnforcePreError
        end
      end
    end

    defmodule EnforcePostError do
      defexception message: "Return value Failed Post Processing Requrements."
    end

    defmacro enforce(:post, list, value) do
      quote do
        valid? =
          Enum.map(unquote(list), fn f -> f.(unquote(value)) end)
          |> Enum.all?(&(&1 == true))

        case valid? do
          true -> unquote(value)
          _ -> raise EnforcePostError
        end
      end
    end

    defmodule EnforceNothingError do
      defexception message: "No enforcements are defined."
    end

    defmacro enforce(:prepost, pre, post, expr) do
      quote do
        pre = unquote(pre) || []
        post = unquote(post) || []
        no_enforcements? = (pre == [] && post == [])
        get_value = fn ->
          unquote(__MODULE__).enforce(:pre, unquote(pre), unquote(expr))
        end

        cond do
          no_enforcements? -> raise EnforceNothingError
          pre && post -> unquote(__MODULE__).enforce(:post, unquote(post), get_value.())
          (pre == []) && post -> unquote(__MODULE__).enforce(:post, unquote(post), unquote(expr))
          (post == []) && pre -> get_value.()
        end
      end
    end

    defmacro new(args, opts, expr) do
      quote do
        fn (unquote_splicing(args)) ->
          unquote(__MODULE__).enforce(
            :prepost, unquote(opts[:pre]), unquote(opts[:post]), unquote(expr)
          )
        end
      end
    end
  end

Where Next?

Popular in Discussions Top

pillaiindu
In django there is a cache framework backed by memcached. Rails also puts a lot of emphasis on caching, and even the idea of russian-doll...
New
WolfDan
After doing a port from a c++ library to my project in phoenix I’ve seen that I need a faster way to run this algorithm and I found this ...
New
nunobernardes99
Hi there Elixir friends :vulcan_salute: In a recent task I was on, I needed to check in two dates which of them is the maximum and which...
New
AlexMcConnell
The reason that Rails is as popular as it is is because it’s very easy for relatively inexperienced developers to get a lot of work done....
588 19568 166
New
ejpcmac
I have discovered Nix last month and I am currently on my way to migrating to it—both on macOS at home and the full NixOS distrubution at...
New
hazardfn
I suppose this question is effectively hackney vs. ibrowse but we are at a point in our project where we have to make a choice between th...
New
restack_oslo
Hello, Please pardon me for any faux paux. I am 46 and this is my first time on a forum of any kind. I wanted to to get answers from tho...
New
RudManusachi
What configs will make sense to put to runtime.exs? – A bit of how I configure apps: I have generic configs in config/config.exs, dev...
New
joeerl
I’m playing with Elixir - It’s fun. I think @rvirding does give Elixir courses these days. Re: files and database - when I given Erlang ...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement