Ну, это возможно.Проблема с вашим кодом заключается в том, что вы смешиваете области видимости.Макросы в Elixir расширяются на этапе компиляции.В данный момент нет скомпилированной say_greetings/1
функции (кроме того, что нельзя вызвать defp
изнутри defmacro
, но это может быть преодолено при правильном цитировании.)
Что вам нужно для этогоработа, будет означать объявление say_greetings/1
в той же области, что и __before_compile__/1
, чтобы сделать его доступным.Вы не можете определить его как функцию (см. Выше), но обходной путь должен был бы определить его как макрос .Таким образом, он будет расширен во время компиляции, и все будет работать (также я сомневаюсь, что понимаю причину этого.)
Подведение итогов:
defmodule Greetify do
defmacro __using__(_) do
quote do
Module.register_attribute __MODULE__, :greet, accumulate: true, persist: false
@before_compile Greetify
end
end
defmacrop say_greetings(greetings) do
quote do
for {name, age} <- unquote(greetings) do
IO.puts "#{name} is #{age} years old"
end
end
end
defmacro __before_compile__(env) do
greetings = Module.get_attribute(env.module, :greet)
say_greetings(greetings)
end
end
defmodule Test do
use Greetify
@greet {"Jon", 21}
@greet {"Sam", 23}
end