So while writing Confy, I wanted to turn shorthand atoms like:integer, :string, :atom into the ‘normal’ forms &Confy.Parsers.integer/1, &Confy.Parsers.string/1, &Confy.Parsers.atom/1, etc.
However, I struggled to properly perform quoting and unquoting while using the function capture operator&.
In the end, I settled on the following snippet:
# Replaces simplified atom parsers with
# an actual reference to the parser function in `Confy.Parsers`.
# NOTE: I dislke the necessity of `Code.eval_quoted` here, but do not currently know of another way.
defp normalize_parser(parser) when is_atom(parser) do
case Confy.Parsers.__info__(:functions)[parser] do
nil -> raise ArgumentError, "Parser shorthand `#{inspect(parser)}` was not recognized. Only atoms representing names of functions that live in `Confy.Parsers` are."
1 ->
{binding, []} = Code.eval_quoted(quote do &Confy.Parsers.unquote(parser)/1 end)
binding
end
end
defp normalize_parser(other), do: other
Note the Code.eval_quoted line: Although it is probably safe since it is only executed when parser indeed is an atom and exists as a function inside the Confy.Parsers module, it does not feel nice to need it.
Is there another way to build a function capture out of a module and function atom?
Note that 'function captures like wrapping everything with fn are not what I am looking for, since the result of normalize_parser is also used to create documentation:
inspect(&Module.foo/1) is "&Module.foo/1" whereas
inspect(fn x -> Module.foo(x) end) is "#Function<6.127694169/1 in :erl_eval.expr/5>".
Thanks! ![]()






















