如何将 ClojureScript 函数序列化为 edn,然后反序列化并调用它们?
How to serialize ClojureScript functions to edn and then later deserialize and invoke them?
如果你像这样构造一个字符串
(def s (pr-str {:greet '(partial str "Hello" " " "World!")}))
如何使用 reader(即 read-string
)读取结构并将 :greet
键的值作为可以调用的函数拉回?
请注意,通过引用代码可以保留形状。如果我删除引号,它会序列化底层 javascript 函数的内容。我也尝试了反引号 (`)。
目标是能够保存用户在某些应用程序中构建的函数,将这些函数序列化为 edn,然后反序列化该文本,提取能够被调用的函数。
以上代码在调用时应该 return "Hello World!"。
安全问题可以单独解决。
您基本上可以使用相同的解决方案http://clojurescript.net/ is using - which is cljs-bootstrap使其工作。
演示:
我准备了a demo repository你可以克隆和运行。它包含一个简单的网页,其中包含您可以输入的内容,将对其进行实时评估。代码非常简短,因此应该易于理解并适应您的需求。它看起来像这样:
解决方案
第一步:得到cljs-bootstrap file compiled to JS。它包含我们将使用的 read_eval_print
方法。在加载已编译的 CLJS 文件之前,将此文件加载到 HTML 文件中。
第 2 步: 由于我们使用的是 JS,而不是正确的 CLJS 依赖项,我们可能需要 externs(即在高级编译模式下):
var cljs_bootstrap = {};
cljs_bootstrap.core = {};
cljs_bootstrap.core.read_eval_print = function() {};
记得将它们添加到您的 project.clj
。
第 3 步: read_eval_print
接受两个参数 - 第一个是带有 ClojureScript 代码的字符串,第二个是评估完成后将调用的回调。此代码将执行:
(let [code "(prn ((partial str \"Hello\" \"World\") \" :)\"))"
cljs (-> js/window .-cljs_bootstrap .-core)]
(.read_eval_print
cljs
code
(fn [success _] (prn "Success?" success))))
如您所见,实际上非常简单:
cljs
用于从window对象中获取read_eval_print
方法。那是因为我们将此文件导入为纯 JS 依赖项,而不是 CLJS 依赖项(这也是我们不需要 (:require)
任何东西的原因。
- callback 接受两个参数 - 第一个是布尔标志,如果代码有效并且可以被评估则设置为 true,否则为 false。第二个参数是一个错误。
此代码在浏览器中执行时会将其打印到 JS 控制台:
差不多就这些了。
几个笔记
- 将 cljs-bootstrap 用作 Clojure 依赖项会很棒,可以作为 Lein 依赖项,也可以仅通过复制所需的命名空间。由于时间不够,我没有这样做。它的工作原理应该是一样的,您只需
(:require)
即可。不过没时间玩。
- 当您加载演示页面时,它会显示一些 JS 加载错误(找不到文件)。那些其实可以忽略,CLJS 编译仍然有效。我没研究过。
如果你像这样构造一个字符串
(def s (pr-str {:greet '(partial str "Hello" " " "World!")}))
如何使用 reader(即 read-string
)读取结构并将 :greet
键的值作为可以调用的函数拉回?
请注意,通过引用代码可以保留形状。如果我删除引号,它会序列化底层 javascript 函数的内容。我也尝试了反引号 (`)。
目标是能够保存用户在某些应用程序中构建的函数,将这些函数序列化为 edn,然后反序列化该文本,提取能够被调用的函数。
以上代码在调用时应该 return "Hello World!"。
安全问题可以单独解决。
您基本上可以使用相同的解决方案http://clojurescript.net/ is using - which is cljs-bootstrap使其工作。
演示:
我准备了a demo repository你可以克隆和运行。它包含一个简单的网页,其中包含您可以输入的内容,将对其进行实时评估。代码非常简短,因此应该易于理解并适应您的需求。它看起来像这样:
解决方案
第一步:得到cljs-bootstrap file compiled to JS。它包含我们将使用的 read_eval_print
方法。在加载已编译的 CLJS 文件之前,将此文件加载到 HTML 文件中。
第 2 步: 由于我们使用的是 JS,而不是正确的 CLJS 依赖项,我们可能需要 externs(即在高级编译模式下):
var cljs_bootstrap = {};
cljs_bootstrap.core = {};
cljs_bootstrap.core.read_eval_print = function() {};
记得将它们添加到您的 project.clj
。
第 3 步: read_eval_print
接受两个参数 - 第一个是带有 ClojureScript 代码的字符串,第二个是评估完成后将调用的回调。此代码将执行:
(let [code "(prn ((partial str \"Hello\" \"World\") \" :)\"))"
cljs (-> js/window .-cljs_bootstrap .-core)]
(.read_eval_print
cljs
code
(fn [success _] (prn "Success?" success))))
如您所见,实际上非常简单:
cljs
用于从window对象中获取read_eval_print
方法。那是因为我们将此文件导入为纯 JS 依赖项,而不是 CLJS 依赖项(这也是我们不需要(:require)
任何东西的原因。- callback 接受两个参数 - 第一个是布尔标志,如果代码有效并且可以被评估则设置为 true,否则为 false。第二个参数是一个错误。
此代码在浏览器中执行时会将其打印到 JS 控制台:
差不多就这些了。
几个笔记
- 将 cljs-bootstrap 用作 Clojure 依赖项会很棒,可以作为 Lein 依赖项,也可以仅通过复制所需的命名空间。由于时间不够,我没有这样做。它的工作原理应该是一样的,您只需
(:require)
即可。不过没时间玩。 - 当您加载演示页面时,它会显示一些 JS 加载错误(找不到文件)。那些其实可以忽略,CLJS 编译仍然有效。我没研究过。