*21 Apr 2020*
Sometimes you might need to execute code dynamically based - for instance - on the name of a module, akin to code reflection on other languages.
In Elixir one way this can be achieved is by using Erlang's `:code` module. As an example, say you want to run a function in a module named `MyProject.Foo`.
### Find that module
The first thing we need to do is to find the module:
` ```
def find_module(name) do
:code.all_loaded()
|> Enum.map(&elem(&1, 0))
|> Enum.find(fn module ->
module_name = Atom.to_string(module)
String.starts_with?(module_name, "Elixir.#{name}") and
!String.ends_with?(module_name, "Test")
end)
end
``` `
You might notice two things there: 1. all modules in Elixir start with `Elixir.` and 2. i am excluding a potential test module that might have the same name as the module we want to run the code on.
### Run them codes
Now we need to be able to execute functions on our module. For that we can use the `apply` function from the Kernel:
` ```
case find_module(module_name) do
nil -> {:error, "module #{module_name} not found"}
module -> apply(module, function, args)
end
``` `
### A concrete example
` ```
defmodule MyProject.Foo do
def bar(message) do
IO.puts("Hello #{message}")
end
end
defmodule MyProject.Runtime do
def find_module(name) do
:code.all_loaded()
|> Enum.map(&elem(&1, 0))
|> Enum.find(fn module ->
module_name = Atom.to_string(module)
String.starts_with?(module_name, "Elixir.#{name}") and
!String.ends_with?(module_name, "Test")
end)
end
def execute_module_function(module_name, function, args \\ []) do
case find_module(module_name) do
nil -> {:error, "module #{module_name} not found"}
module -> apply(module, function, args)
end
end
end
MyProject.Runtime.execute_module_function("MyProject.Foo", :bar, ["world"])
MyProject.Runtime.execute_module_function("MyProject.NonExisting", :bar, ["world"])
``` ` Happy coding!
[[tags/code|code]] [[tags/dynamic|dynamic]] [[tags/elixir|elixir]] [[tags/execution|execution]] [[tags/module|module]] [[tags/reflection|reflection]]