TheSquad
TheSquad

Reputation: 7506

Define another macro inside __using__

I have a module called Interfaces:

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

Another module called Interfaces.MyModule :

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

  expose :plop
end

But at compile time I get

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

Upvotes: 1

Views: 1310

Answers (1)

Sheharyar
Sheharyar

Reputation: 75840

I highly recommend that you read the Macros Guide on the official Elixir website. While what you're doing is possible (using quote), it is not encouraged at all.

Macros should be simple and their functionality should be broken down further in other macros and methods if the need arises. One way to do that is to use the import statement in your macro to import other macros that you need exposed in the final module:

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

Now you can use it:

defmodule MyImplementation do
  use Interface, for: AnotherModule

  expose(:hello)
end

Here's another example from one of my projects, on how you should break down the implementation of large macros using helper functions and other macros.

Upvotes: 2

Related Questions