Skip to content

Instantly share code, notes, and snippets.

@polvalente
Created November 22, 2020 23:39
Show Gist options
  • Save polvalente/8c8f903bb9f6704039500c8dd2ee3e7c to your computer and use it in GitHub Desktop.
Save polvalente/8c8f903bb9f6704039500c8dd2ee3e7c to your computer and use it in GitHub Desktop.
Observable pattern implemented with metaprogramming
defmodule Observable do
defmacro __using__(opts) do
subscriber_modules = opts[:subscriber_modules]
function = opts[:observable_function]
tag = opts[:tag]
{f, _} = Code.eval_quoted(function)
arity = f |> :erlang.fun_info() |> Keyword.get(:arity)
args =
Enum.map(1..arity, fn n ->
Macro.var(:"arg_#{n}", __MODULE__)
end)
quote do
require Kernel.SpecialForms
@doc """
Dispatches the `function(arg)` result to the subscriber modules
"""
def execute(unquote_splicing(args)) do
result = unquote(function).(unquote_splicing(args))
Enum.each(unquote(subscriber_modules), fn mod ->
:ok = mod.receive(unquote(tag), result)
end)
result
end
end
end
end
defmodule Subscriber1 do
def receive(tag, result) do
IO.puts("Sub. 1 received #{inspect(result)} from #{tag}")
end
end
defmodule Subscriber2 do
def receive(tag, result) do
IO.puts("Sub. 2 received #{inspect(result)} from #{tag}")
end
end
defmodule Executor do
use Observable,
subscriber_modules: [Subscriber1, Subscriber2],
tag: :my_executor,
observable_function: &Executor.addition/3
@doc false
def addition(a, b, c), do: a + b + c
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment