Skip to content

Instantly share code, notes, and snippets.

@blatyo
Last active December 2, 2016 13:52
Show Gist options
  • Save blatyo/8b5dd4ca6ca998c79af862bed5a73d6e to your computer and use it in GitHub Desktop.
Save blatyo/8b5dd4ca6ca998c79af862bed5a73d6e to your computer and use it in GitHub Desktop.
defmodule P do
defmacro __using__(_opts) do
quote do
import P
Module.register_attribute(__MODULE__, :plugs, accumulate: true)
@before_compile P
end
end
defmacro __before_compile__(env) do
plugs = [{:call, quote do: opts} | Module.get_attribute(env.module, :plugs)]
builder = P.compile(plugs, quote do: next)
quote location: :keep do
def run(message, opts) do
__build__(&(&1), opts).(message)
end
def __build__(next, opts) do
unquote(builder)
end
end
end
defmacro plug(plug, opts \\ []) do
quote do: @plugs {unquote(plug), unquote(Macro.escape(opts))}
end
def compile(plugs, last) do
Enum.reduce(plugs, last, fn plug, next ->
quoted_plug = quote_plug(plug, next)
quote do
unquote(quoted_plug)
end
end)
end
defp quote_plug({plug, opts}, next) do
case Atom.to_char_list(plug) do
~c"Elixir." ++ _ -> quote_module_plug(plug, next, opts)
_ -> quote_fun_plug(plug, next, opts)
end
end
defp quote_module_plug(plug, next, opts) do
if Code.ensure_compiled?(plug) do
quote do
unquote(plug).__build__(unquote(next), unquote(opts))
end
else
raise "Couldn't find module #{plug}"
end
end
def quote_fun_plug(plug, next, opts) do
quote do
fn message ->
unquote(plug)(message, unquote(next), unquote(opts))
end
end
end
end
defmodule M do
use P
plug :foo, 3
plug :bar, 2
def foo(num, next, sub \\ 3) do
next.(num - sub)
end
def bar(num, next, mult \\ 2) do
next.(num * mult)
end
def call(num, next, add \\ 1) do
next.(num + add)
end
end
defmodule N do
use P
plug M, 1
plug M, 2
def call(num, next, div \\ 2) do
next.(num / div)
end
end
# plug x - 3
# plug x * 2
# plug x + 1
plugs = [
fn x, next -> next.(x + 1) end,
fn x, next -> next.(x * 2) end,
fn x, next -> next.(x - 3) end
]
math = Enum.reduce(plugs, &(&1), fn plug, next ->
&plug.(&1, next)
end)
math.(50) # ((50 - 3) * 2) + 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment