dynamic - Elixir-Método de llamada en el módulo por String-name
module load (3)
Soy bastante nuevo en Elixir y en los lenguajes de programación funcionales en general.
En Elixir, quiero llamar a una función específica en Módulos, dado el nombre del Módulo como Cadena.
Tengo el siguiente código (muy malo) funcionando, que hace lo que quiero:
module_name = elem(elem(Code.eval_file("module.ex", __DIR__), 0), 1)
apply(module_name, :helloWorld, [])
Esto (al menos tal como lo entiendo) compila el módulo (ya compilado) de module.ex
en el directorio actual. Estoy extrayendo el nombre de los módulos (no como una cadena, no sé qué tipo de datos es en realidad) de las dos tuplas y ejecuto el método helloWorld
en él.
Hay dos problemas con este código:
Imprime una advertencia como
redefining module Balance
. Ciertamente no quiero que eso suceda en producción.AFAIK este código compila
module.ex
. Pero como module.ex ya está compilado y cargado, no quiere que eso suceda.
No necesito llamar a métodos en estos módulos por nombre de archivo, el nombre de módulo también estaría bien. Pero tiene que hacerlo por dinámica, ej. al ingresar "Libro" en la línea de comando, después de verificar si el módulo existe, llame a la función Book.helloWorld
.
Gracias.
Bueno, ahí es donde pedir ayuda: lo sabrás tú mismo en el momento en que lo pidas. ;)
Simplemente usando apply(String.to_existing_atom("Elixir.Module"), :helloWorld, [])
ahora. (tal vez el nombre "Módulo" no está permitido, no lo sé)
También tenga en cuenta que el nombre de un módulo es un átomo, por lo que String.to_existing_atom
no suele ser necesario. Considera este código:
defmodule T do
def first([]), do: nil
def first([h|t]), do: h
end
En este caso, simplemente puede hacer la solicitud de esta manera:
apply(T,:first,[[1,2,3]])
#=> 1
O este ejemplo (la lista a continuación es el módulo de la lista Elixir):
apply(List,:first,[[1,2,3]])
#=> 1
Quiero decir que si conoces el nombre del módulo, no es necesario pasarlo como una cadena y luego convertir la cadena a un átomo existente. Simplemente use el nombre sin comillas.
Tenga en cuenta que siempre necesita agregar un prefijo a sus módulos con "Elixir".
defmodule Test do
def test(text) do
IO.puts("#{text}")
end
end
apply(String.to_existing_atom("Elixir.Test"), :test, ["test"])
imprime "prueba" y devuelve {: ok}