跟踪“使用”另一个模块的模块

时间:2017-06-23 22:53:23

标签: elixir

我正在尝试在编译时跟踪use另一个模块的所有模块,并在运行时获取所有这些模块的列表:

defmodule BaseModule do
  defmacro __using__(_) do
    quote do
      # common behaviour
    end
  end
end


defmodule A do
  use BaseModule
end

defmodule B do
  use BaseModule
end

defmodule C do
  use BaseModule
end

通过调用类似的东西在运行时获取它们:

BaseModule.children()
#=> [A, B, C]

我一直试图找到一种方法来实现这一目标,但仍然完全不知道如何做到这一点。通过this thread on the elixir-lang mailing list@josevalim建议使用Protocols执行此操作。但经过大约一个小时的努力,我无法让它与协议一起工作。

我也一直在查看Registry模块,看看我是否可以使用它完成此任务,但看起来它主要用于处理进程。

任何帮助都将受到高度赞赏。提前谢谢!

1 个答案:

答案 0 :(得分:3)

如果基本模块使用某种行为,则可以使用以下解决方案。

defmodule BaseModule do
  @callback foo() :: any()

  defmacro __using__(_opts) do
    quote do
      # Fairly standard to use a behaviour and gives us something to detect later.
      @behaviour unquote(__MODULE__)

      # Any other setup required
    end
  end

  def children() do
    (for {module, _} <- :code.all_loaded(), do: module)
    |> Enum.filter(&is_child?/1)
  end

  def is_child?(module) do
    module.module_info[:attributes]
    |> Keyword.get(:behaviour, [])
    |> Enum.member?(__MODULE__)
  end
end

defmodule A do
  use BaseModule
end

BaseModule.children()
#=> [A]