我试图处理以下DSL:
(simple-query
(is :category "car/audi/80")
(is :price 15000))
非常流畅,所以我又添加了一个东西 - 传递给查询的选项:
(simple-query {:page 1 :limit 100}
(is :category "car/audi/80")
(is :price 15000))
现在我有一个问题,如何以最文明的方式处理这个案子。正如您所看到的,simple-query
可能会将哈希映射作为第一个元素(后面跟着很长的条件列表),或者根本没有哈希映射选项。此外,我希望将默认值作为默认选项集,以防在查询中没有提供明确的部分(或全部)选项。
这就是我想到的:
(def ^{:dynamic true} *defaults* {:page 1
:limit 50})
(defn simple-query [& body]
(let [opts (first body)
[params criteria] (if (map? opts)
[(merge *defaults* opts) (rest body)]
[*defaults* body])]
(execute-query params criteria)))
我觉得它有点乱。任何想法如何简化这种结构?
答案 0 :(得分:2)
为了在我自己的代码中解决这个问题,我有一个方便的功能,我希望你能见到...... take-when
。
user> (defn take-when [pred [x & more :as fail]]
(if (pred x) [x more] [nil fail]))
#'user/take-when
user> (take-when map? [{:foo :bar} 1 2 3])
[{:foo :bar} (1 2 3)]
user> (take-when map? [1 2 3])
[nil [1 2 3]]
因此我们可以使用它为您的可选地图第一个参数...
实现解析器user> (defn maybe-first-map [& args]
(let [defaults {:foo :bar}
[maybe-map args] (take-when map? args)
options (merge defaults maybe-map)]
... ;; do work
))
因此,就我而言,您提出的解决方案或多或少都有点,我只是通过将解析器分解为抓取选项图(这里是我的take-when
帮助器)来清理它。并将默认值合并到自己的绑定语句中。
一般情况下,使用动态var存储配置是一种反模式,因为在懒惰地评估时可能存在错误行为。
答案 1 :(得分:1)
这样的事情怎么样?
(defn simple-query
[& body]
(if (map? (first body))
(execute-query (merge *defaults* (first body)) (rest body))
(execute-query *defaults* body)))