Определите другой макрос внутри __using__ - PullRequest
0 голосов
/ 30 октября 2018

У меня есть модуль под названием Интерфейсы:

defmodule Interfaces do
  defmacro __using__(module) do
    @module unquote(module) |> List.first |> elem(1)
    defmacro expose(name) do
      IO.inspect params, label: "Expanding macro with: "
      IO.inspect @module, label: "I need this !!"

      def unquote(name)() do
        IO.puts "The function has been created with exposed name"
      end
    end
  end
end

Еще один модуль под названием Interfaces.MyModule:

defmodule Interfaces.MyModule do
  use Interfaces, for: Something.DefinedElseWhere

  expose :plop
end

Но во время компиляции я получаю

** (CompileError) lib/my_module.ex:6: undefined function expose/1

1 Ответ

0 голосов
/ 30 октября 2018

Я настоятельно рекомендую вам прочитать Руководство по макросам на официальном сайте Elixir. Хотя то, что вы делаете, возможно (используя quote), это совсем не поощряется.

Макросы должны быть простыми, и их функциональность должна быть разбита на другие макросы и методы в случае необходимости. Один из способов сделать это - использовать оператор import в вашем макросе, чтобы импортировать другие макросы, которые вам нужны в последнем модуле:

defmodule Interface do
  defmacro __using__(opts) do
    quote(bind_quoted: [opts: opts]) do
      import Interface

      @interface_module Keyword.get(opts, :for)
    end
  end

  defmacro expose(name) do
    quote do
      IO.inspect @interface_module, label: "I need this !!"

      def unquote(name)() do
        IO.puts "The function has been created with exposed name"
      end
    end
  end
end

Теперь вы можете использовать его:

defmodule MyImplementation do
  use Interface, for: AnotherModule

  expose(:hello)
end

Вот другой пример из одного из моих проектов о том, как вам следует разбить реализацию больших макросов с помощью вспомогательных функций и других макросов.

...