2

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

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

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

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

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

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

安全性可以单独解决。

4

1 回答 1

3

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

演示:

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

在此处输入图像描述

解决方案

第 1 步:获取编译为 JS 的 cljs-bootstrap 文件。它包含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))))

这实际上非常简单,如您所见:

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

此代码在浏览器中执行时会将其打印到 JS 控制台:

在此处输入图像描述

差不多就是这样。

几条笔记

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