基本的なシナリオは次のとおりです。データベースからテキストをロードし、そのテキストを Elixir モジュール (または Erlang モジュール) に変換して呼び出しを行う必要があります。テキストは実質的にモジュール ファイルと同じです。したがって、これはホット コード ロードの一種です。「ファイル」をコンパイルしてから、結果のモジュールをロードし、それを呼び出します。後で荷降ろしします。唯一の違いは、コードがディスク上のファイルではなくデータベースに存在することです。(そして、それをロードするコードを書いている時点では存在しません。)
Erlang がホット コード ロードをサポートしていることは知っていますが、ディスク上のファイルをコンパイルしてからビームをロードすることに重点を置いているようです。これをより動的なプロセスとして実行したいと考えており、実行中のコードを置き換えるのではなく、コードをロードしてから実行し、アンロードします。
Elixir には、実行時にコードを評価するための機能がいくつかあります。私はそれらでこれを行う方法を理解しようとしていますが、ドキュメントは少しまばらです。
Code.compile_string(string, "nofile")
「最初の要素がモジュール名で、2 番目の要素がそのバイナリであるタプルのリストを返します」。これで、モジュール名とそのバイナリを取得できましたが、バイナリをランタイムにロードして呼び出す方法がわかりません。どうすればいいですか?(私が見ることができるコードライブラリにはそのための機能はありません。)
おそらく、Erlang 関数を使用できます。
:code.load_binary(Module, Filename, Binary) ->
{module, Module} | {error, What}
わかりました、これはアトム「モジュール」とモジュールのタプルを返します。データベースからロードされた文字列が「Paris」というモジュールを定義した場合、コードでどのように実行しますか
paris.handler([parameters])
parisというモジュールがあることを前もって知らないので?文字列「paris」もデータベースに保存することで、これが名前であることを知ることができましたが、呼び出しているモジュールの名前として文字列を使用して、モジュールを呼び出す方法はありますか?
もあります:
eval(string, binding // [], opts // [])
文字列の内容を評価します。この文字列をモジュールの定義全体にすることはできますか? そうではないようです。相互に呼び出す複数の関数を持つような方法で評価されるこのコードを記述できるようにしたいと考えています。たとえば、事前定義されたエントリ ポイント (メインなどの「DynamicModule.handle([パラメータ, リスト])」として
次に、EEx モジュールがあります。これには次のものがあります。
compile_string(source, options // [])
これは、テンプレートを作成するのに最適です。しかし、最終的には、文字列があり、Elixir コードが埋め込まれているユースケースでのみ機能するようです。オプションのコンテキストで文字列を評価し、文字列を生成します。文字列を、呼び出し可能な 1 つ以上の関数にコンパイルしようとしています。(問題のない関数を 1 つだけ作成できる場合、その関数はパターン マッチするか、必要な他のことを行うように切り替えることができます....)
これが型にはまらないことはわかっていますが、このようにする理由があり、それらは良いものです。これを行う方法についてアドバイスを探していますが、「そうしないでください」と言われる必要はありません。Erlang はホット コード ロードをサポートし、Elixir は非常に動的ですが、構文や適切な関数がわかりません。私はこの質問を注意深く監視します。前もって感謝します!
最初の回答に基づく編集:
答えてくれてありがとう、これは良い進歩です。Yuri が示したように、eval はモジュールを定義できます。また、José が指摘するように、コード eval はバインディングを含むコードの小さな部分に使用できます。
評価されるコードは (モジュールに変換されるかどうかにかかわらず) かなり複雑になります。そして、その開発は、それを関数に分解し、それらの関数を呼び出すことを含むのが最善です.
参考までに、いくつかのコンテキストを提供させてください。Web フレームワークを構築しているとします。データベースからロードされたコードは、特定の URI のハンドラーです。したがって、HTTP 呼び出しが着信すると、example.com/blog/ のコードをロードすることがあります。このページには、コメント、最近の投稿のリストなど、いくつかの異なる内容が含まれる場合があります。
多くの人が同時にページにアクセスしているため、各ページ ビューを処理するプロセスを生成しています。したがって、異なる要求に対して、このコードが同時に評価される場合が多くあります。
モジュール ソリューションを使用すると、コードをページのさまざまな部分 (例: 投稿、コメントのリストなど) の関数に分割できます。また、起動時にモジュールを 1 回ロードし、それを呼び出す多くのプロセスを生成します。それに。モジュールはグローバルですよね?
モジュールが既に定義されている場合はどうなりますか? EG: モジュールが変更され、そのモジュールを既に呼び出しているプロセスがある場合。
iex では、既に定義されているモジュールを再定義できます。
iex(20)> Code.eval "defmodule A do\ndef a do\n5\nend\nend"
nofile:1: redefining module A
そのモジュールを現在呼び出しているすべてのプロセスに対して、実行時にモジュールを再定義するとどうなりますか? また、この再定義は iex 以外の通常の操作で機能しますか?
モジュールの再定義には問題があり、モジュールがグローバルであると名前空間の衝突で問題が発生する可能性があると想定して、関数を定義するために eval を使用することを検討しました。
データベースからのコードで関数を定義するだけでよい場合、それらの関数はどのようなプロセスのスコープ内にもあり、グローバルな衝突の可能性はありません。
ただし、これは機能しないようです。
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
私も試しました:
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
つまり、要約すると:
モジュールを呼び出すプロセスがある場合、Code.eval を使用してモジュールを再定義できますか?
Code.eval を使用して、Code.eval が呼び出されたプロセスにスコープがバインドされた関数を作成することはできますか?
私がやろうとしていることを理解できたら、より良い方法を提案してもらえますか?
また、私がこれを尋ねるべきであるより良いフォーラムがあれば、遠慮なく私に知らせてください. また、読むべきドキュメントや関連する例があれば、遠慮なくそれらを教えてください。私はあなたにすべての仕事をさせようとしているわけではなく、自分でそれを理解することができません.
特にコードを動的に評価する機能のために Elixir を学んでいますが、Elixir の知識は今では最小限です。
どうもありがとう!