Давайте посмотрим на реальный пример карт проекта Leiningen :global-vars
:
;; Sets the values of global vars within Clojure. This example
;; disables all pre- and post-conditions and emits warnings on
;; reflective calls. See the Clojure documentation for the list of
;; valid global variables to set (and their meaningful values).
:global-vars {*warn-on-reflection* true
*assert* false}
Это позволяет пользователю leiningen переопределить значения по умолчанию глобальных переменных Clojures для области своего проекта.
Теперь, если бы ключи этой карты состояли из ключевых слов, мы бы использовали clojure.spec/keys
, чтобы сначала указать, какие ключи могут быть частью карты, а затем отдельно определить значения, ожидаемые для этих ключей. Но поскольку clojure.spec/keys
молча игнорирует неключевые слова в :req
и :req-un
и выдает исключение для :opt
и :opt-un
(начиная с alpha15), нам придется каким-то образом обойти это.
Мы можем получить тип большинства этих глобальных переменных через
(for [[sym varr] (ns-publics 'clojure.core)
:when (re-matches #"\*.+\*" (name sym))]
[varr (type @varr)])
=>
[*print-namespace-maps* java.lang.Boolean]
[*source-path* java.lang.String]
[*command-line-args* clojure.lang.ArraySeq]
[*read-eval* java.lang.Boolean]
[*verbose-defrecords* java.lang.Boolean]
[*print-level* nil]
[*suppress-read* nil]
[*print-length* nil]
[*file* java.lang.String]
[*use-context-classloader* java.lang.Boolean]
[*err* java.io.PrintWriter]
[*default-data-reader-fn* nil]
[*allow-unresolved-vars* java.lang.Boolean]
[*print-meta* java.lang.Boolean]
[*compile-files* java.lang.Boolean]
[*math-context* nil]
[*data-readers* clojure.lang.PersistentArrayMap]
[*clojure-version* clojure.lang.PersistentArrayMap]
[*unchecked-math* java.lang.Boolean]
[*out* java.io.PrintWriter]
[*warn-on-reflection* nil]
[*compile-path* java.lang.String]
[*in* clojure.lang.LineNumberingPushbackReader]
[*ns* clojure.lang.Namespace]
[*assert* java.lang.Boolean]
[*print-readably* java.lang.Boolean]
[*flush-on-newline* java.lang.Boolean]
[*agent* nil]
[*fn-loader* nil]
[*compiler-options* nil]
[*print-dup* java.lang.Boolean]
а остальное мы можем заполнить, прочитав документы. Но мой вопрос к вам: как нам написать спецификацию, которая гарантирует, что если карта содержит ключ '*assert*
, она будет содержать только логические значения?