¿Cómo crear y cargar módulos dinámicamente en tiempo de ejecución en Elixir o Erlang?

El escenario básico es este: necesito cargar texto de una base de datos, y luego convertir ese texto en un módulo de Elixir (o un módulo de Erlang) y luego hacer llamadas en él. El texto es efectivamente el mismo que un archivo de módulo. Así que esta es una forma de carga de código caliente. Quiero compilar el "archivo" y luego cargar el módulo resultante, luego hacer llamadas en él. Después lo descargaré. La única diferencia es que el código existe en una base de datos en lugar de un archivo en el disco. (y no existe en el momento en que escribo el código que lo cargará).

Sé que Erlang admite la carga de códigos en caliente, pero parece estar enfocado en compilar archivos en el disco y luego cargar los haces. Deseo hacer esto como un proceso más dinámico, y no estaré reemplazando el código en ejecución, sino cargando el código, luego ejecutándolo y luego descargándolo.

Hay varias instalaciones en Elixir para evaluar el código en tiempo de ejecución. Estoy tratando de averiguar cómo hacer esto con ellos, y la documentación es un poco escasa.

Code.compile_string(string, "nofile")

"devuelve una lista de tuplas donde el primer elemento es el nombre del módulo y el segundo es su binario". Entonces, ahora tengo los nombres de los módulos y sus binarios, pero no conozco una manera de cargar los binarios en el tiempo de ejecución y llamarlos. ¿Como podría hacerlo? (No hay ninguna función para eso en la biblioteca de códigos que pueda ver).

Posiblemente podría usar la función de Erlang:

:code.load_binary(Module, Filename, Binary)  ->
           {module, Module} | {error, What}

Ok, entonces esto devuelve una tupla con el átomo "módulo" y luego el módulo. Si la cadena cargada desde la base de datos define un módulo llamado "París", ¿cómo ejecutaría en mi código?

paris.handler([parameters])

ya que no sé de antemano que habrá un módulo llamado paris? Podría saber, al tener la cadena "paris" también almacenada en la base de datos que este es el nombre, pero ¿hay alguna forma de llamar a un módulo, usando una cadena como el nombre del módulo que está llamando?

También hay:

eval(string, binding // [], opts // [])

Que evalúa los contenidos de la cadena. ¿Puede esta cadena ser la definición completa de un módulo? Parece que no. Me gustaría poder escribir este código que se está evaluando de tal manera que tenga múltiples funciones que se llamen entre sí, por ejemplo. un pequeño programa completo, con un punto de entrada predefinido (que podría ser un main, como "DynamicModule.handle ([parámetro, lista])"

Luego está el módulo EEx, que tiene:

compile_string(source, options // [])

Lo que es genial para hacer plantillas. Pero en última instancia, parece que solo funciona para el caso de uso donde hay una cadena y tienes el código Elixir incorporado. Evalúa la cadena en el contexto de las opciones y produce una cadena. Estoy tratando de compilar la cadena en una o más funciones que luego puedo llamar. (Si solo puedo hacer una función que esté bien, esa función puede hacer un patrón de coincidencia o cambiar para hacer las otras cosas que se necesitan ...)

Sé que esto no es convencional, pero tengo mis razones para hacerlo de esta manera y son buenas. Estoy buscando consejos sobre cómo hacer esto, pero no es necesario que me digan "no hagas eso". Parece que debería ser posible, Erlang admite la carga de códigos en caliente y Elixir es bastante dinámico, pero no conozco la sintaxis ni las funciones correctas. Estaré siguiendo de cerca esta pregunta. ¡Gracias por adelantado!

EDITOS basados ​​en las primeras respuestas:

Gracias por las respuestas, este es un buen progreso. Como demostró Yuri, eval puede definir un módulo y, como señala José, puedo usar el código eval para pequeñas partes de código con enlaces.

El código que se está evaluando (ya sea que se convierta en un módulo o no) será bastante complejo. Y su desarrollo sería mejor involucrarlo en funciones y llamar a esas funciones.

Para ayudar, déjame dar un poco de contexto. Supongamos que estoy construyendo un framework web. El código cargado desde la base de datos es manejadores para URIs específicos. Entonces, cuando entra una llamada HTTP, podría cargar el código para example.com/blog/ Esta página puede incluir varias cosas diferentes, como comentarios, una lista de publicaciones recientes, etc.

Como muchas personas están golpeando la página al mismo tiempo, estoy generando un proceso para manejar cada vista de página. Así, hay muchas veces cuando este código puede ser evaluado simultáneamente, para diferentes solicitudes.

La solución del módulo le permite a uno dividir el código en funciones para diferentes partes de la página (por ejemplo: la lista de publicaciones, comentarios, etc.) Y cargaría el módulo una vez, al inicio, y permitiría que muchos procesos generen esa llamada en ello. El módulo es global, ¿correcto?

¿Qué pasa si ya hay un módulo definido? EG: Cuando el módulo cambia y ya hay procesos que llaman a ese módulo.

En iex, puedo redefinir un módulo que ya se ha definido:

iex(20)> Code.eval "defmodule A do\ndef a do\n5\nend\nend"
nofile:1: redefining module A

¿Qué sucede si redefino el módulo en tiempo de ejecución, a todos los procesos que actualmente están llamando a ese módulo? Además, ¿funcionará esta redefinición fuera de iex en el funcionamiento normal?

Suponiendo que la redefinición del módulo sería problemático y que los módulos que son globales podrían tener problemas con colisiones de espacio de nombres, busqué en el uso de eval para definir una función.

Si simplemente puedo hacer que el código de la base de datos defina funciones, entonces esas funciones están dentro del alcance de cualquier proceso, y no tenemos la posibilidad de colisiones globales.

Sin embargo, esto no parece funcionar:

iex(31)> q = "f = function do
...(31)> x, y when x > 0 -> x+y
...(31)> x, y -> x* y
...(31)> end"
"f = function do\nx, y when x > 0 -> x+y\nx, y -> x* y\nend"
iex(32)> Code.eval q
{#Fun<erl_eval.12.82930912>,[f: #Fun<erl_eval.12.82930912>]}
iex(33)> f
** (UndefinedFunctionError) undefined function: IEx.Helpers.f/0
    IEx.Helpers.f()
    erl_eval.erl:572: :erl_eval.do_apply/6
    src/elixir.erl:110: :elixir.eval_forms/3
    /Users/jose/Work/github/elixir/lib/iex/lib/iex/loop.ex:18: IEx.Loop.do_loop/1

iex(33)> f.(1,3)
** (UndefinedFunctionError) undefined function: IEx.Helpers.f/0
    IEx.Helpers.f()
    erl_eval.erl:572: :erl_eval.do_apply/6
    erl_eval.erl:355: :erl_eval.expr/5
    src/elixir.erl:110: :elixir.eval_forms/3
    /Users/jose/Work/github/elixir/lib/iex/lib/iex/loop.ex:18: IEx.Loop.do_loop/1

También intenté:

    iex(17)> y = Code.eval "fn(a,b) -> a + b end"
{#Fun<erl_eval.12.82930912>,[]}
iex(18)> y.(1,2)
** (BadFunctionError) bad function: {#Fun<erl_eval.12.82930912>,[]}
    erl_eval.erl:559: :erl_eval.do_apply/5
    src/elixir.erl:110: :elixir.eval_forms/3
    /Users/jose/Work/github/elixir/lib/iex/lib/iex/loop.ex:18: IEx.Loop.do_loop/1

Entonces, en resumen:

¿Se pueden redefinir los módulos utilizando Code.eval cuando hay procesos que llaman a ellos?

¿Es posible usar Code.eval para realizar funciones cuyo alcance está vinculado al proceso en el que se llamó a Code.eval?

Si entiendes qué es lo que estoy tratando de hacer, ¿puedes sugerir una mejor manera de hacerlo?

Además, si hay un foro mejor donde debería preguntar esto, no dude en hacérmelo saber. Y si hay documentos o ejemplos relevantes que debería leer, no dude en señalarme. No estoy tratando de hacer que hagas todo el trabajo, soy incapaz de averiguarlo yo mismo.

Estoy aprendiendo Elixir específicamente por la capacidad de evadir dinámicamente el código, pero mi conocimiento de Elixir es mínimo ahora, acabo de empezar, y mi erlang también está oxidado.

¡Muchas gracias!

Respuestas a la pregunta(3)

Su respuesta a la pregunta