metosin / spec-tools

Clojure(Script) tools for clojure.spec
Eclipse Public License 2.0
592 stars 94 forks source link

Support for regex ops (s/*, s/?, s/+) in data specs, with encoding #146

Closed alza-bitz closed 5 years ago

alza-bitz commented 5 years ago

Hi there,

I was just wondering if the spec regex ops on sequences are supported? I am seeing some interesting results when I try and perform encoding.

For example, given the following example data specs:

(def sub-widget-a-spec
  (std/spec
   {:name ::sub-widget-a-spec
    :spec {:a-prop pos-int?}}))

(def sub-widget-b-spec
  (std/spec
   {:name ::sub-widget-b-spec
    :spec {:b-prop pos-int?}}))

(def sub-widget-c-spec
  (std/spec
   {:name ::sub-widget-c-spec
    :spec {:c-prop pos-int?}}))

(def widget-spec
  (std/spec
   {:name ::widget-spec
    :spec {:sub-widgets (s/cat :sub-widget-a (s/? sub-widget-a-spec)
                               :sub-widget-b (s/? sub-widget-b-spec)
                               :sub-widget-c (s/* sub-widget-c-spec))}}))

If I try and generate some sample data using the data spec, all is good and I see the regex op rules and ordering being adhered to for the sequence:

(gen/generate (s/gen widget-spec))
{:sub-widgets ({:a-prop 200} {:b-prop 165777148} {:c-prop 245783086} {:c-prop 796329} {:c-prop 58783983} {:c-prop 21259962} {:c-prop 2577} {:c-prop 2} {:c-prop 505012} {:c-prop 827210} {:c-prop 3} {:c-prop 277} {:c-prop 1519})}

However, if I then try to perform encoding, for example encoding to strings, I see inconsistent results - some data in the sequence is encoded correctly, but some is left as-is:

(st/encode widget-spec (gen/generate (s/gen widget-spec)) st/string-transformer)
{:sub-widgets ({:a-prop "1"} {:c-prop 2020} {:c-prop "4356"} {:c-prop "9"} {:c-prop "2"} {:c-prop "27"})}

I was wondering whether this should be expected to work or not? (since gen/generate works, it's just the encoding that doesn't and is therefore possibly a bug?)

Thanks!

alza-bitz commented 5 years ago

Hi again,

Whatever the underlying issue is, it seems to be affecting data-spec/or as well. For example, if I redefine widget-spec as:

(def widget-spec
  (std/spec
   {:name ::widget-spec
    :spec {:sub-widgets [(std/or 
                          {:sub-widget-a sub-widget-a-spec
                           :sub-widget-b sub-widget-b-spec
                           :sub-widget-c sub-widget-c-spec})]}}))

And try again:

(st/encode widget-spec (gen/generate (s/gen widget-spec)) st/string-transformer)

I get similar results:

{:sub-widgets [{:b-prop 228404} {:c-prop 766} {:c-prop 1} {:a-prop "1573"} {:c-prop 33686636}]}
alza-bitz commented 5 years ago

Since the data-spec/or issue is separate to the regex ops issue (and the results are slightly different), I've created a separate issue for that one: https://github.com/metosin/spec-tools/issues/147

alza-bitz commented 5 years ago

Fixed by #148.