Hi,
I’ve a little macro that given some attributes in the form keys / getters like:
defmodule Foo do
use Foo.Macro
# simplified version, normally there's a little DSL that defines the following map
event :something do
%{
foo: {Map, :get, [:somekey]},
bar: {Map, :get, [:someotherkey]}
}
end
end
adds a parse(data)
function to the Foo
module which returns a map with the above keys and values extracted from data using the given accessor.
The macro is something like:
defmodule Foo.Macro do
defmacro __using__(_opts) do
quote do
import Foo.Macro
end
end
defmacro event(_name, do: block) do
quote do
def parse(event) do
unquote(block)
|> Enum.map(fn {key, parser} ->
{m, f, args} = parser
{key, apply(m, f, [event | args])}
end)
|> Map.new()
end
end
end
end
Which works without problems.
The question now is: is possible in someway to dynamically create a function in the form:
def parse(event) do
%{
bar: Map.get(event, someotherkey),
foo: Map.get(event, somekey)
}
end
Without having to resort to a runtime Enum.map
, since all map keys and accessor functions/args are known at compile time ?
I’ve tried all sort of stuff, like composing a string of code, quoting it, etc etc but no result till now. Wondering if this is possible in Elixir (I’m not a super macro expert at all…)
In the real world this is a sort of map translator, where the data has somewhat many keys and accessor functions can be much more complex but always needs the whole data as input, since the value returned for field X may be dependent also on other fields.
Ready to learn the best way to do that, if any!
PS: the relevant files are also in elixir-macro-experiment/lib at main · xadhoom/elixir-macro-experiment · GitHub