I got a bit carried away experimenting with specs and I believe I might have hit a dead end unless spec can actually pick apart a string (like I could do with regex capturing groups or Instaparse). Can spec accomplish something like this contrived example?
(s/def ::title #{"mr" "mrs" "dr" ,,,})
(s/def ::surname #{"green" "brown" "who" ,,,})
(s/def ::title-surname (s/__ :title ::title :surname ::surname))
(s/conform ::title-surname "mrgreen") ;;alt1 => [:title "mr" :surname "green"]
(s/conform ::title-surname "mrsbrown") ;;alt2 => {:title "mrs" :surname "brown"}
@mokr The standard answer to this is: although you could, spec isn't designed for parsing strings
@borkdude Thanks, that settles it. I need to backtrack a bit.
I agree with @borkdude, spec isn’t the right tool for this, however I have done this kind of thing in past for fun:
(s/def ::title
(s/alt :mr (s/cat :m #{\m} :r #{\r})
:mrs (s/cat :m #{\m} :r #{\r} :s #{\s})
:dr (s/cat :d #{\d} :r #{\r})))
(s/def ::surname
(s/alt :green (s/cat :g #{\g} :r #{\r} :e #{\e} :e #{\e} :n #{\n})
:brown (s/cat :b #{\b} :r #{\r} :o #{\o} :w #{\w} :n #{\n})
:who (s/cat :w #{\w} :h #{\h} :o #{\o})))
(s/def ::title-surname
(s/cat :title ::title :surname ::surname))
(s/conform ::title-surname (seq "mrwho"))
;; => {:title [:mr {:m \m, :r \r}], :surname [:who {:w \w, :h \h, :o \o}]}
(s/conform ::title-surname (seq "mrsbrown"))
;; => {:title [:mrs {:m \m, :r \r, :s \s}], :surname [:brown {:b \b, :r \r, :o \o, :w \w, :n \n}]}
Does cljs.spec.test.alpha/check
generate bad input? I have a function spec that specifies a map for its input. gen/generate
and gen/sample
work fine.
But calling cljs.spec.test.alpha/check
fails with the error: More than one element found in structure
. And it looks like the spec system is generating incorrect input.
bar spec
(s/def ::check-run
(s/keys
:req-un
[::action
::check_run
::installation
::organization
::repository
::sender]))
foo.cljs
(s/def ::payload :bar/check-run)
(s/def ::check-run-started (s/keys :req-un [::payload]))
(s/fdef check-run->cijob-created
:args (s/cat :arg ::check-run-started))
(defn check-run->cijob-created [arg])
While the function spec only declares A, the spec system is generating B.
;; A
{:payload {:action "", :check_run {:html_url "", }}, ...}
;; B
[({:payload {:action "", :check_run {:html_url "", }}, ...}})]
workbench
(cljs.spec.test.alpha/check
`foo/check-run->cijob-created
{:clojure.spec.test.check/opts {:num-tests 10}})
[{:spec #object[cljs.spec.alpha.t_cljs$spec$alpha50916],
:clojure.spec.test.check/ret
{:shrunk
{:total-nodes-visited 313, :depth 148, :pass? false, :result #object[Error Error: More than one element found in structure: 0], :result-data #:clojure.test.check.properties{:error #object[Error Error: More than one element found in structure: 0]}, :time-shrinking-ms 11299,
:smallest
[({:payload {:action "", :check_run {:html_url "", }}, ...}})]},
:sym foo/check-run->cijob-created,
:failure #object[Error Error: More than one element found in structure: 0]}]