我有一个clojure.specs映射,我想用它在运行时验证我的请求,如下所示:
{::num-id int?
:project-spec/id ::num-id
:project-spec/name (s/and string? #((< (count %) 24)))
:project-spec/project (s/keys :req-un [:project-spec/id :project-spec/name])}我可以在运行时使用这些规范中的任何一个来使用s/valid?进行验证,但project-spec/project规范除外。这需要在全局规范注册中心中注册所有其他成员才能正常工作。当我尝试使用简单的doseq函数注册规范时,如果失败,因为我将局部变量传递给s/def宏,并且在展开宏之前它不会将变量解析为值。
(doseq [[name spec] spec-map]
(s/def name spec))在将宏传递给s/def宏之前,我试着将宏创建到eval变量,但是这个宏在CompilerException java.lang.UnsupportedOperationException: Can't eval locals中失败了。
(defmacro reg-spec
[name spec]
`(s/def ~(eval name) ~(eval spec)))
(doseq [[name spec] spec-map]
(reg-spec name spec))我最后一次尝试的方法是在传递给s/def时使用eval变量,但这不能通过规范验证。
(s/def (eval spec-name) (eval spec-spec))
CompilerException java.lang.AssertionError: Assert failed: k must be
namespaced keyword or resolvable symbol (c/and (ident? k) (namespace k))有什么办法实现我想做的事吗?还是我误解了什么明显的东西?任何帮助都是非常感谢的!
发布于 2017-10-13 07:06:12
你为什么不想通过s/def给这些规范取一个名字呢?规范的一个重要方面是强名称/命名空间名称。您的示例从某种意义上给出了它们的名称,但仅作为该地图中的键。我会把他们全都s/def的。我在上面的例子中修正了一些错误。您的地图键是命名空间的,所以s/keys应该使用:req而不是:req-un。
(s/def ::num-id integer?)
(s/def :project-spec/id ::num-id)
(s/def :project-spec/name (s/and string? #(< (count %) 24)))
(s/def :project-spec/project (s/keys :req [:project-spec/id :project-spec/name]))如果您需要,仍然可以构建您的规范映射,但是键/值将是相同的。
(s/conform :project-spec/project
{:project-spec/id 1, :project-spec/name "123"})
;;=> {:project-spec/id 1, :project-spec/name "123"}https://stackoverflow.com/questions/46723901
复制相似问题