Hey,
I know there are other ways to do this, but I went down a deep rabbit hole last night trying to figure this one out … this is purely a though experiment.
Say you have 2 almost identical dependencies, but you only want to use one of them at a time. Maybe the choice of dependency is geographic based?
Both dependencies have an example module hierarchy like:
M0
|
M0.M1 - M0.M2 - M0.M3
|
M0.M2.M4
Now of course a simple solution to ensure the code in the rest of the application selects the correct dependency would be something like this in all the modules that use it:
config = Application.compile_env(:my_app, SpecialDependency, [])
@dependency Keyword.get(config, :special_dep)
# And code would do:
@dependency.foo(a, b, c)
Seems a bit hokey…what would be nice is to create a new (set) of stub modules that, for want of a better word “alias” the correct dependency. All the application code would call the stub which would get mapped onto the correct target dependency.
For example (yes, I can also use defdelegate
)
defmodule SpecialDependencyStub do
config = Application.compile_env(:my_app, SpecialDependency, [])
@dependency Keyword.get(config, :special_dep)
# Generate the same functions as the real dependency
Enum.each(@dependency.__info__(:functions), fn({fun, arity}) ->
args = Macro.generate_arguments(arity, __MODULE__)
def unquote(fun)(unquote_splicing(args)), do: unquote(@dependency).unquote(fun)(unquote_splicing(args))
end)
end
Now that works fine…where I am stumped is how to handle all the modules under the SpecialDependency
. I want those modules to retain the same name as the real dependency, and I’d rather not have to repeat the above for every module. Something like
Enum.each(modules, fn(mod) -> WizzardsBeHere end)
Hopefully that all makes sense