Fun with Elixir Macros

Fun with Elixir Macros

Lightning talk from ElixirConfEU 2018

9fae8c5d475fe322a3a74e53d56ee2a0?s=128

Tymon Tobolski

April 16, 2018
Tweet

Transcript

  1. 2.

    defmodule AppRouter do use Plug.Router plug :match plug :dispatch get

    "/hello" do send_resp(conn, 200, "world") end match _ do send_resp(conn, 404, "oops") end end
  2. 5.

    defmodule Tesla do defmacro __using__(_) do quote do Module.register_attribute(__MODULE__, :middleware,

    accumulate: true) @before_compile Tesla import Tesla, only: [plug: 1, plug: 2] def request(method, path), do: Tesla.request(__MODULE__, {method, path}) end end # ...
  3. 7.

    defmodule Cabify do Module.register_attribute(__MODULE__, :middleware, accumulate: true) @before_compile Tesla @middleware

    {Tesla.Middleware.Base, "https://cabify.com"} @middleware {Tesla.Middleware.JSON, []} end
  4. 9.

    defmodule Cabify do # ... def __middleware__ do [ {Tesla.Middleware.Base,

    "https://cabify.com"}, {Tesla.Middleware.JSON, []} ] end end
  5. 10.

    defmodule Tesla do def request(module, env) do stack = module.__middleware__

    run(env, stack) end def run(env, []), do: make_request(env) def run(env, [{module, opts} | rest]), do: apply(module, :call, [env, rest, opts]) end
  6. 11.

    defmodule Tesla.Middleware.Base do def call({method, path}, next, base) do Tesla.run({method,

    base <> path}, next) end end defmodule Tesla.Middleware.JSON do def call({method, path}, next, _opts) do Tesla.run({method, path <> ".json"}, next) end end
  7. 13.

    - Simple & powerful API - call(env, next, opts) -

    Allows hot reloading of middlewares on production system - Full implementation at github.com/teamon/tesla (be sure to use 1.0.0-beta.1) - Don’t be afraid of macros :)