Decorators/wrappers for Elixir the way you've never seen it!

Hi there!

From what you know, decorators in Elixir can be implemented, but it gets cumbersome and you shouldn’t do it. Below you will see a new approach that is very simple. It is not exactly decorators (the module attributes syntax is not used) but a decent replacement for them: wrappers.

defmodule Wrapper do
  defmacro apply(call, [do: block]) do
    {wrapper, _opts, args} = call
    func = makefun(do: block)
    {wrapper, [], [:wraps, func] ++ args}
  end

  def makefun(do: block), do:
    {:fn, [], [{:->, [], [[], block]}]}

end



defmodule Ex do
  require Wrapper

  # a wrapper that increments each of 2 values returned
  def incr(:wraps, f, x, y) do
    # x and y are unused here
    {a, b} = f.()
    {a+1, b+1}
  end

  def f(x, y) do
    incr(x, y) |> Wrapper.apply do
      {x, y}
    end
  end

  # a convenience macros for incr wrapper
  # just showing it can have the same name (incr)
  defmacro incr(x,y, do: block) do
    {wrapper, _opts, _args} = quote do Ex.incr end
    func = Wrapper.makefun(do: block)
    {wrapper, [], [:wraps, func, x, y]}
  end
  def g(x, y) do
    incr(x, y) do
      {x, y}
    end
  end

end