clojure.spec - Realistic Clojure Spec for function with named arguments -


say have function clothe requires 1 positional argument person in addition number of optional named arguments :hat, :shirt , :pants.

(defn clothe [person & {:keys [hat shirt pants]}]   (str "clothing " person " " hat shirt pants ".")) (clothe 'me :hat "top hat") => "clothing me top hat." 

my current way of writing spec function be:

(require '[clojure.spec     :as spec]          '[clojure.spec.gen :as gen])  (spec/def ::person symbol?) (spec/def ::clothing   (spec/alt :hat   (spec/cat :key #{:hat}   :value string?)             :shirt (spec/cat :key #{:shirt} :value string?)             :pants (spec/cat :key #{:pants} :value string?)))  (spec/fdef clothe            :args (spec/cat :person  ::person                            :clothes (spec/* ::clothing))            :ret string?) 

the problem being allows argument lists like

(clothe 'me :hat "top hat" :hat "nice hat") => "clothing me nice hat." 

which though allowed language mistake whenever made. perhaps worse makes generated data unrealistic how function called:

(gen/generate (spec/gen (spec/cat :person  ::person                                   :clothes (spec/* ::clothing)))) => (_+_6+h/!-6gg9!43*e :hat "m6vqmor72cxc6r3gp2hcdb5a0"     :hat "05g5884ablc80s4af5x9v84u4rw" :pants "3q" :pants "a0v329r25f3k5oj4uzjjqa5"     :hat "c5h2hw34lg732ifpqdieh" :pants "4aebas8uwx1eqwyplrezbir" :hat "c229mzw"     :shirt "hgw3eguzkf7c7ya6q2fqw249gsb" :pants "byg23h2xymtx0p7v5ve9qbs"     :shirt "5wpmjn1f2x84lu7x3ctfalpknq5" :pants "0m5tbghq4lr489j55atm11f3"     :shirt "fkn5vmjoiayo" :shirt "2n9xkcibh66" :hat "k8xsfeydf" :hat "sqy4iupf0ef58198270dof"     :hat "ghgeqi58a4ph2s74t0" :pants "" :hat "d6rkwjjoflcaahid8af4" :pants "exab2w5o88b"     :hat "s7ti2cb1f7se7o86i1ue" :shirt "9g3k6q1" :hat "slkjk67608y9w1sqv1kxm"     :hat "cfbvmaq8bfp22p8cd678s" :hat "f57" :hat "2w83oa0wvwm10y1u49265k2bjx"     :hat "o6" :shirt "7buj824efbb81rl99zbrvh2hjziit") 

and worse of all, if happen have recursive defenition spec/* there no way of limiting number of potentially recursive occurences generated when running tests on code.

so question becomes: there way specify named arguments function limiting number of occurences per key one?

if @ way require macro specced in clojure.core.specs can see uses (spec/keys* :opt-un []) specify named arguments in dependency list, such :refer , :as in (ns (:require [a.b :as b :refer :all])).

(s/def ::or (s/map-of simple-symbol? any?)) (s/def ::as ::local-name)  (s/def ::prefix-list   (s/spec     (s/cat :prefix simple-symbol?            :suffix (s/* (s/alt :lib simple-symbol? :prefix-list ::prefix-list))            :refer (s/keys* :opt-un [::as ::refer]))))  (s/def ::ns-require   (s/spec (s/cat :clause #{:require}                  :libs (s/* (s/alt :lib simple-symbol?                                    :prefix-list ::prefix-list                                :flag #{:reload :reload-all :verbose}))))) 

the documentation doesn't mention :req-un , :opt-un for, spec guide on other hand mentions specifying unqualified keys. returning our function defenition write as:

(spec/def ::clothing (spec/keys* :opt-un [::hat ::shirt ::pants])) (spec/def ::hat   string?) (spec/def ::shirt string?) (spec/def ::pants string?) (spec/fdef clothe            :args (spec/cat :person  ::person                            :clothes ::clothing)            :ret string?) 

sadly doesn't function accepting multiple instances of same named argument

(stest/instrument `clothe) (clothe 'me :hat "top hat" :hat "nice hat") => "clothing me nice hat." 

though mean generator maximally produces 1 instance of same key recursive specs.

(gen/generate (spec/gen (spec/cat :person ::person                                   :clothes ::clothing))) => (u_k_p6!!?4ok!_i.-.d!2_.t-0.!+h+/at.7r8z*6?qb+921a     :shirt "b4w86p637c6kak1rv04o4frn6s" :pants "3gdkiy" :hat "20o77") 

Comments

Popular posts from this blog

commonjs - How to write a typescript definition file for a node module that exports a function? -

openid - Okta: Failed to get authorization code through API call -

ios - Change Storyboard View using Seague -