Fork me on GitHub
#clojure-spec
<
2017-02-07
>
p-himik10:02:42

Is it possible, given some data, a keyword for its spec and a keyword for a simple spec that is a part of the data spec, extract all values conforming to the simple spec?

p-himik10:02:26

E.g. I have a map id->val and three specs - for id, for val and for the map itself. And I'd like to extract all vals from the map.

frank14:02:01

so not all of the map entries in this map conform to the map spec, but you want to find the ones that do?

ddellacosta20:02:58

how to specify a map that may be recursive?

joshjones21:02:51

actually, any map spec is recursive, since a map spec allows keys not specified in the spec

joshjones21:02:16

but for clarity's sake, you may want to put the spec name in the :opt portion of the map spec

ddellacosta21:02:45

it’s recursive perhaps, but not useful if it doesn’t validate anything about the map, is it?

joshjones21:02:03

it will validate anything given in :req etc

hiredman21:02:21

user=> (s/def ::foo (s/or :a number? :b ::bar))
:user/foo
user=> (s/def ::bar :req [::foo])
ArityException Wrong number of args (3) passed to: spec/def  clojure.lang.Compiler.macroexpand1 (Compiler.java:6832)
user=> (s/def ::bar (s/keys :req [::foo]))
:user/bar
user=> (s/valid? ::bar {::foo 1})
true
user=> (s/valid? ::bar {::foo {::foo 1}})
true
user=> (s/valid? ::bar {::foo {::foo :a}})
false
user=> 

ddellacosta21:02:39

as it is, I have

(s/or (s/map-of string? keyword?) (s/map-of string? map?))
but that is only recursing one level

ddellacosta21:02:04

@hiredman thanks, that looks like it

ddellacosta21:02:30

oh hrm maybe not with the map I have here

hiredman21:02:40

user=> (require '[clojure.spec :as s])
nil
user=> (s/def ::foo (s/map-of string? (s/or :value keyword? :rec ::foo)))
:user/foo
user=> (s/valid? ::foo {"a" :a})
true
user=> (s/valid? ::foo {"a" 1})
false
user=> (s/valid? ::foo {"a" {"b" :b}})
true
user=> 

joshjones21:02:51

you don't even need to do that

joshjones21:02:19

(s/def ::a string?)
(s/def ::mymap (s/keys :req [::a]))
(s/valid? ::mymap {::a "abc" ::mymap {::a "def" ::mymap {::a "xyz"}}})

ddellacosta21:02:50

that works if your keys are namespaced keywords

ddellacosta21:02:55

but I have string keys here

ddellacosta21:02:46

but, I’m filing all of this away for the time I do need such a construction…thanks @joshjones and @hiredman , very helpful

ag23:02:51

How do I generate map with keys and values that correspond to a given (s/keys) spec? let's say I have (s/keys :req-un [::id ::name] :opt-un [::money]) based on that I should generate vector like:

[{:id 1 :name "Greg" :money 0.02} {:id 2 :name “Alice”}]
upd: I actually want the keys to be randomly selected out of that spec, not precisely the same keys

hiredman23:02:28

having the same key in req and opt doesn't make sense

bfabry23:02:51

^ that is true

ag23:02:31

@hiredman sorry my mistake. fixed it

hiredman23:02:03

maybe close the paren too while you are at it

hiredman23:02:10

it depends sort of on what purpose you are generating them for, but if you generally just want to poke at them, exercise is a way to generate data for a give spec, s/keys created or otherwise

ag23:02:15

oh, I guess I got it all wrong… hold on..

ag23:02:03

I need to generate map where the keys are “randomly selected” out of the s/keys spec and the corresponding values also generated according to the spec

bfabry23:02:18

sounds like you want another s/keys spec with all the keys optional

ag23:02:16

well, can I read the keys out of the previously defined s/keys spec?