I've found Kernel.apply/3
which allows dynamically calling a public method in a module by specifying the method as an atom, e.g. result = apply(__MODULE__, :my_method, [arg])
translates to result = my_method(arg)
What baffles me is a way to call a private method; Given code like this:
defmodule MyModule do
def do_priv(atom, args) when is_list(args) do
apply(__MODULE__, atom, args)
end
# (change defp => def, and this all works)
defp something_private(arg), do: arg #or whatever
end
I would expect that MyModule.do_priv(:something_private, [1])
to be permissible, since it's a call to a private method from within the module. I can appreciate that under the hood Elixir is using Erlang's apply/3, and so this approach probably isn't going to get us there.
I've also tried using the Code.eval_quoted/3
method, but it doesn't even seem to be capable of calling a hardcoded private method (and hence no time spent building the AST by hand, rather than using quote do
as below- though that's an option if someone sees how to make this work):
defmodule MyModule do
def do_priv_static do
something_private(1) #this works just fine
end
def do_priv_dynamic do
code = quote do
something_private(1)
end
Code.eval_quoted(code, [], __ENV__) #nope. fails
end
defp something_private(arg), do: arg #or whatever
end
Again, it's access to a private function from within the containing module, so I would expect it to be permissible. Its possible that I just don't understand the __ENV__
parameter to eval_quoted
The only working solution right now is changing defp
to def
, which is a fine solution for my personal code; but since I write code that supports other programmers who do care, I'd like to find a solution.
I'm open to other approaches, but I'm personally stumped on how to make this happen.