Spec overrides and aliases
I ran into a counter-intuitive issue. Do I understand it correctly that overriding Clojure spec generators using the clojure.spec.alpha/gen overrides keyword isn’t working with aliases specs?
(ns raszi.spec-overrides
(:require
[clojure.spec.alpha :as s]
[clojure.test.check.generators :as gen]))
(def spec-test (s/with-gen string?
#(gen/elements #{"foo" "bar" "foobar"})))
(s/def ::test spec-test)
(s/def ::alias spec-test)
(s/def ::other-alias ::test)
(s/def ::map (s/keys :req-un [::test
::alias
::other-alias]))
(comment
(gen/generate (s/gen ::test))
(gen/generate (s/gen ::map))
(gen/generate (s/gen ::map {::test #(gen/elements #{"FOO" "BAR" "FOOBAR"})})))
I would not expect the ::other-alias spec to be overridden by the overrides attribute.This is a known issue: https://clojure.atlassian.net/browse/CLJ-2079
The workaround I use is to s/def the aliased specs by wrapping the aliased keyword in s/spec, as described in this comment: https://clojure.atlassian.net/browse/CLJ-2079?focusedCommentId=47742
(s/def ::test (s/spec spec-test))
(gen/generate (s/gen ::map {::test #(gen/elements #{"FOO" "BAR" "FOOBAR"})}))
=> {:test "FOO", :alias "foobar", :other-alias "FOO"}I see, thank you for the explanation! I am glad that I got the intentions right and this is an actual issue.
I refactored the code to have the definitions with def-s and the usages with s/def. I guess we can revert the change after this gets fixed.
If ever, since it is almost a 5 years old issue.
I guess your suggestion would be:
(s/def ::other-alias (s/spec ::test))And that seems to be working
I’ve created this small repro case here: https://github.com/raszi/spec-overrides
Is this a bug or I actually need to define this re-usable specs using def instead of s/def?
By doing that the code gets much-much more complicated and other features won’t be supported. 😞
The worst part here, is that you cannot add an override on the aliased spec name only on the original.