基本情况是这样的:我需要从数据库加载文本,然后打开该文本为药剂模块(或一个Erlang模块),然后拨打电话到它。 该文本实际上是相同的模块文件。 因此,这是热码负载的形式。 我要编译的“文件”,然后加载生成的模块,然后拨打电话到它。 后来我就卸载它。 唯一的区别是一个数据库,而不是磁盘上的文件存在的代码。 (和它不会在我正在写将加载它的代码的时间存在。)
我知道二郎支持热代码加载,但似乎集中在编制磁盘上的文件,然后加载横梁。 我希望这样做,因为一个更加动态的过程,我不会被替换的运行代码,但加载代码,然后运行它,然后卸载它。
有几个设施药剂在运行时评估代码。 我试图找出如何与他们做到这一点,该文档是有点稀疏。
Code.compile_string(string, "nofile")
“其中的第一个元素是模块名,第二个是其二进制返回元组的列表”。 所以,现在我拥有的这些模块的名称和它们的可执行文件,但我不知道的方式来然后加载到二进制运行时和调用到他们。 我会怎么做呢? (有针对的代码库,我可以看到没有作用。)
也许我可以再使用Erlang的功能:
:code.load_binary(Module, Filename, Binary) ->
{module, Module} | {error, What}
好了,所以这将返回与该原子“模块”,然后模块的元组。 如果从数据库加载字符串定义了一个名为“巴黎”模块,在我的代码我将如何再执行
paris.handler([parameters])
因为我不可能提前知道这样做会有一个叫做巴黎模块? 我能知道,通过具有字符串“巴黎”,也存储在数据库中,这是名字,但有叫成模块,使用字符串作为你调用该模块的名称的方法吗?
此外还有:
eval(string, binding // [], opts // [])
其分析字符串的内容。 这个字符串可以是一个模块的整个定义是什么? 好像还没有。 我希望能写出这样的代码,在这样的方式进行评估,它有相互调用多种功能 - 例如,一个完整的小程序,用一个预先定义的入口点(这可能是一个主要的,如为 “DynamicModule.handle([参数,列表])”
然后是的EEx模块,其中有:
compile_string(source, options // [])
这是伟大的做模板。 但最终似乎只对使用情况有一个字符串的工作,你已经有了嵌入了药剂代码。 它评估了选项的情况下串并产生一个字符串。 我正在寻找字符串编译成一个或多个功能,我可以再调用。 (如果我只能做一个功能的罚款,即功能模式匹配或者切换到这样做是需要的其他东西......)
我知道这是标新立异,但我有我的理由做这种方式,他们是好的。 我正在寻找关于如何做到这一点的建议,但不需要被告知“不这样做”。 现在看来似乎应该是可能的,二郎神支持热代码加载和药剂是非常动态的,但我只是不知道语法,或右功能。 我会密切关注这个问题。 提前致谢!
EDITS基于第一答案:
感谢您的答案,这是很好的进展。 成宥利则显示,EVAL可以定义一个模块,何塞指出,我可以只使用代码的eval与绑定的代码一小部分。
该代码被评估(是否变成了模块,或不)将是相当复杂的。 其发展将是最好的,涉及将它分解为功能和调用这些功能。
为了帮助,让我提供一些背景。 假设我建立一个Web框架。 从数据库加载中的代码是针对特定URI的处理程序。 所以,当一个HTTP电话打进来时,我可能会加载代码example.com/blog/此页面可能涉及到几个不同的东西,比如评论,最近发表的文章列表等。
由于很多人都打在同一时间的页面,我产卵的过程来处理每个页面视图。 因此,有很多时候此代码可以同时评价,对于不同的请求。
该模块解决方案允许一到了破解密码进入该页面的不同部分功能(例如:帖子列表,评论等),我要再次加载模块,在启动时,让很多进程都会产生这一呼吁进去。 该模块是全球性的,对不对?
如果有已定义的模块会发生什么? 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被称为功能呢?
如果你了解什么是我想要做的,你可以提出一个更好的路要走呢?
此外,如果有更好的论坛,我应该问这个,随时让我知道。 如果有文档或相关的例子我应该阅读,请随时点我给他们。 我不想让你做的所有工作,我只是一时无法找出自己。
我正在学习药剂专为能够动态evlauate代码,但我的药剂知识是最小的现在 - 我只是started-和我Erlang是生锈了。
非常感谢!