This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-07
Channels
- # beginners (73)
- # boot (20)
- # chestnut (8)
- # cider (36)
- # clara (37)
- # cljs-dev (21)
- # cljs-experience (1)
- # cljsrn (2)
- # clojure (163)
- # clojure-austin (3)
- # clojure-dusseldorf (6)
- # clojure-finland (1)
- # clojure-ireland (4)
- # clojure-italy (45)
- # clojure-russia (9)
- # clojure-spec (47)
- # clojure-uk (20)
- # clojurescript (107)
- # cursive (24)
- # data-science (4)
- # datomic (4)
- # defnpodcast (1)
- # fulcro (1)
- # heroku (3)
- # jobs-discuss (4)
- # juxt (52)
- # lein-figwheel (1)
- # leiningen (4)
- # lumo (37)
- # midje (5)
- # off-topic (16)
- # onyx (15)
- # portkey (11)
- # re-frame (112)
- # reagent (12)
- # rum (1)
- # specter (35)
- # uncomplicate (6)
Is there a version of s/or
that just conforms the value and doesn’t tell you what value it is? I have a map where certain entries can be either a string or a function that returns a string and I just want to get back either a conformed map or :cljs.spec.alpha/invalid
. Am I supposed to traverse the returned map and remove the named vectors?
(s/def ::key (s/or :int int? :str string?))
(s/conform ::key 1)
=> [:int 1]
(s/conform (s/nonconforming ::key) 1)
=> 1
(s/conform (s/nonconforming ::key) :foo)
=> :clojure.spec.alpha/invalid
@misha oh cool. so just call s/nonconforming
first?
Oh wait, s/nonconforming
says that it returns the original value. I want the conformed value though.
original is the original value, but a conformer function can return a modified value.
Well I was using all custom conformers. Writing separate functions like str-or-fn-ret-str
, but I realized I was duplicating a lot of code. Also, I think that requires me to write custom generators for everything.
It looks like (s/unform ::key (s/conform ::key val))
is working
Well, it’s actually string-or-react-class. Here’s what it looks like:
(defn string-or-react-class?
"Accepts either a string, react class, or a fn that returns a react class. If it's a fn, props will automatically
convert (js->clj) when the fn is called."
[s-or-c]
(cond
(helpers/is-react-class? s-or-c) s-or-c
(string? s-or-c) s-or-c
(fn? s-or-c) (fn [props & children]
(let [clj-props (js->clj props :keywordize-keys true)
react-c (s-or-c clj-props children)]
react-c))
:else :cljs.spec.alpha/invalid))
if you supply custom unformer - it might work. But I have a feeling you are doing something redundant
That’s what I was asking. If I do it as s/or
predicates I get back vectors
From my perspective, you conform to get back a vector, or a custom projection of the specced data.
If you want to know if something validates, you do (when (s/valid? ...) do), or one of the explain fns.
try to wrap s/or
in nonconforming
. this way you can have more granular conformer for just (fn? s-or-c)
case.
Okay. I’ll give that a shot. Thanks.
@seantempesta it seems like nonconforming or
prevents any conformation inside its branches
@seantempesta Can you talk more about why a call to conform
is useful in this case? If you just want the original value, could you just do something like (if (s/valid? ::string-or-int x) x :cljs.spec.alpha/invalid)
How do you prevent a :ret
spec to be described by doc
? I have a big spec and I’d like to be displayed by name rather than dumping it on the user. Currently I wrap it into spec/and
. Is there a more elegant solution?
then you’ll just see the name in the doc
I guess I don’t understand why that’s better
If I put it in only in the doc then it's not in the spec anymore. If I put it in doc and in spec it doesn't prevent doc
from dumping the whole description. So s/and
is the hack to have :ret spec'ed without doc being verbose
sorry. I went and tried it and I understand what you’re saying now. So the current behavior is not the intention. there is a ticket for the early aliased spec resolution, don’t know the #.
what is the best approach for validating a tuple that has optional fields? E.g. [:required :required :optional]
?
use (s/cat :a int? :b int? :c (s/? int?))
etc
ah thanks Alex, s/?
was the missing piece I was trying to find.
it’s like regex - s/* s/+ s/? s/cat s/alt
@alexmiller can you comment on @seantempesta's question, please?
what is a better way to do coercion with spec?
what is expected way to work with conformed compound values (map conformed to some the nested spec)? e.g. when you get map values as an or-conform-vector [:branch conformed-value]
. Is "conform-client" code supposed to know the spec structure, and be able to walk the conformed data structure?
don’t do coercion with spec
use conform to tell you how a value is parsed. then use clojure to transform that to what you want.
for the specific case of wanting to avoid conforming an s/or (one of the most common), spec as (s/def :foo (s/nonconforming (s/or :a int? :b string?)))
that is, use s/nonconforming at the leaves, not at the top
for this particular case, I’ve come to believe that nonconforming or is a reasonable use case and either we should keep s/nonconforming or add that as a variant/option on or
so, going back to Sean's example, conform map to spec (will return [:fn? s-or-c]
for some key), and then post-process conformed map with a coerce-function, which will replace [:fn? s-or-c]
with (fn [props & children] ...
?
without having completely read or grokked all of the backchat, sure
Clojure is like, pretty good at transforming data. use it.
I think the issue/question is: "should one wrap coerce-fn in s/conformer
and conform to that, or should one just apply coerce-fn after conforming data to simpler spec?"
the latter
if you do the former, you are registering specs that throw away information about the original value