Fork me on GitHub
#beginners
<
2017-01-06
>
richiardiandrea01:01:20

Noob question, when using xml zippers, is there a way to create programmatically a root node? Can't seem to find one

richiardiandrea01:01:33

I tried: (data-xml/element :root {} (map zip/node (dzx/xml-> family-loc :resource)))

dpsutton01:01:21

(xml-zip root) Returns a zipper for xml elements (as from xml/parse), given a root element

dpsutton01:01:24

does that not work?

richiardiandrea01:01:15

no I mean, I have already the bits and pieces from the zippers, I want to combine stuff together, but I need a root

dpsutton01:01:25

oh you have a forest of nodes?

dpsutton01:01:29

and need to combine them?

richiardiandrea01:01:40

yep I am trying now -> (zip/make-node family-loc (dx/element :root {} {}) (dzx/xml-> family-loc :resource))

richiardiandrea01:01:32

the above makes it almost right, if only there was only one contect vector and not a vec of vec

dpsutton01:01:03

(apply data-xml/element :root {} (map (.....))?

richiardiandrea01:01:17

aaaand....the winner is: (zip/make-node family-loc (dx/element :root) (map zip/node (dzx/xml-> family-loc :resource)))

vandr0iy08:01:16

why doesn't this work:

(let [func #(println "raboof")
      jb   (defrecord Foo []
             org.quartz.Job
             (execute [_ _] (func)))]
... ;stuff
)
=> CompilerException java.lang.RuntimeException: Unable to resolve symbol: func in this context, compiling:(/tmp/form-init7561963032470631764.clj:4:29) 

roelof08:01:11

why do I see here

(s/with-gen get-objectNumbers
 (fn [] (gen/sample (gen '/string-from-regex #"[A-Z]{2}-[A-Z]-\d{1,4}")))) 

roelof08:01:29

this message : Unmatched delimiter: )

roelof08:01:45

I checked several times and all the ) seems to match

delaguardo09:01:35

@vandr0iy maybe because defrecord generate class and must be compiled before func appears. you can try reify instead of defrecord

vandr0iy09:01:52

'/string-from-regex <- typo?

vandr0iy09:01:16

@delaguardo unfortunately, that's not an option - quartz, in order to schedule a task, must define a class that implements the org.quartz.Job interface with the stuff to do to be placed in the execute method; then, whenever it wants to schedule that job it extends that class... friggin Java """""design patterns"""""

roelof09:01:36

I was a typo and a forgotten namespace import

roelof09:01:16

I have this spec : (s/def ::objectNumber (s/and string? #(re-matches #"[A-Z]{2}-[A-Z]-\d{1,4}" %)))

roelof09:01:46

and this generator :

(s/with-gen ::objectNumber
 (fn [] (gen/sample (gen'/string-from-regex #"[A-Z]{2}-[A-Z]-\d{1,4}"))))  

roelof09:01:22

which produces this output :

[clojure.spec$and_spec_impl$reify__13956 
 17955548 
 "clojure.spec$and_spec_impl$reify__13956@111fadc"]  

roelof09:01:31

which looks good to me

roelof09:01:53

but when I do : (s/exercise ::objectNumber)

roelof09:01:16

I see this output : ExceptionInfo Couldn't satisfy such-that predicate after 100 tries

roelof09:01:38

Can someone give me a hint what is going wrong ?

agile_geek09:01:37

@roelofw the generator is randomly producing strings and then checking that they conform to your spec. Given enough time it would generate some that do but it gives up after 100 tries. You need to write a custom generator for that spec as it's too specific for the generic one to cope with. Try reading this: http://clojure.org/guides/spec#_custom_generators

agile_geek09:01:32

BTW scroll up from that heading in the page and you will see an example of a similar exception and an explanation of why it happened.

roelof09:01:39

yep, that is why I tried to write a custom generator with the help of test.chuck

roelof09:01:35

so my custom generator is not doing what its supposed to do

roelof09:01:47

back to that part and read it another time

agile_geek09:01:41

Haven't used test.chuck so I suggest you read the readme and try some very simple examples first. Might give you a clue. Always start by simplifying the problem and take it step at a time.

roelof09:01:11

oke, I will, I checked the anymous function and that one worked fine

roelof09:01:46

so I think I did something wrong with the with-gen part

roelof09:01:57

seancorfield said I have to use this template : (s/with-gen my-spec (fn [] the-generator)) `

roelof09:01:44

I think my-spec is here : ::objectNumber

roelof09:01:20

and the generator schould be (gen/sample (gen'/string-from-regex #"([A-Z]{2}-[A-Z]-\d{1,4})"))

roelof09:01:05

back to the manual

roelof10:01:16

last question

roelof10:01:27

I have this

(s/def ::objectNumber2
 (s/with-gen ::objectNumber
  (fn [] (gen/sample (gen'/string-from-regex #"([A-Z]{2}-[A-Z]-\d{1,4})"))))) 

roelof10:01:54

is now ::objectNumber2 the name of the generator ?

magnars10:01:50

I'm keeping a registry of processes in an atom. However, you're not supposed to perform side-effects in a swap!, so this code is no good:

(swap! processes #(if (get % id) % (assoc % id (create-process! id))))
How would I go about doing this correctly?

roelof11:01:17

When I do (s/exercise ::objectNumber) or (s/exercise ::objectNumber2) I see this message : AssertionError Assert failed: Second arg to such-that must be a generator

roelof11:01:02

so I wonder what is here the name of the generator :

(s/def ::objectNumber2
 (s/with-gen ::objectNumber
  (fn [] (gen/sample (gen'/string-from-regex #"([A-Z]{2}-[A-Z]-\d{1,4})"))))) 

roelof11:01:27

I suspect ::objectNumber2 but that one also error out

roelof12:01:23

@magnars what do you want to do exactly ?

magnars12:01:30

@roelof I want to start one and only one process (specifically a core.async go-loop) per id.

roelof12:01:52

@magnars maybe start with the if then ?

magnars12:01:23

Moving the if outside the swap! would only add another race condition to the mix.

roelof12:01:24

hmm, then I have at this moment, no idea

magnars12:01:47

Thanks for giving it some thought anyways. 🙂

madstap15:01:05

@roelof gen/sample takes a generator and returns some samples generated from it. It does not return a generator. The anonymous fn needs to return a generator.

roelof15:01:38

oke, back to the manual how to do that

roelof15:01:56

@madstap any tips/hints

roelof15:01:42

I think I missed this part : #(s/gen ?

madstap15:01:01

@roelof hint: gen'/string-from-regex does return a generator

madstap15:01:50

@roelof "I think I missed this part : #(s/gen ?" No, s/gen is for getting a generator from a spec. You already have the generator from the call to string-from-regex.

roelof15:01:08

Thanks for the tip. This is working :

(s/def ::objectNumber
 (s/with-gen ::objectNumber
  (fn [] (gen'/string-from-regex #"([A-Z]{2}-[A-Z]-\d{1,4})")))) 

Alex Miller (Clojure team)15:01:52

the custom generator should not use sample

Alex Miller (Clojure team)15:01:21

(sorry, reading backchat out of order - looks like you’re there)

roelof16:01:43

another problem : when I do (s/explain :artObject/response (get-data-detail-page ( get-artObject ( read-json-data "SK-C-5" )))

roelof16:01:20

I see this error : RuntimeException EOF while reading, starting at line 1

roelof16:01:45

I tried this (get-data-detail-page ( get-artObject ( read-json-data "SK-C-5" )))

roelof16:01:50

and that worked fine

madstap16:01:18

That first snippet is missing a closing paren

roelof16:01:13

thanks, I overlooked it when I was checking that one

henriklundahl16:01:17

@magnars Here's an idea for how you can accomplish what you want: 1. Try to add the process id to processes with a unique number as value. 2. Outside the swap!, create the process, if the process id was added. 3. Exchange the random number with the result from create-process!.

roelof16:01:10

Can I make a spec that I want to have a number between let's say 1900 - 2017 ?

magnars16:01:09

@henriklundahl: thanks, that sounds like it would work. 👍

seancorfield17:01:30

@roelof: (s/int-in 1900 2018)

roelof17:01:41

he, I thought you were not on slack this weekend

roelof17:01:20

with a little help I got the generator works for objectNumber and most of the specs

roelof17:01:29

@belucid : how is the show going ? I know this is offtopic

roelof17:01:11

@seancorfield how is the show going ? I know this is offtopic

seancorfield17:01:38

I'm not at my computer. On my phone. Short replies. Show starts in a few hours, 100 miles from home 😸

roelof17:01:14

oke, success and I take care that on Monday my github is up-to-date

joelmiller17:01:48

Alright I’ve got a silly question

joelmiller17:01:22

Trying to open package manager with M-x by pressing command + x

joelmiller17:01:54

Taking me to the last character of my buffer but not opening the command window as I would hope

seancorfield17:01:01

M-x is option-x or alt-x (on Mac). The command-x key is S-x in Emacs speak.

joelmiller17:01:02

Turns out it’s the option key 😁

roelof18:01:51

I have made this function

(s/fdef get-objectNumbers
 :args (s/cat :response :artObject/response)
 :ret (s/coll-of ::objectNumber)) 

roelof18:01:03

and made this generator :

(s/def ::objectNumber
 (s/with-gen ::objectNumber
  (fn [] (gen'/string-from-regex #"([A-Z]{2}-[A-Z]-\d{1,4})")))) 

roelof18:01:38

now I want to test it so I did : (stest/check 'get-objectNumbers)

roelof18:01:01

but then I see this as output ()

roelof18:01:42

when I do this : (stest/check ::objectNumber)

roelof18:01:11

I get as message : IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Keyword

roelof18:01:54

Can anyone give me a hint which part I do not understand of the clojure spec guide

seancorfield18:01:38

stest/check works on "vars (functions) named by symbols" which is why that second call fails — ::objectNumber is a keyword, not a symbol.

seancorfield18:01:31

Try

(stest/check `get-objectNumbers)
(backtick, not quote) or
(stest/check ‘paintings2.api-get/get-objectNumbers)
as stest/check requires a fully-qualified symbol name.

seancorfield18:01:54

(don’t forget to keep your GitHub repo up-to-date @roelof so folks can always see your latest code, when you need help)

roelof18:01:43

the first one gives this as answer :

({:clojure.spec.test.check/ret {:num-tests 1000, 
                                :seed 1483727820434, 
                                :result true}, 
  :sym paintings2.api-get/get-objectNumbers, 
  :spec [clojure.spec$fspec_impl$reify__14282 
         7640208 
         "clojure.spec$fspec_impl$reify__14282@749490"]})   

roelof18:01:55

which seems good

roelof18:01:39

the second one gives almost the same :

({:clojure.spec.test.check/ret {:num-tests 1000, 
                                :seed 1483727903786, 
                                :result true}, 
  :sym paintings2.api-get/get-objectNumbers, 
  :spec [clojure.spec$fspec_impl$reify__14282 
         7640208 
         "clojure.spec$fspec_impl$reify__14282@749490"]})  

seancorfield18:01:14

:thumbsup::skin-tone-2: Often easiest to call (stest/summarize-results (stest/check ‘my-ns/my-fn)) to get sane results back. Failures produce very large output otherwise.

seancorfield18:01:16

For example:

user=> (require '[clojure.spec :as s])
nil
user=> (require '[clojure.spec.test :as stest])
nil
user=> (defn foo [n] (inc n))
#'user/foo
user=> (s/fdef foo :args (s/cat :n int?) :ret int?)
user/foo
user=> (stest/summarize-results (stest/check 'user/foo))
{:sym user/foo}
{:total 1, :check-passed 1}
user=> (defn foo [n] "Boom!")
#'user/foo
user=> (s/fdef foo :args (s/cat :n int?) :ret int?)
user/foo
user=> (stest/summarize-results (stest/check 'user/foo))
{:spec (fspec :args (cat :n int?) :ret int? :fn nil),
 :sym user/foo,
 :failure
 {:clojure.spec/problems
  [{:path [:ret], :pred int?, :val "Boom!", :via [], :in []}],
  :clojure.spec.test/args (0),
  :clojure.spec.test/val "Boom!",
  :clojure.spec/failure :check-failed}}
{:total 1, :check-failed 1}

roelof18:01:18

@seancorfield thanks, that produces this : {:check-passed 1, :total 1}

roelof18:01:50

so it seems my get-objectNumbers works well

roelof18:01:30

my first test written in spec 🙂

roelof18:01:47

Does this :num-tests 1000, means there are 1000 tests done

roelof18:01:57

then the test are very fast

seancorfield18:01:04

Yes, for small, simple functions, generative testing is pretty quick.

seancorfield18:01:51

Behind the scenes, it is generating 1,000 pieces of data that conforms to the :args spec and then calling the function for each piece, and then verifying the :ret (and :fn) spec.

seancorfield18:01:49

(this is part of clojure.test.check behind the scenes — adapted from Haskell’s QuickCheck — and the real power behind clojure.spec for testing)

roelof18:01:11

thanks for the explanation. That was one of the things I liked about haskell QuickCheck

roelof19:01:31

This weekend I can now write the last fdef and test everything 🙂

roelof19:01:07

and then think about how to make it work. I see a pagination with page-numbers

roelof19:01:22

and my first project is done 🙂

roelof19:01:12

Is it normal with proto-repl that it takes multiple minutes to get in a state where I can work on it

roelof19:01:02

I have this file ( https://github.com/rwobben/paintings/blob/master/src/clj/paintings2/api_get.clj ) in my project and if I start up repl it looks like proto-repl is not responding at all

roelof19:01:31

This is happening since I added a spec test

seancorfield19:01:07

Sounds like you still have some of the “reload” options enabled?

roelof19:01:31

I have these all disabled

roelof19:01:12

I just checked it

adamkowalski20:01:07

Whats the recommended way of actually using your function specs. Do you just use instrument? Is there a way to actually check the :fn and :ret portions, or is there something else?

roelof20:01:04

I use instrument to test the input parameters , this uses only the :args part

roelof20:01:15

after that I write the rest and use (stest/summarize-results (stest/check namespace/function)) to test if the function does what I expect. Herefore I only use the :args` and :ret part because I have very small functions

adamkowalski20:01:34

how would you specify that both arguments are both extend a protocol, and have the same type just using :args

roelof20:01:41

@adamkowalski I hope this makes something clear for you

adamkowalski20:01:02

like if I want to write an append function, that can work with two vectors, lists, sets, or hash maps

adamkowalski20:01:12

but I want them to be the same type

adamkowalski20:01:23

pairs of vecs, etc...

roelof20:01:28

That question I cannot help you, Im also learning spec and tests

adamkowalski20:01:08

I guess I could put it as a precondition right? just say that they must have the same type

roelof20:01:08

I think you can put that in the fn . but I can be mistaken as I said earlier im also learning specs and spec testing

roelof20:01:45

I hope some more experienced person in spec can answer that

roelof20:01:53

im sorry I cannot help you more

adamkowalski20:01:03

(s/fdef append
        :args (s/cat :a coll? :b coll?)
        :fn (fn [{:keys [args ret]}]
              (let [{:keys [a b]} args]
                (= (type a) (type b) (type ret))))
        :ret coll?)

adamkowalski20:01:08

thats what I was thinking

adamkowalski20:01:36

but instrument doesn’t seem to check either fn or ret

roelof20:01:09

correct, as far as I know instrument looks only at the `:args

roelof20:01:36

instrument is as far as I know be used to check if the right parameters are used

Alex Miller (Clojure team)21:01:03

@adamkowalski to specify a relationship between args, just s/and an additional predicate to the :args spec

Alex Miller (Clojure team)21:01:26

like (s/fdef append :args (s/and (s/cat :a coll? :b coll?) (fn [{:keys [a b]}] (= (type a) (type b)))))

Alex Miller (Clojure team)21:01:48

if you want to specify a relationship between args and ret, then that needs to be in :fn

Alex Miller (Clojure team)21:01:05

putting it in :args has the benefit of being checked by instrument

adamkowalski21:01:25

oh yeah that makes things a lot easier

adamkowalski21:01:35

thanks for the tip

adamkowalski21:01:52

I have another question however

adamkowalski21:01:43

Could specs potentially replace protocols? Or I mean, can they provide the same functionality that they can provide?

adamkowalski21:01:21

Instead of specifying that something extends a protocol, could you just continually compose specs and accomplish something similar

roelof21:01:44

@alexmiller Are you a atom user ?

rgorrepati21:01:25

why does this throw an exception? (def c (chan 10)) (>!! c 20) (alts!! [(timeout 2000) c])

rgorrepati21:01:53

. Unhandled java.lang.NoSuchMethodError clojure.core.async$do_alts$fn__12286.<init>(Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V

Alex Miller (Clojure team)21:01:49

@rgorrepati I can’t repro that - I get [20 #object[clojure.core.async.impl.channels.ManyToManyChannel 0x2026efb8 “clojure.core.async.impl.channels.ManyToManyChannel@2026efb8”]] - a value and the channel c

rgorrepati21:01:39

@alexmiller sorry, may be something weird with my nrepl