ClojureScript 中的 eval-str 以 public 结构作为参数
eval-str in ClojureScript with public structure as a parameter
我的问题需要将自定义逻辑函数应用于结构。这些函数作为字符串存储在数据库中。我有这样的数据:
(def fruits {:apple {:color "red" :ripe? true}
:strawberry {:color "red" :ripe? false}})
我有这个条件检查:
"(some (fn [fruit] (-> fruit val :ripe? false?)) fruits)"
不幸的是,即使我尝试了各种方法,我也无法做到这一点:
1)
(cljs/eval-str (cljs/empty-state)
"(some (fn [fruit] (-> fruit val :ripe? false?)) my.main/fruits)"
""
{:eval cljs/js-eval}
identity)
这有效但会产生错误:
WARNING: No such namespace: my.main, could not locate my/main.cljs, my/main.cljc, or Closure namespace "" at line 1
WARNING: Use of undeclared Var my.main/fruits at line 1
而且这种方法在高级编译中显然行不通。
2) 我尝试利用在 Clojure 中有效的方法:
((eval
(read-string
"(fn [fruits]
(some (fn [fruit] (-> fruit val :ripe? false?)) fruits))"))
fruits)
我不明白为什么这在高级编译中不起作用。不幸的是,它每次都只是 returns nil
。
是只有我没有想出解决方案还是 CLJS 还没有能力做到这一点?
我怀疑您将很难通过以下方式实现您的要求
这种方法。大问题可能是由于方式
clojurescirpt 需要编译成 javascript(使用 Google 闭包)。你
可能可以让它工作 用外部设备做一些聪明的事情并使用低
级别 javascript 互操作和闭包库,但我怀疑它会很难
工作。
可能值得考虑的几种替代方法
- 将数据以edn格式存储在数据库中。使用 edn,您可以
把它读入一个var然后执行它
- 改变方向 - 你真的需要存储完整的功能吗?
而是定义一种 DSL 类型,它从数据库中获取参数
将提供必要的动态执行级别。
- 你能有某种预处理解决方案吗,即将函数写在
clojurescript,但使用闭包功能将其编译为 javascript 和
将其插入数据库而不是原始 clojurescript。这个会
使数据的初始存储更加复杂,但可以简化调用
运行时的动态函数。您甚至可以包括一些代码检查或
验证以减少从数据库中获取代码的可能性
错了。
使用完全动态的代码有很多风险,几乎
从来没有一个好的解决方案。除了您遇到的众多安全问题
这种做法,你还得优雅地处理出现的处理问题
来自被插入数据库的错误定义(即错误函数
使您的应用程序崩溃或损坏数据的定义。如果你只需要拥有
动态执行未知代码的能力,那么至少 edn 提供了一些
使用 eval-str 无法获得额外的保护 - 但实际上,不要这样做
它。
经过数小时的实验并努力从字符串中评估函数,我决定编写 DSL。
在数据库中,我使用包含这些参数的映射存储字符串:
- :在哪里? - 包含所需答案路径的矢量。
- :什么? - 我正在寻找的答案。
- :严格? (可选)- 一个布尔值。如果为真,则答案需要与
:what?
规则完全相同(顺序无关紧要)。
然后我只评估那个简单的 cljs 文件。它适用于 advanced
和 none
优化模式。
(defn standard-cond-met? [{:keys [what? where? strict?]
:or {strict? false}}]
(let [answer (get-in answers (conj where? :values))]
(if strict?
(= (sort what?) (sort answer))
(clojure.set/subset?
(set what?)
(set answer)))))
我的问题需要将自定义逻辑函数应用于结构。这些函数作为字符串存储在数据库中。我有这样的数据:
(def fruits {:apple {:color "red" :ripe? true}
:strawberry {:color "red" :ripe? false}})
我有这个条件检查:
"(some (fn [fruit] (-> fruit val :ripe? false?)) fruits)"
不幸的是,即使我尝试了各种方法,我也无法做到这一点:
1)
(cljs/eval-str (cljs/empty-state)
"(some (fn [fruit] (-> fruit val :ripe? false?)) my.main/fruits)"
""
{:eval cljs/js-eval}
identity)
这有效但会产生错误:
WARNING: No such namespace: my.main, could not locate my/main.cljs, my/main.cljc, or Closure namespace "" at line 1
WARNING: Use of undeclared Var my.main/fruits at line 1
而且这种方法在高级编译中显然行不通。
2) 我尝试利用在 Clojure 中有效的方法:
((eval
(read-string
"(fn [fruits]
(some (fn [fruit] (-> fruit val :ripe? false?)) fruits))"))
fruits)
我不明白为什么这在高级编译中不起作用。不幸的是,它每次都只是 returns nil
。
是只有我没有想出解决方案还是 CLJS 还没有能力做到这一点?
我怀疑您将很难通过以下方式实现您的要求 这种方法。大问题可能是由于方式 clojurescirpt 需要编译成 javascript(使用 Google 闭包)。你 可能可以让它工作 用外部设备做一些聪明的事情并使用低 级别 javascript 互操作和闭包库,但我怀疑它会很难 工作。
可能值得考虑的几种替代方法
- 将数据以edn格式存储在数据库中。使用 edn,您可以 把它读入一个var然后执行它
- 改变方向 - 你真的需要存储完整的功能吗? 而是定义一种 DSL 类型,它从数据库中获取参数 将提供必要的动态执行级别。
- 你能有某种预处理解决方案吗,即将函数写在 clojurescript,但使用闭包功能将其编译为 javascript 和 将其插入数据库而不是原始 clojurescript。这个会 使数据的初始存储更加复杂,但可以简化调用 运行时的动态函数。您甚至可以包括一些代码检查或 验证以减少从数据库中获取代码的可能性 错了。
使用完全动态的代码有很多风险,几乎 从来没有一个好的解决方案。除了您遇到的众多安全问题 这种做法,你还得优雅地处理出现的处理问题 来自被插入数据库的错误定义(即错误函数 使您的应用程序崩溃或损坏数据的定义。如果你只需要拥有 动态执行未知代码的能力,那么至少 edn 提供了一些 使用 eval-str 无法获得额外的保护 - 但实际上,不要这样做 它。
经过数小时的实验并努力从字符串中评估函数,我决定编写 DSL。
在数据库中,我使用包含这些参数的映射存储字符串:
- :在哪里? - 包含所需答案路径的矢量。
- :什么? - 我正在寻找的答案。
- :严格? (可选)- 一个布尔值。如果为真,则答案需要与
:what?
规则完全相同(顺序无关紧要)。
然后我只评估那个简单的 cljs 文件。它适用于 advanced
和 none
优化模式。
(defn standard-cond-met? [{:keys [what? where? strict?]
:or {strict? false}}]
(let [answer (get-in answers (conj where? :values))]
(if strict?
(= (sort what?) (sort answer))
(clojure.set/subset?
(set what?)
(set answer)))))