首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从地图注册clojure.specs

从地图注册clojure.specs
EN

Stack Overflow用户
提问于 2017-10-13 06:40:37
回答 1查看 403关注 0票数 3

我有一个clojure.specs映射,我想用它在运行时验证我的请求,如下所示:

代码语言:javascript
复制
{::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宏,并且在展开宏之前它不会将变量解析为值。

代码语言:javascript
复制
(doseq [[name spec] spec-map]
    (s/def name spec))

在将宏传递给s/def宏之前,我试着将宏创建到eval变量,但是这个宏在CompilerException java.lang.UnsupportedOperationException: Can't eval locals中失败了。

代码语言:javascript
复制
(defmacro reg-spec
  [name spec]
  `(s/def ~(eval name) ~(eval spec)))

(doseq [[name spec] spec-map]
    (reg-spec name spec))

我最后一次尝试的方法是在传递给s/def时使用eval变量,但这不能通过规范验证。

代码语言:javascript
复制
(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))

有什么办法实现我想做的事吗?还是我误解了什么明显的东西?任何帮助都是非常感谢的!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-10-13 07:06:12

你为什么不想通过s/def给这些规范取一个名字呢?规范的一个重要方面是强名称/命名空间名称。您的示例从某种意义上给出了它们的名称,但仅作为该地图中的键。我会把他们全都s/def的。我在上面的例子中修正了一些错误。您的地图键是命名空间的,所以s/keys应该使用:req而不是:req-un

代码语言:javascript
复制
(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]))

如果您需要,仍然可以构建您的规范映射,但是键/值将是相同的。

代码语言:javascript
复制
(s/conform :project-spec/project
           {:project-spec/id 1, :project-spec/name "123"})
;;=> {:project-spec/id 1, :project-spec/name "123"}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46723901

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档