У меня есть карта, на которой я хочу использовать один источник правды для нескольких функций.Допустим, это:
source_of_truth = %{a: 10, b: 20}
Я бы хотел, чтобы ключи этой карты имели значения EctoEnum .EctoEnum предоставляет макрос defenum
, который я должен использовать следующим образом:
defenum(
EnumModule,
:enum_name,
[:a, :b]
)
Я не хочу повторять [:a, :b]
часть.Вместо этого я хотел бы использовать ключи с карты следующим образом:
defenum(
EnumModule,
:enum_name,
Map.keys(source_of_truth)
)
Это не работает, потому что макрос defenum
ожидает простой список.
Я думал, что смогу сделатьопределив мой собственный макрос следующим образом:
defmacro dynamic_enum(enum_module, enum_name, enum_values) do
quote do
defenum(
unquote(enum_module),
unquote(enum_name),
unquote(enum_values)
)
end
end
, а затем вызовите:
dynamic_enum(EnumModule, :enum_name, Map.keys(source_of_truth))
Однако это делает то же самое: enum_values
- это не предварительно вычисленный список, а AST дляMap.get
.Мой следующий подход был:
defmacro dynamic_enum(enum_module, enum_name, enum_values) do
quote do
values = unquote(enum_values)
defenum(
unquote(enum_module),
unquote(enum_name),
?
)
end
end
Не уверен, что я мог бы поместить туда, где находится ?
.Я не могу просто поставить values
, потому что это переменная, а не список.Я тоже не могу поставить unquote(values)
.
Решение такого рода работ таково:
defmacro dynamic_enum(enum_module, enum_name, enum_values) do
{values, _} = Code.eval_quoted(enum_values)
quote do
defenum(
unquote(enum_module),
unquote(enum_name),
unquote(values)
)
end
end
Однако в документах говорится, что использование eval_quoted
внутри макросаплохая практика.
[EDIT] Решение с Macro.expand
тоже не работает, потому что на самом деле ничего не оценивает.Расширение останавливается на:
Expanded: {{:., [],
[
{:__aliases__, [alias: false, counter: -576460752303357631], [:Module]},
:get_attribute
]}, [],
[
{:__MODULE__, [counter: -576460752303357631], Kernel},
:keys,
[
{:{}, [],
[
TestModule,
:__MODULE__,
0,
[
file: '...',
line: 16
]
]}
]
]}
, поэтому оно не расширяется до списка, как мы ожидали.
[\ EDIT]
Что является хорошим решением для этой проблемы