defmodule Pipex do @moduledoc """ ### Example usage: ```elixir defmodule Pipeline do use Pipex alias __MODULE__ defstruct var1: nil, var2: [] pipe :local_function pipe ExternalModule def run(args) do token = struct(Pipeline, args) Pipeline.call(token) end def local_function(%Pipeline{} = token) do # do something with the token and return it %{token | va1: "var1"} end end def ExternalModule do def call(%Pipeline{} = token) do # do something with the token and return it %{token | var2: [1, 2, 3]} end end ``` """ defmacro __using__(_opts) do quote do Module.register_attribute(__MODULE__, :pipes, accumulate: true) @before_compile Pipex import Pipex, only: [pipe: 1] def call(token) do do_call(token) end end end defmacro pipe(module) do quote do @pipes unquote(module) end end defmacro __before_compile__(_env) do quote do defp do_call(token) do pipes = Enum.reverse(@pipes) Pipex.call_pipes(__MODULE__, token, pipes) end end end def call_pipes(module, initial_token, pipes) do Enum.reduce(pipes, initial_token, fn pipe, token -> case Atom.to_charlist(pipe) do 'Elixir.' ++ _ -> pipe.call(token) _ -> Kernel.apply(module, pipe, [token]) end end) end end