Fork me on GitHub
#beginners
<
2016-12-23
>
seancorfield00:12:40

@johnmarinellii The next time you do pretty much anything with Leiningen, it will update. You rarely need to run lein deps these days.

seancorfield00:12:18

If you start a REPL via lein repl or “jacking in” from Emacs or another editor, that should trigger the update.

johnmarinellii00:12:47

@seancorfield ok that’s what i had thought - however when i launch a cider nrepl instance from emacs i get WARNING: CIDER's version (0.8.1) does not match cider-nrepl's version (0.9.0)

seancorfield00:12:34

Have you tried lein repl outside Emacs?

ballpointcarrot01:12:40

@johnmarinellii based on that error, it may be that you need to update cider in emacs - nrepl is reporting 0.9.0, but cider says 0.8.1

johnmarinellii01:12:17

@ballpointcarrot , that….makes sense. ty 🙂

johnmarinellii01:12:53

(realizing i should have just read the error message)

seancorfield01:12:32

I can never remember which way round that error message works!

mss02:12:24

is there an idiomatic way to turn a java exception into a clojure data structure?

mss02:12:52

calling stacktrace.root-cause with my throwable seems to return a data structure closer to what I want, but I can’t figure out how to pull any values off of the returned object

dpsutton04:12:05

and just a heads up, CIDER is 0.14 on stable and 0.15 on melpa. and it now handles its nrepl dependency so you can remove that from your profile file if/when you update

roelof06:12:37

@seancorfield I think im bitten by this :

(or "2" 1)
=> "2"  

roelof06:12:58

the url parameter is a string where the api needs a integer

roelof06:12:13

so I need to do :

(or (read-string"2") 1)
=> 2 

roelof06:12:04

and that was the culprit

roelof06:12:30

I only need to do some check if the string contains a number

roelof06:12:43

and not a smaller then 1 and bigger then 470

seancorfield07:12:33

read-string is a bit of a sledgehammer to crack a nut because it will read any Clojure expression and potentially execute code.

seancorfield07:12:12

If you're expecting an integer, you're much safer using (or (Long/parseLong x) 1)

seancorfield07:12:56

that will only convert a string into a long (integer), without the risk of executing any code, or it will throw an exception if it is given anything other than a numeric string.

roelof07:12:36

I think I have to write my own validation function so I can check these conditions

roelof07:12:58

1) if there are no url parameters . the outcome will be 1

roelof07:12:45

2) if there are url parameters, i could convert it with (or (Long/parseLong x) 1)

roelof07:12:11

3) the outcome of 2 must be between the 1 and 470

seancorfield07:12:27

You might be at a point where clojure.spec is useful...

roelof07:12:27

can spec do input validation ??

seancorfield07:12:29

(require '[clojure.spec :as s])
(s/conform (s/int-in 1 471) page)
checks 1 <= page < 471

seancorfield07:12:54

We have specs for all our APIs, that accept strings that can be conformed to numbers in particular ranges

seancorfield07:12:56

(defn ->long [s] (try (Long/parseLong s) (catch Exception _ ::s/invalid)))
(s/def ::page (s/and ->long (s/int-in 1 471)))
That will conform strings to integers in the range 1..470, or else produce something you can check with s/invalid?

roelof07:12:36

oke, but what if a user enters /page="a" . I think spec does the nothing ?

roelof07:12:01

I still have to handle the case of wrong input , Right ?

seancorfield07:12:26

(let [page-num (s/conform ::page page)] (if (s/invalid? page-num) (handle-the-error) (use-the-number page-num)))

seancorfield07:12:38

You always have to handle invalid input somehow.

seancorfield07:12:58

(you'll need something slightly different to handle nil in amongst all this)

roelof07:12:08

I can use that in the code ?

roelof07:12:36

oke, I think I have to dive in spec

seancorfield07:12:59

Hmm, the above isn't quite right but it should point you in the right direction...

roelof07:12:31

@seancorfield does spec work in 1.8 ?

seancorfield07:12:37

Well, there's a backport library for it... but we're using Clojure 1.9 Alpha 14 in production already...

seancorfield07:12:28

boot.user=> (require '[clojure.spec :as s])
nil
boot.user=> (defn ->long [s] (try (Long/parseLong s) (catch Exception _ ::s/invalid)))
#'boot.user/->long
boot.user=> (s/def ::page (s/and (s/conformer ->long) (s/int-in 1 471)))
:boot.user/page
boot.user=> (s/def ::optional-page (s/nilable ::page))
:boot.user/optional-page
boot.user=> (let [page nil page-num (or (s/conform ::optional-page page) 1)] page-num)
1
boot.user=> (let [page "42" page-num (or (s/conform ::optional-page page) 1)] page-num)
42
boot.user=> (let [page "a" page-num (or (s/conform ::optional-page page) 1)] page-num)
:clojure.spec/invalid
boot.user=> (let [page "500" page-num (or (s/conform ::optional-page page) 1)] page-num)
:clojure.spec/invalid
Something like that... You can test (if (s/invalid? page-num) (bad-stuff) (good-stuff page-num))

roelof07:12:58

thanks maybe time for a upgrade

seancorfield07:12:37

We're using spec pretty heavily in production. 1.9 is basically 1.8 + spec so the core is the same.

roelof10:12:55

@seancorfield oke, one question : Can I also make a spec for a function that take a clojure object and filter some things out of it. Things like name and so on ?

roelof10:12:09

and thanks for the examples. I think I can made my code working with it

agile_geek13:12:43

@roelofw yes you can define data structures in Spec.... that's its whole raison d'etre

roelof15:12:51

oke, so I can make a spec to test this function :

(defn read-numbers

  "Reads the ids of the paintings"

  [response]

  (->> (:body response)

       :artObjects

       (map :objectNumber)))  

roelof15:12:04

oke, slack messed up the indentation again

roelof16:12:31

I think I can do it like this one :

def email-regex #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$")
(s/def ::email-type (s/and string? #(re-matches email-regex %)))

(s/def ::acctid int?)
(s/def ::first-name string?)
(s/def ::last-name string?)
(s/def ::email ::email-type)

(s/def ::person (s/keys :req [::first-name ::last-name ::email]
                        :opt [::phone]))  

dpsutton16:12:11

just ask people that are in this channel. you don't need to ping specific people

roelof18:12:49

one thing what is not clear to me. Do I have to place the specs in the test directory or only the (s/test .... ) and the rest in the same file as the code I want to test

kevinbheda18:12:49

I’m in a similar situation where i need to do this. I know this is a hack but is there any alternative way of doing it? http://stackoverflow.com/questions/27652176/clojure-is-it-possible-to-execute-multiple-expressions-in-a-cond-case

(cond
  (> a 0) (when true
            (println a)
            (println (* a a))
 :else (str "do nothing")
            ))

`

olslash18:12:06

ive had the same question, using cond to ie put something on a channel conditionally

olslash18:12:19

i ended up using do when multiple clauses were needed

olslash18:12:32

doesnt really feel right

seancorfield18:12:27

@roelof For your purposes, it’s probably easier to put the specs in the source files, but in general “it depends” — at World Singles, we tend to have specs in separate namespaces (but still in the source tree) since we are mostly specifying data structures, rather than functions.

seancorfield19:12:55

You also have the option of running different kinds of tests. If you spec your functions, you can have your test code call s/instrument to add spec-based instrumentation while you are running your tests: that will verify that functions are called with correct arguments (but that doesn’t check results, nor the “invariants” of the functions). You can also use clojure.spec.test/check to have Clojure generate (conforming) test data for you and exercise your function with lots of example data.

seancorfield19:12:30

In addition, you can use spec directly in your source code to validate arguments and conform input data to your specified model.

seancorfield19:12:55

clojure.spec brings a lot of power and a lot of features so there’s a lot to learn about using it — but it’s definitely worth the effort.

roelof19:12:26

@seancorfield oke, so I can use spec to test my read-data function I post earlier

roelof19:12:59

I could then test parameters and I want to test if the function works well

roelof19:12:45

So I have then to use s/instrument and 'clojure.spec.test/check` if I understand you right

roelof19:12:49

I have googled but not much info about this subject with examples

sveri19:12:47

@roelof It is not even a year old / in the public. This guide: http://clojure.org/guides/spec is pretty good 🙂

roelof19:12:34

yep, I read that a few times

roelof19:12:14

so I found there a example how I could make tests for the read-data functions and the others that I use

roelof19:12:55

and if I understand it right, I could use them the same as I run the normal code

roelof19:12:34

@sveri it looks to me that spec could be a the testing/validation platform for clojure

sveri19:12:29

Thats what it ist among other things

roelof19:12:56

I will play with it so I know that my functions are working properly

roelof19:12:08

I could try to implement the code sean gave me in read-data . Also there the page schould be between 1 and 471.

roelof19:12:52

and work when I get that working . Try instrument and the check part

roelof19:12:12

Thanks all . Enough things to explore here

roelof19:12:12

@sveri what is spec more then in your oponion

sveri20:12:25

@roelof https://m.youtube.com/watch?v=VNTQ-M_uSo8 this is a good Talk about spec where stuart compares it to other type systems among other things.

sophiago22:12:44

i heard people were talking about spec in here so figured i'd drop by... trying to finish up speccing a project before i refactor it and am having trouble with just a few things

sophiago22:12:00

mainly, i want to construct a list of s/defs to pass as the arguments and return values of a s/fdef and then probably run s/exercise on it, but am not getting the syntax right

sveri22:12:25

@sophiago I am not sure if I understand you exactly, but, this is how I use spec: https://github.com/sveri/getless-clj/blob/master/src/clj/de/sveri/getless/db/food.clj

sophiago22:12:31

@sveri something like this, but obviously my syntax is off:

steinhauser22:12:43

@kevinbheda I would definitely either use a do form as suggested, or put the multiple other things you want to do into their own function

sophiago23:12:36

@sveri can you tell from that snippet what i'm getting wrong? this is the last thing i'm trying to get done for the day 🙂