I'm trying to keep track of all modules that use another module at compile-time and get a list of all these module at runtime:
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
And get them at runtime by calling something like this:
BaseModule.children()
#=> [A, B, C]
I have been trying to find a way to accomplish this but still have absolutely no idea on how to do it. Going through this thread on the elixir-lang mailing list, @josevalim recommends using Protocols to do this. But after struggling this for about an hour, I can't get it to work with Protocols either.
I've also been looking in to the Registry module to see if I can accomplish this using that, but it looks like it's designed to work with processes mainly.
Any help would be highly appreciated. Thanks in advance!
If your base module uses a behaviour then the following solution is possible.
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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With