Last active
December 2, 2016 13:52
-
-
Save blatyo/8b5dd4ca6ca998c79af862bed5a73d6e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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