Module middleware

Any ideas how to perform module middleware? Like Plug do but for modules.
Example:

defmodule ModuleA do
use Magic, only [:target_fun]

def target_fun(someparams) do
end

def no_magic_here(params) do 
end
end

defmodule ModuleB do

def calling_fun do
    result = ModuleA.target_fun(someparams)
end

end

defmodule Magic do
defmacro __using__(_) do
quote do

def run_me_before_some_functions() do
    do_some_job
    result = apply(__MODULE__, target_fun, someparams)
    do_some_job
    result
end

def do_some_job do
end

end
end
1 Like

@DmytroNasyrov: You could make it with module attributes and your custom def macro, but it’s not easy to do and it’s not clear. Easier way is to write something like:

defmodule Hello do
  def world, do: IO.puts "Hello world!"
end

defmodule Jobs do
  def first_job do
    # ...
  end
end

defmodule Magic do
  def call(module, method, args, opts \\ %{}) do
    if Map.has_key?(opts, :before), do: do_call(opts.before)
    apply(module, method, args)
    if Map.has_key?(opts, :after), do: do_call(opts.before)
  end

  defp do_call({module, method, args}) do
    apply(module, method, args)
  end
end

tuple = {Jobs, :first_job, []}
Magic.call(Hello, :world, [], %{after: tuple, before: tuple})
2 Likes

Yes, my solution is very-very similar to this. Just instead of Magic.call(m, :f, a) it’s Jobs.run(:f, [a]).
But I want to completely hide that and make it Jobs.f(a)

1 Like