想象一下,动态生成了cat
的规范
[:first-name string? :surname string?]
现在我想将它们与cljs.spec.alpha/cat
一起使用。
在普通的Clojure中,我可以编写一个宏,该宏将用args构造一个宏并将其赋值,对吗?但是对于ClojureScript来说,它并不容易,因为macros
是编译时的野兽,而且eval
也是另一回事。
将我的args向量应用于ClojureScript中的宏的解决方法是什么?
答案 0 :(得分:2)
不幸的是,对于动态/数据驱动的规范来说,这并不容易,但是显然可以在将来的版本中使用。
我认为唯一的解决方法是eval
,或者使用您提到的cljs.spec.alpha内部实现。
cljs.user=> (def cat-args [:x string?])
#'cljs.user/cat-args
cljs.user=> (s/def ::foo (eval (cons 's/cat cat-args)))
:cljs.user/foo
cljs.user=> (s/conform ::foo '("foo"))
{:x "foo"}
答案 1 :(得分:2)
您的规范是在编译时以符号方式生成的吗?如果是这样,也许您可以按照建议使用宏。
(ns foo.core)
(defmacro gen-spec []
`'~(into '[:first-name string?] '[:surname string?]))
(defmacro apply-macro [name args-form]
`(~name ~@(eval args-form)))
这里是使用它的示例
$ clj -m cljs.main
ClojureScript 1.10.339
cljs.user=> (require '[clojure.spec.alpha :as s])
nil
cljs.user=> (require-macros 'foo.core)
nil
cljs.user=> (foo.core/gen-spec)
[:first-name string? :surname string?]
cljs.user=> (foo.core/apply-macro s/cat (foo.core/gen-spec))
{:cljs.spec.alpha/op :cljs.spec.alpha/pcat, :ps [#object[cljs$core$string_QMARK_] #object[cljs$core$string_QMARK_]], :ret {}, :ks [:first-name :surname], :forms [cljs.core/string? cljs.core/string?], :rep+ nil}
请注意gen-spec
是如何以符号形式建立规格并以引用形式返回的。