Wie erstellen Sie und laden von Modulen zur Laufzeit dynamisch in Elixir, oder Erlang?

Das grundlegende Szenario ist dieses: ich brauche zum laden von text aus einer Datenbank, und drehen Sie dann den text in ein Elixier-Modul (oder ein Erlang-Modul) und dann ruft hinein. Der text ist genauso effektiv wie eine Modul-Datei. Dies ist eine Art von hot-code laden. Ich möchte kompilieren Sie die "Datei", und laden Sie dann das resultierende Modul, dann ruft hinein. Später werde ich zu entladen. Der einzige Unterschied ist der code in einer Datenbank vorhanden ist, anstatt eine Datei auf der Festplatte. (und dann existiert es nicht an der Zeit, dass ich Schreibe den code zu laden.)

Ich weiß, Erlang unterstützt hot-code laden, scheint aber konzentrierte sich auf die Erstellung von Dateien auf der Festplatte und lädt dann die Balken. Ich wünschte, dies zu tun als ein dynamischer Prozess, und ich nicht ersetzen, ausführen von code, sondern laden Sie den code, dann läuft es, dann zu entladen.

Gibt es mehrere Einrichtungen in Elixir für die Bewertung von code zur Laufzeit. Ich versuche, herauszufinden, wie dies zu tun ist mit Ihnen, und die Dokumentation ist etwas spärlich.

Code.compile_string(string, "nofile")

"gibt eine Liste von Tupeln, wobei das erste element ist der name des Moduls und die zweite ist eine Binär". So, jetzt habe ich die Module Namen und Ihre Programme, aber ich weiß nicht, wie laden Sie dann die binaries in die Laufzeit und rufen in Ihnen. Wie soll ich das tun? (Es gibt keine Funktion, die in der Code-Bibliothek, die ich sehen kann.)

Vielleicht könnte ich dann mit der Erlang-Funktion:

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

Ok, das gibt ein Tupel mit dem atom "Modul" und dann das Modul. Wenn der string aus der Datenbank geladen, definiert ein Modul namens "Paris", wie in meinem code würde ich dann ausführen

paris.handler([parameters])

da ich nicht im Voraus wissen, dass es ein Modul namens paris? Konnte ich wissen, indem er die Zeichenfolge "paris" ebenfalls in der Datenbank gespeichert, dass dies der name, aber gibt es eine Möglichkeit der Berufung in ein Modul mit einer Zeichenfolge, die als name für das Modul, das Sie hier aufrufen?

Gibt es auch:

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

Das wertet den Inhalt der Zeichenfolge. Können diese Zeichenfolge die gesamte definition von einem Modul? Es erscheint nicht. Ich möchte in der Lage sein, um dieser code zu schreiben ist, die ausgewertet wird in einer solchen Weise, dass es hat mehrere Funktionen, die sich gegenseitig aufrufen--z.B. ein komplettes kleines Programm, mit vordefinierten entry-point (Die könnte ein Haupt, wie "DynamicModule.Griff([parameter-Liste])"

Dann gibt es die EEx-Modul, die hat:

compile_string(source, options //[])

Das ist toll, für den tut Vorlagen. Aber letztlich ist es nur scheint zu funktionieren für den Anwendungsfall, wo ein string und du hast Elixir-code in Sie eingebettet sind. Es wertet die Zeichenfolge, die im Rahmen der Optionen und erzeugt einen string. Ich Suche kompilieren Sie die Zeichenfolge in eine oder mehr Funktionen, die ich dann aufrufen kann. (Wenn ich nur eine Funktion, die ist in Ordnung, das Funktion können Muster übereinstimmen oder Schalter zu tun, die anderen Dinge, die benötigt werden....)

Ich weiß, das ist unkonventionell, aber ich habe meine Gründe, es zu tun auf diese Weise, und Sie sind die guten. Ich bin auf der Suche nach Rat, wie dies zu tun, müssen aber nicht gesagt "Mach das nicht". Es scheint, wie es sollte möglich sein, Erlang unterstützt hot-code laden und Elixier ist ziemlich dynamisch, aber ich weiß einfach nicht, die syntax, oder die richtigen Funktionen. Ich werde die überwachung dieser Frage eng zusammen. Vielen Dank im Voraus!


BEARBEITUNGEN basierend auf den ersten Antworten:

Danke für die Antworten, das ist gute Fortschritte. Als Yuri zeigte, eval definieren können Sie ein Modul, und wie José Punkte aus, kann ich einfach code eval für kleine Teile von code mit Bindungen.

Dem code wird ausgewertet (ob sich in einem Modul, oder nicht) ist ziemlich Komplex. Und seine Entwicklung das beste wäre, mit ZERLEGUNG in Funktionen und den Aufruf der jeweiligen Funktionen.

Helfen, lassen Sie mich Ihnen einige Kontext. Angenommen ich Baue ein web-framework. Der code geladen von der Datenbank-Handler für bestimmte URIs. Also, wenn ein HTTP-Aufruf kommt, könnte ich laden den code für example.com/blog/auf Dieser Seite kann auch bedeuten verschiedene Dinge, wie Kommentare, eine Liste der letzten Beiträge, etc.

Da viele Leute auf die Seite zur gleichen Zeit, ich bin erzeugen eines Prozesses zur Verarbeitung von jeder Seite anzeigen. So gibt es viele Male, wenn dieser code ausgewertet werden kann gleichzeitig für unterschiedliche Anforderungen.

Dem die Modul-Lösung erlaubt es, brechen Sie den code in Funktionen für die verschiedenen Teile der Seite (z.B.: die Liste der Beiträge, Kommentare, etc. ) Und ich würde laden Sie das Modul einmal, beim Start, und lassen Sie viele Prozesse spawnen, dass call-in-es. Das Modul global ist, richtig?

Was passiert, wenn es ein Modul ist bereits definiert? Beispiel: Wenn das Modul verpasst, und es gibt Prozesse fordern bereits, dass Modul.

In iex, ich bin in der Lage, neu zu definieren, ein Modul, das bereits definiert:

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

Was passiert, wenn ich definieren das Modul zur Laufzeit, zu allen Prozessen, die aktuell Berufung in das Modul? Auch wird diese Neudefinition der Arbeit außerhalb der iex im normalen Betrieb?

Unter der Annahme, dass die Neudefinition der module problematisch sein würde, und dass die Module global könnte Probleme mit Namespaces Kollisionen, schaute ich in die Verwendung von eval auf eine Funktion definieren.

Wenn ich kann lediglich den code aus der Datenbank-Funktionen definieren, dann sind diese Funktionen im Rahmen von was auch immer Prozess, und wir haben nicht die Möglichkeit, von globalen Zusammenstößen.

Jedoch, dies scheint nicht zu funktionieren:

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

Ich auch versucht:

    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

So, in Zusammenfassung:

  1. Können Module neu definiert werden, mithilfe von Code.eval, wenn es-Prozesse aufrufen, die in Ihnen?

  2. Ist es möglich mit Code.eval, um Funktionen, deren Umfang gebunden ist, ist der Prozess, in dem Code.eval aufgerufen wurde?

  3. Wenn Sie verstehen, was ich versuche zu tun, können Sie vorschlagen, eine bessere Art und Weise, darüber zu gehen?

Auch, wenn es ein besseres forum, wo ich sein sollte, Fragen Sie diese, fühlen Sie sich frei, mich wissen zu lassen. Und wenn es docs oder relevante Beispiele, die ich Lesen sollte, bitte fühlen Sie sich frei, um mich zu Ihnen. Ich versuche nicht, um Sie alle Arbeit tun, ich bin nicht in der Lage, um es herauszufinden selber.

Ich Lerne Elixier speziell für die Fähigkeit, dynamisch evlauate code, aber meine Elixir wissen ist minimal - ich habe gerade angefangen, - und meine erlang ist rusty zu.

Viel Dank!

InformationsquelleAutor nirvana | 2012-11-04
Schreibe einen Kommentar