I see there was a long discussion on the proposal of private modules, but I can’t tell what decision was reached. I’m writing a library which has an internal-only __using__/1
macro, and I want to know how I can make it private to the library.
There are no private modules, only private functions. It might be possible to do something of the sort with macro / metaprogramming trickery, but there is no standard feature for it. There is a library called Boundary that provides some guarantees to prevent using modules you shouldn’t.
To hard-restrict calling macros from allowed places only, one might use __CALLER__
special form inside macro.
@allowed_callers Foo.Bar, Foo.Baz
defmacro any_macro do
raise unless __CALLER__.module in @allowed_callers
...
end
Love this solution. I would mark it as the solution in this thread but I can’t apparently because of the discussion type I chose.
One question, is there a way to check if __CALLER__.module
is a submodule or child module of another module – i.e. ModA.ModB
is child of ModA
?
I made the change to the topic and set the solution as requested.
There is no such thing as “submodule” or “child module” in Elixir. Foo.Bar
, despite it shares the first part of the name with Foo
is absolutely not related to Foo
by any means.
If you meant “to check whether a module shares a namespace,” that’d be easy to achieve with Module.split/1
and List.starts_with?/2
, like
{m1, m2} = {Foo.Bar.Baz, Foo.Bar}
[m2, m1] |> Enum.map(&Module.split/1) |> Enum.reduce(&List.starts_with?/2)
#⇒ true
[m1, m2] |> Enum.map(&Module.split/1) |> Enum.reduce(&List.starts_with?/2)
#⇒ false