clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
Aron 2020-04-20T21:42:18.189700Z

so I am reading docs and I am sure I will figure this out too, but someone could help me here a lot with a shortcut to speccing a hashmap that has 3 levels, the first is a fixed set of keys, second also a fixed set of keys, and the third is depending on the key either a string or a vector of keywors. so a valid example would be {:firstlevelkey {:label "string" :fields [:fieldone :fieldtwo]}} and I just want to say that on the first level only certain keys are allowed( one predefined set of keywords), second level always have to be both a :label and :fields and label always have to be string and the :fields always needs to be a vector of keywords from another set of predefined keys

Aron 2020-04-20T21:42:49.190300Z

i don't need a full solution, just tell me please what to use so I can read up on those specifics because it's taking forever to sieve through 🙂

Aron 2020-04-20T21:43:27.190700Z

I am trying to google > clojure spec "-un" and it's not going well

Aron 2020-04-20T21:53:03.191200Z

the more I read the less I understand.

seancorfield 2020-04-20T22:06:41.192500Z

> I just want to say that on the first level only certain keys are allowed This isn't something Spec favors -- it follows the concept of "open for extension". So you will need additional predicates with s/and to restrict keys (and remember that it's not really "idiomatic" to do that).

Aron 2020-04-20T22:07:40.193500Z

Ok, good to know, so I won't force it if it's not expected

seancorfield 2020-04-20T22:11:41.197500Z

The whole spec is going to end up looking something like this:

(s/def :key/label string?)
(s/def :field/keys #{:fieldone :fieldtwo ,,,}) ; your set of predefined keys allowed
(s/def :key/fields (s/coll-of :field/keys :kind vector?)) ; maybe you want min and/or max counts too?
(s/def :second/level (s/keys :req-un [:key/label :key/fields]))
(s/def :top/keys #{:firstlevelkey ,,,}) ; available top-level keys
(s/def :top/level (s/map-of :top/keys :second/level))

seancorfield 2020-04-20T22:12:30.198400Z

If your set of keys isn't known at spec-time, it's a bit harder but that's probably a good first cut outline to start with.

Aron 2020-04-20T22:12:43.198800Z

it's known 🙂 luckily

seancorfield 2020-04-20T22:12:44.198900Z

(with better names, of course)

seancorfield 2020-04-20T22:13:23.200300Z

That actually solved the restricted set of top-level keys, but at the expense of not requiring a minimum set either.

Aron 2020-04-20T22:13:30.200500Z

the naming of keywords is arbitrary, right? so I could do just :label instead of :key/label, it just pays off to have very specific names of symbols so there is no collision?

seancorfield 2020-04-20T22:14:00.200900Z

Right. Qualified names help avoid collisions.

seancorfield 2020-04-20T22:14:46.201700Z

Only s/keys cares -- :req-un treats the qualified names as just their unqualified part (`:req` would pay attention to the qualifier as well).

Aron 2020-04-20T22:15:20.202Z

it's quite hard to grasp the pattern

Aron 2020-04-20T22:15:34.202300Z

I need to experiment with this, thank you very much

Aron 2020-04-20T22:17:40.203800Z

one more question that I think I know the answer for but still, if I want to spec anything, I always have to give a name to both the thing I want to spec and either use the definitions in place or create a named spec, right? So there is no way to write specs that would fit existing names automatically.

seancorfield 2020-04-20T22:21:43.204500Z

I'm not quite sure I'm following your question but I think the answer is "no, no way to do that in Spec 1".

seancorfield 2020-04-20T22:22:09.205200Z

Spec 2 does allow unqualified keys in a schema to have inline specs (predicates).

Aron 2020-04-20T22:22:52.206100Z

in app namespace I define something like (def whatever "string") and then in app.specs namespace I say (s/def whatever string?) and there is some magic to match them

Aron 2020-04-20T22:23:03.206500Z

probably a bad idea

seancorfield 2020-04-20T22:25:43.207200Z

Specs are in a completely separate "space" from regular Var names so you need to associate them yourself explicitly.

seancorfield 2020-04-20T22:26:03.207700Z

With functions, that's s/fdef but there's nothing for other Vars.

seancorfield 2020-04-20T22:26:22.208200Z

You need to use s/valid? or s/conform to "apply" a spec to a value at runtime.

seancorfield 2020-04-20T22:26:36.208500Z

(does that answer your question?)

Aron 2020-04-20T22:27:28.208700Z

yes : )