This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-23
Channels
- # beginners (20)
- # boot (7)
- # cider (115)
- # cljsrn (13)
- # clojars (1)
- # clojure (122)
- # clojure-italy (23)
- # clojure-spec (60)
- # clojurescript (74)
- # data-science (7)
- # datomic (26)
- # emacs (8)
- # graphql (1)
- # lumo (26)
- # music (1)
- # off-topic (1)
- # re-frame (9)
- # ring (3)
- # rum (1)
- # spacemacs (4)
- # uncomplicate (6)
- # vim (7)
is there something like spec/or
that just takes a list of predicates rather than the k/v list?
i don't totally understand why spec/or
and spec/and
are different in this way
also, what's the best way to use spec to see if something only has a certain set of keys?
spec/or
takes a k/v list so that when you conform, you see which of the branches was taken
check out the “Composing predicates” here: https://clojure.org/guides/spec
this is not needed for s/and
, since there is no branching there (all predicates must be true)
checking that something only contains a certain set of keys is sort of against specs pricinples, since key sets are supposed to be open
@schmee i have a map that contains some keys that represent "machine data" like ids/references and some that represent "user data" which is what the user actually typed in
when an item has only machine data left in it i want to be able to clean it out of my db
because that item no longer represents anything useful to the user
so i want a spec that can tell when only machine keys are left
so it is open when adding, but closed when making a decision about whether to "clean up"
it's not that they're not allowed
i mean they are
but that's not the right way to think about it in context
i'm trying to detect something not restrict it
it's like
(if (spec/valid? :item/item--machine-only) (do ...) (do ...))
@schmee the extra keys are totally allowed but i do want to treat items that have only machine keys a bit differently
perhaps something like this would work?
(s/def ::machine-keys (s/keys :req [:a :b :c]]))
(s/def ::human-keys (s/keys :req [:d :e]]))
(s/def ::all-keys (s/merge ::machine-keys ::human-keys))
then you could validate thing separately when needed but still have a spec for the combination
@schmee the problem is that ::machine-keys
is valid when there are human keys too
and human keys is valid for machine keys
then do something like (and (s/valid? ::machine-keys foo) (not (s/valid? ::human-keys foo))
@schmee but then :f
would trigger
i actually do want my keys to be open
i don't want to have to stipulate every human key, and none of them are required, they're all optional, it's just important that there is at least one
@schmee also, when you're doing spec/or
and using keywords it still seems odd to force k/v
e.g. (spec/or :foo/bar :foo/bar :a/b :a/b)
e.g
dev=> (s/def ::test (s/or :foo keyword? :bar int?))
:dev/test
dev=> (s/conform ::test 1)
[:bar 1]
@schmee but if the branch is just a keyword that is already registered it already has a tag, so it could use that for error messages
hmmm how is it possible that
(valid? ::foo a)
and (valid? ::bar a)
are both true
but (valid? (spec/and ::foo ::bar) a)
is false?
it would be weird if there was a different syntax for registered keywords, better to have a uniform interface and accept the extra typing
@schmee mmk, any idea why spec/and
can be false when each of the individual items are true?
@schmee typo, it's all supposed to be a
boot.user=> (spec/valid? :item/item--exists {:item/project #uuid "4e2db038-f64d-4805-95cf-720e9e7f1419", :db/id 1, :item/title "85", :item/list-id {:db/id 10}})
true
boot.user=> (spec/valid? :item/item--user-input {:item/project #uuid "4e2db038-f64d-4805-95cf-720e9e7f1419", :db/id 1, :item/title "85", :item/list-id {:db/id 10}})
true
boot.user=> (spec/valid? (spec/and :item/item--user-input :item/item--exists) {:item/project #uuid "4e2db038-f64d-4805-95cf-720e9e7f1419", :db/id 1, :item/title "85", :item/list-id {:db/id 10}})
false
(spec/def :item/item--exists
(spec/and
:item/item
(comp #(spec/valid? :item/id--exists %) :db/id)))
(spec/def :item/item--user-input
(spec/and
:item/item
#(not (all-keys-in? % base-keys))))
(defn all-keys-in?
[coll allowed-keys]
(= #{}
(clojure.set/difference
(set (keys coll))
allowed-keys)))
but does it matter?
how can (and true true)
be false?
interestingly, {:item/project #uuid "4e2db038-f64d-4805-95cf-720e9e7f1419", :db/id 1, :item/title "85", :item/list-id {:db/id 10}}
was generated by exercise
for the spec/and
wait, that's a lie 😛
i generated it with slightly different code
hmmm, so if i do exercise for :item/item--exists
or :item/item--user-input
independently i can generate :item/list-id
but together i cannot