【问题标题】:How to serialize ClojureScript functions to edn and then later deserialize and invoke them?如何将 ClojureScript 函数序列化为 edn,然后反序列化并调用它们?
【发布时间】:2016-02-15 21:09:00
【问题描述】:

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

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

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

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

目标是能够保存用户在某些应用程序中构建的函数,将它们序列化到 edn,然后反序列化该文本,提取能够被调用的函数。

上面的代码应该返回“Hello World!”调用时。

可以单独解决安全问题。

【问题讨论】:

标签: clojure clojurescript edn


【解决方案1】:

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

演示:

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

解决方案

第 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 用于从窗口对象中获取read_eval_print 方法。这是因为我们将该文件作为纯 JS 依赖项导入,而不是 CLJS 依赖项(这也是我们不需要 (:require) 任何东西的原因。
  • callback 接受两个参数 - 第一个是一个布尔标志,如果代码有效并且可以评估,则设置为 true,否则为 false。第二个参数是一个错误。

这段代码在浏览器中执行时会打印到 JS 控制台:

差不多了。

几点说明

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

【讨论】:

  • 哇。感谢您为此付出了如此多的精力。
  • @mario 不客气。有趣的问题,解决它很有趣:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多