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