如何将ClojureScript函数序列化为edn然后反序列化并调用它们?

时间:2016-02-06 23:11:33

标签: clojure clojurescript edn

如果你构造一个像这样的字符串

(def s (pr-str {:greet '(partial str "Hello" " " "World!")}))

如何使用阅读器(即read-string)读取结构并将:greet键的值作为函数拉回来,而不是可以调用?

请注意,通过引用代码,它会保留形状。如果我删除引号,它会序列化底层javascript函数的内容。我也尝试了反击(`)。

目标是能够保存用户在某个应用程序中构建的函数,将这些函数序列化为edn然后反序列化该文本,拉出能够被调用的函数。

上面的代码应该返回" Hello World!"在被调用时。

安全性可以单独解决。

1 个答案:

答案 0 :(得分:3)

您可以使用http://clojurescript.net/正在使用的相同解决方案使其工作 - 基本上是cljs-bootstrap

演示:

我准备了a demo repository你可以克隆并运行。它包含一个简单的网页,其中包含您可以输入的输入,这些输入将进行实时评估。代码非常简短,因此应该易于遵循并适应您的需求。它看起来像这样:

enter image description here

解决方案

第1步:获取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控制台:

enter image description here

那就是它。

很少注意到

  • 将cljs-bootstrap用作Clojure依赖关系,无论是作为Lein依赖还是仅通过复制所需的命名空间,都很棒。由于时间不够,我没有这样做。它应该工作相同,你只需(:require)它。虽然我没有时间玩它。
  • 当您加载演示页面时,它会显示一些JS加载错误(找不到文件)。实际上可以忽略这些,CLJS编译仍然有效。我没有调查过。