clojure - 如何动态定义规范?

标签 clojure clojure.spec

我希望根据我从请求中提取的一些数据生成一组规范。我想根据我收到的数据动态定义一些规范。

(def my-key :frame-data/pretty_name) ;;imagine this and the validator aren't hardcoded
(def validator string?)
(s/def my-key validator?) ;; defines my-ns/my-key, instead of `:frame-data/pretty_name.
(s/describe my-key) ;; string? ;;which sorta works, but its looking up `my-ns/my-key` instead of :frame-data/pretty_name

我的目标是拥有一个看起来像我写的规范:

(s/def :frame-data/pretty_name string?)

我是 clojure 新手,所以我不太清楚如何做到这一点,但我尝试了一些方法:

(s/def (eval my-key) validator) ;;Assert Failed: k must be a namespaced keyword or resolveable symbol

(definemacro def-spec [key validator]
  '(s/def ~key ~validator))
(def-spec my-key validator) ;; my-ns/my-key ;; returns the same as earlier

还有很多变体,但我不确定如何动态定义规范,但感觉应该如此。

最佳答案

您可以在 clojure.spec.alpha/def 表单上执行宏扩展来查看它扩展为的内容:

(macroexpand `(s/def :frame-data/pretty_name string?))
;; => (clojure.spec.alpha/def-impl (quote :frame-data/pretty_name) (quote clojure.core/string?) string?)

或者查看source code clojure.spec.alpha/def

然后编写您自己的宏,不引用规范键以便对其进行评估:

(defmacro defspec [k spec-form]
  `(s/def-impl ~k (quote ~spec-form) ~spec-form))

示例:

(defspec my-key validator)

(s/valid? my-key "abc")
;; => true

(s/valid? my-key 123)
;; => false

(s/describe my-key)
;; => validator

如果您不喜欢 (s/de​​scribe my-key) 返回 validator,请尝试替换 (quote ~spec-form) 在宏定义中只用~spec-form,也许你会更喜欢这样。

关于clojure - 如何动态定义规范?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69197996/

相关文章:

clojure - 在 clj 文件中哪里可以指定 warn-on-reflection?

clojure - Clojure 是编译的还是解释的?

clojurescript - 当函数返回其符号时,如何从 var 中提取元数据?

Clojure 规范 "conformer"函数,它是什么?

function - Lisp 匿名函数局部变量

clojure - 为什么 clojure 中的许多函数对于列表和向量有不同的行为以及如何更改它?

clojure - 在 Clojure 中正确导入 Apache Storm 依赖项

clojure - 什么是 Clojure 规范?

clojure - 使用 Clojure Spec 从递归定义生成

Clojure:如何在全局范围内启用规范断言?