This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-12-28
Channels
- # ai (1)
- # beginners (190)
- # boot (24)
- # cider (43)
- # cljsjs (3)
- # cljsrn (29)
- # clojars (6)
- # clojure (310)
- # clojure-dev (6)
- # clojure-nl (6)
- # clojure-russia (11)
- # clojure-spec (66)
- # clojure-uk (95)
- # clojurescript (103)
- # clojurewerkz (2)
- # core-async (9)
- # cursive (4)
- # datomic (5)
- # hoplon (163)
- # lein-figwheel (52)
- # off-topic (6)
- # om (6)
- # onyx (42)
- # perun (8)
- # re-frame (16)
- # reagent (10)
- # ring (7)
- # ring-swagger (1)
- # rum (1)
- # slack-help (2)
- # uncomplicate (1)
- # untangled (80)
I m thinking of doing the spec files into there own namespace like paintings.api-get-specs
Can I then in paintings.api-get use require to use api-get-specs and in api-get-specs require api-get
You'd usually keep Specs in the same namespace as the functions that use them so that the keywords in the specs are in the same namespace
oke, then I have to find a way to seperate the specs from the normal code. The file gets very big then ?
Shouldn't be that big
I find this one big : https://github.com/rwobben/paintings/blob/master/src/clj/paintings2/api_get.clj
@agile_geek Do you still think I can put all the specs into this one file ?
@roelofw why not?
That namespace isn't very big
I would keep specs together with fn's that use them and if the ns gets to big split them a different way. For example, you could split the fns that call the api from the functions that destructure the data from the calls if you wanted. However, at the moment that code is just a few fn's so I would just leave them together for now.
If you want put your specs at the top of the file and the fns after. If you want to separate with comments use ;;
not (comment ...)
as the first version is a better visual cue and it tends to highlight in different colours from a normal fn or macro in some editors which makes it stand out even more.
Something like that but most ppl reading it will have no problem separating the two anyway. Here's what I mean about highlighting comments.
What do I do here not right :
;; the specs files for input validation
(def id-regex #" [a-z]{2}-[a-z]-\d{1,2}")
(s/def ::id-type (s/and string? #(re-matches id-regex %)))
(s/def ::id ::id-type)
(s/def ::id-list (s/keys :req [::id]))
(defn read-numbers
"Reads the ids of the paintings"
[response]
(let [response-checked (s/conform ::id-list response)]
(response-checked)))
repl :
(read-numbers 1)
IllegalArgumentException Wrong number of args passed to keyword: :clojure.spec/invalid clojure.lang.Keyword.throwArity (Keyword.java:97)
(read-numbers "1")
IllegalArgumentException Wrong number of args passed to keyword: :clojure.spec/invalid clojure.lang.Keyword.throwArity (Keyword.java:97)
(read-numbers {:roelof 1})
IllegalArgumentException Wrong number of args passed to keyword: :clojure.spec/invalid clojure.lang.Keyword.throwArity (Keyword.java:97)
Your spec for ::id-list
says your argument has to be a vector of ::id
's
oke, but this is also not working :
IllegalArgumentException Wrong number of args passed to keyword: :clojure.spec/invalid clojure.lang.Keyword.throwArity (Keyword.java:97)
(read-numbers [:id 1])
IllegalArgumentException Wrong number of args passed to keyword: :clojure.spec/invalid clojure.lang.Keyword.throwArity (Keyword.java:97)
(read-numbers [1])
IllegalArgumentException Wrong number of args passed to keyword: :clojure.spec/invalid clojure.lang.Keyword.throwArity (Keyword.java:97)
Hmm, I miss read your code...
then I have to change the spec for id-list. It schould check for this [{ :id 1}{:id 2}]
Question: Why do you define ::id-type
and then redefine it unchanged as ::id
?
Not sure it's wrong but don't see the point
oke, I was doing that because I followed the spec guide guide : http://clojure.org/guides/spec#_entity_maps
Ah ok like I said don't think it's wrong
Break it down. Start by calling re-matches
on that regex with something you expect to pass.
looking at the regex it looks odd.
You are expecting a space as the first character? Is that correct?
no, I expect to validate this SK-C-5 so two characters , a - , one character , a - and then 1 or two numbers
OK so that regex looks wrong as it's got a space between the " and the [
Even after you correct that your spec is specifying that you pass a map as an argument and the map has a key of ::id
with a value that conforms to a string and the regex.
is that correct?
i.e. once you remove that space in the regex this will pass
(s/explain ::id-list {::id "aa-s-12"})
oke, I tried that in repl but saw something wierd :
(s/explain ::id-list {::id "aa-s-12"})
In: [:paintings2.api-get/id] val: "aa-s-12" fails spec: :paintings2.api-get/id-type at: [:paintings2.api-get/id] predicate: (re-matches id-regex %)
=> nil
(s/explain ::id-list {::id "aa-s"})
In: [:paintings2.api-get/id] val: "aa-s" fails spec: :paintings2.api-get/id-type at: [:paintings2.api-get/id] predicate: (re-matches id-regex %)
=> nil
It does fail - it will be in sys out
explain
prints to console
Start by just running the re-matches
i.e. (re-matches id-regex "aa-s-12")
see what that does and then try explaining the ::id-type
spec next and so on
one step at a time
Right which means your regex is not matching
as you should see the string again if there's a match
They both don't match
Your regex is wrong - did you remove the space?
Then your repl is probably confused and hasn't reloaded the pattern properly. Restart it and try again. As you can see @clojurebot thinks it's ok
Look at this as well:
(defn read-numbers
"Reads the ids of the paintings"
[response]
(let [response-checked (s/conform ::id-list response)]
(response-checked)))
see here :
(s/explain ::id-list {::id "aa-s-12"})
Success!
=> nil
(s/explain ::id-list {::id "aa-s"})
In: [:paintings2.api-get/id] val: "aa-s" fails spec: :paintings2.api-get/id-type at: [:paintings2.api-get/id] predicate: (re-matches id-regex %)
=> nil
What is response-checked? I.e. what type of thing and then look at what you do with it (response-checked)
Run s/conform
on a map that conforms and see what it does
Also remember that ::id
is a namespace qualified keyword, so you can't pass :id
you need to pass a fully qualified namespaced keyword. So if you namespace is paintings.api-get
you need to pass {paintings.api-get/id "aa-s-12"}
::id
is shorthand for <current-ns>/id
It's not expecting a vector of maps. Just a map
yep, see here :
=> :clojure.spec/invalid
(s/explain ::id-list [{:id "SK-C-5" :name "Roelof"}])
val: [{:id "SK-C-5", :name "Roelof"}] fails spec: :paintings2.api-get/id-list predicate: map?
OK so you need to change your spec defn
OK - I've got to go now but take it step at a time and try it out in repl using s/conform
or s/explain
Don't forget it's expecting a fully qualified id key
Can someone explain this :
(in-ns 'paintings2.api-get)
=> #object[clojure.lang.Namespace 0x171df08 "paintings2.api-get"]
(s/explain ::id-list [{:id "SK-C-5" :name "Roelof"}])
IllegalArgumentException Key must be integer clojure.lang.APersistentVector.invoke (APersistentVector.java:292)
(s/explain ::id-list [{paintings.api-get/id "aa-s-12"}])
CompilerException java.lang.ClassNotFoundException: paintings.api-get, compiling:(C:\Users\rwobb\AppData\Local\Temp\form-init8511580151742996713.clj:1:1)
here more examples where I cannnot see what im doing wrong ?
(s/explain ::id-list {:id 1 })
val: {:id 1} fails spec: :paintings2.api-get/id-list predicate: (contains? % :paintings2.api-get/id)
=> nil
(s/explain ::id-list [{paintings.api-get/id "aa-s-12"}])
CompilerException java.lang.ClassNotFoundException: paintings.api-get, compiling:(C:\Users\rwobb\AppData\Local\Temp\form-init3968416759727215223.clj:1:1)
(s/explain ::id-list {paintings.api-get/id "aa-s-12"})
CompilerException java.lang.ClassNotFoundException: paintings.api-get, compiling:(C:\Users\rwobb\AppData\Local\Temp\form-init3968416759727215223.clj:1:1)
I already switched to the right namespace :
(in-ns 'paintings2.api-get)
=> #object[clojure.lang.Namespace 0x171df08 "paintings2.api-get"]
@dpsutton thanks. Now this problem :
(s/explain ::id-list {paintings2.api-get/id "aa-s-12"})
CompilerException java.lang.RuntimeException: No such var: paintings2.api-get/id, compiling:(C:\Users\rwobb\AppData\Local\Temp\form-init5817193040681417679.clj:1:1)
because your reader is saying No such var: paintings2.api-get/id
. So go investigate and see if you are wrong or it is wrong
but agile-geek says this :
Also remember that `::id` is a namespace qualified keyword, so you can't pass `:id` you need to pass a fully qualified namespaced keyword. So if you namespace is `paintings.api-get` you need to pass `{paintings.api-get/id "aa-s-12"} ::id` is shorthand for `<current-ns>/id
I missed the :
It's a keyword
@agile_geek @dpsutton then I see the same error :
(s/explain ::id-list {paintings2.api-get/:id "aa-s-12"})
CompilerException java.lang.RuntimeException: No such var: paintings2.api-get/:id, compiling:(C:\Users\rwobb\AppData\Local\Temp\form-init5817193040681417679.clj:1:1)
@dpsutton you are correct
@dpsutton thanks, this is working (s/explain ::id-list {:paintings2.api-get/id "aa-s-12"})
:my-namespace/id
is fully namespaces kw
If you reference ::id
inside the NS my-namespace
you get same thing
Namespaces keywords are used to give context and avoid name clashes
So u can have :ns1/id
and :ns2/id
and they are different
You can see with a common name like id
why that might be useful
time for a break and then trying to find out how to change this : (s/def ::id-list (s/keys :req [::id]))
Yes and you can use id
in addresses, person, car, etc
This might help you think about how you name namespaces too
One tip I give ppl is "every developer spends over 80% of their time reading and comprehending code not writing it so optimise for readability". That means formatting matters, naming matters and following common ideoms matters too. All those things allow the reader to shortcut some comprehension. I can write all my English sentences without punctuation but they'd be hard to read!
yes. I have someone is the family which is not using punctuation and now capital characters and that is not nice to read
I try with my code to be as clear as possible to other knows what the code does and for myself when I see the code after some months I still know what the code does exactly
Why can the id not be found here :
(s/def ::id ::id-type)
(s/def ::id-list (s/coll-of
(s/keys :req-un [::id])
:kind vector?))
it fails with this message : In: [0] val: #:paintings2.api-get{:id "aa-s-12"} fails spec: :paintings2.api-get/id-list predicate: (contains? % :id)
if i'm reading this correctly, can you tell me what part of "aa-s-12" would have the key :id
?
here are all the specs :
(def id-regex #"[a-z]{2}-[a-z]-\d{1,2}")
(s/def ::id-type (s/and string? #(re-matches id-regex %)))
(s/def ::id ::id-type)
(s/def ::id-list (s/coll-of
(s/keys :req-un [::id])
:kind vector?))
also, your id-list spec is just saying it expects a vector of maps with an unqualified keyword :id
found it . This works
def id-regex #"[a-z]{2}-[a-z]-\d{1,2}")
(s/def ::id-type (s/and string? #(re-matches id-regex %)))
(s/def ::id ::id-type)
(s/def ::id-list (s/coll-of
(s/keys :req [::id])
:kind vector?))
it works fine as far as I can see :
(s/explain ::id-list [{:paintings2.api-get/id "wont conform"}])
In: [0 :paintings2.api-get/id] val: "wont conform" fails spec: :paintings2.api-get/id-type at: [:paintings2.api-get/id] predicate: (re-matches id-regex %)
but one think I do not understand. I have this function :
(defn read-numbers
"Reads the ids of the paintings"
[response]
(let [response-checked (s/conform ::id-list response)]
(response-checked)))
and then I see this error : ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429)
I have another problem . I now have to use ::id but the reponse which I want to input validated has [{:id "xxxx"}]
so or I have to rewrite the specs or parse the response first to have :paintings2.api-get/id
instead of just :id
or is there another way to describe a vector of maps , where a map has a key named :id
Use :req-un
in your spec — for required, unqualified.
You have :req
which means required, qualified.
@seancorfield thanks