Fork me on GitHub
#beginners
<
2016-12-22
>
michael zhou00:12:39

Hello.guys. Anyone know a page break library for web?

gdeer8102:12:42

Like for pagination for a server/client web app?

michael zhou03:12:09

yes,clojure pagination lib

jessecogollo05:12:41

I have a question, I need print n time a string. for example. if i get the number 3, the string "example" should be print 3 times.

(fn[n]
  (println (repeat n (str "Example\n"))))
the issue with my solution is that print (Example Example) but I need Example Example

dpsutton05:12:48

are you in a repl?

dpsutton05:12:57

can you evaluation (repeat 3 (str "Example\n"))

jessecogollo06:12:35

`(Example Example Example ) nil`

dpsutton06:12:54

so what does it mean to call println on a list

jessecogollo06:12:51

I dont need the list

dpsutton06:12:57

well you made one

jessecogollo06:12:57

only need the string

dpsutton06:12:15

so we need to make a string rather than a list

dpsutton06:12:33

but repeat always returns a seq of things

dpsutton06:12:51

but we can apply str to stuff

dpsutton06:12:15

(str "blah" "blah" "blah") "blahblahblah"

dpsutton06:12:31

so, if we make a list of "Example", we can call string on that

jessecogollo06:12:58

:thinking_face:

dpsutton06:12:53

(apply str (repeat 3 "blah")) "blahblahblah"

dpsutton06:12:03

so, here we are using apply

dpsutton06:12:18

if we called string on te list of (blah blah blah), it would "string" the structure

dpsutton06:12:25

we want to call the function with that list as its arguments

dpsutton06:12:32

which is apply versus standard function call

dpsutton06:12:50

so we say hey, call the function str on with the arguments in this list

dpsutton06:12:10

looks weird, but if we print that, we should get what we want

jessecogollo06:12:28

yes, it works.

dpsutton06:12:23

there's another way to do it as well

dpsutton06:12:31

and you can decide which way you prefer

jessecogollo06:12:39

ok, let me see..

dpsutton06:12:04

rather than constructing what we want to print, we can take the traditional route and do what we want n number of times

dpsutton06:12:27

so rather than making the string of three examples with line breaks, we could just "loop" and print example however many times we want

dpsutton06:12:11

which you prefer probably largely depends on what else you're doing in your code

dpsutton06:12:25

but probably always good to write things twice in two different styles while you are learning

jessecogollo06:12:21

yes, thanks. I get it.

jessecogollo06:12:44

Thanks for share with me the dotimes function.

dpsutton06:12:25

no problem. happy coding!

grounded_sage08:12:00

This is the first time I have tried out playing with API's and I am trying to get some stuff from Meetup. I'm just stumped on the time format.

grounded_sage08:12:29

"id": "ngmmrlywjbdc",
"name": "Social Meetup",
"status": "upcoming",
"time": 1498118400000,
"updated": 1457950138000,
"utc_offset": 36000000,
This is a snippet taken from Meetup. What am I supposed to do with that "time":

roelof08:12:05

@grounded_sage If you want to convert it to a normal time object. you can look at clj-time

grounded_sage08:12:44

I managed to find some information on it. Google didn't surface it very well with my queries but I got there in the end.

grounded_sage08:12:05

I'm looking to grab it on the front end so I guess I will have to find a cljs-time equivalent.

roelof08:12:16

with that you can do (c/from-long (:time <naam variable))

sveri08:12:15

@grounded_sage this is a timestamp, see https://en.wikipedia.org/wiki/Unix_time. And there is cljs-time: https://github.com/andrewmcveigh/cljs-time which is similar to clj-time

sveri08:12:40

Also, please be aware that the map contains a "utc_offsett" which you would have to apply too, to get the correct time. Although it might be a bit difficult depending on the timezone the user consuming the API, sits.

grounded_sage10:12:08

Thank you. I think it's easier for now if I just manually update.

grounded_sage10:12:20

Hitting a lot of issues with Rum that are more critical

roelof14:12:20

my homepage looks like this. The first page can be found with just / . Next pages are found with /pages=x . Must I make two seperate routes or can one route handle both cases

joakimmohn16:12:18

im trying to save an array of images to my postgres db.

joakimmohn16:12:19

im trying to save an array of images to my postgres db.

(doseq [file files]
                  (upload/save-image! user file))
but only the first image is stored before i get batch update exception. Any ideas on how to make sure all images gets stored?

sveri16:12:46

@joakimmohn Not sure if I understand that correctly, but if you do get an exception, you should get rid of that first

kevinbheda16:12:33

in honeysql what is this operator ‘-> ‘ https://github.com/jkk/honeysql

-> (select :a :b :c)
    (from :foo)
    (where [:= :f.a "baz"]))

joakimmohn16:12:34

@sveri `(POST "/file" [] :multipart-params [files :- [TempFileUpload]] (doseq [file files] (db/save-image! "kappachino" file)) (ok))` This is how the handler looks like. I think the problem is that postgres isn't finished working before the next image is attempted to be stored.

joakimmohn16:12:40

If the images are small (< 50 kb it works fine)

kkruit16:12:17

@kevinbheda I'm pretty sure it's just a thread first macro http://clojuredocs.org/clojure.core/-%3E

sveri17:12:35

@joakimmohn i am Sure that PostgreSQL Cab handle multiple parallel requests

sveri17:12:13

Could you Post the exception please?

joakimmohn17:12:17

i wrapped the operation in a try catch block and now i'm not able to recreate the problem, so i guess thats called a solution? should all db operations be wrapped in try catch blocks?

adamkowalski17:12:04

how do I compose futures together? Like if I want to map a function over a future is there a standard library function for that?

adamkowalski17:12:28

Ideally it would wait till the future is realized, then apply the function to that value, returning another future

mtkp17:12:25

your second comment makes me think that pmap might be what you're looking for

mtkp17:12:25

but though i can't think of something in clojure.core, using your description:

mtkp17:12:34

(defn chain [f] (fn [fut] (future (f @fut))))

(map (chain my-fn) my-seq-of-futures)

sveri17:12:00

@joakimmohn If you wrap it in a try catch, the exception wont go away. You will just have to handle it explicitly then. What does your code look like now?

joakimmohn18:12:35

(POST "/file" []
                 :multipart-params [files :- [TempFileUpload]]
                 (doseq [file files]
                   (try
                     (upload/save-image! "userid" file)
                     (catch Exception e (.getNextException e))))
                 (ok))

kevinbheda18:12:54

in emacs clojure what is the short cut for copying s-expression ?

sveri18:12:49

@joakimmohn Like this you catch the exception and thats about it. That is not the way to go. You should log at least and do something, depending on the exception. Instead of (.getNextException e) you could call (.printStackTrace e) to get an idea what it is about and post it here.

joakimmohn18:12:43

@sveri '(catch Exception e (.printStackTrace e))' I would post it here, but it seems like all the images are being stored without any issues now. I haven't used try/catch blocks a lot tbh

roelof18:12:41

IM finisched reading compojure routes in detail. so if I make a routes like this ⁠⁠⁠⁠

 (GET "//?page=:page" [page] (home-page)) 

roelof18:12:33

and a user uses only \ then page is nill

roelof18:12:43

so I could make a test to look if page is nill with (let [page 1] (if (nil? page)))

roelof18:12:59

so far , right ? @dpsutton

agile_geek18:12:40

@roelofw you don't route on query params. In other words your route only has the URL in it

agile_geek18:12:22

Also another gotcha will be that page will be a string when it comes from params so be aware of that.

roelof18:12:28

oke, so the route is only \

sveri18:12:20

the route is /

roelof18:12:56

I will hit the page again to find out about url parameters

sveri18:12:18

@roelof When reading, take the examples and implement them yourself

sveri18:12:20

try them out

sveri18:12:23

play around with it

roelof18:12:46

I was following this example :

(GET "/user/:id" [id]
  (str "<h1>Hello user " id "</h1>"))  

sveri18:12:03

Basically it goes like: 1. Make an assumption: If I change this, I expect that. 2. Test your assumption

roelof18:12:05

where as far as I understand :id is a url parameter

roelof18:12:05

or must I follow this example I found at stack overflow :

(GET "/:id/descendants" [id]
     :return [d/CategoryTreeElement]
     :path-params [id :- Long]
     :query-params [context-type :- d/ContextType
                    levels :- Integer
                    {tenant :- d/Tenant :DEF_TENANT}
                    {show-future :- Boolean false}
                    {show-expired :- Boolean false}
                    {show-suppressed :- Boolean false}
     :summary "Fetch category descendants"
     (ok ...))  

agile_geek18:12:36

@roelofw that is an example of destructuring a parameter from the URI

agile_geek18:12:52

you want an example of getting a query param

sveri18:12:59

Stick to the compojure tutorial

roelof18:12:54

oke, I think you mean this :

(GET "/:foo" [foo id]                    ; You can always destructure and use query parameter in the same way
  (str "Foo = " foo " / Id = " id))   
; curl get /bar?id=33 would be "Foo = bar / Id = 33"   

agile_geek18:12:02

kind of but you don't need :foo in this example

agile_geek18:12:49

that would pattern match this URL "/thisisfoo?id=1"

roelof18:12:01

oke, now I try to remember how to make optional parameters to a function

dominicm18:12:25

Multiple arity is what you need to google I think 🙂

roelof18:12:59

I think I could do something like this (GET "/" [page 1 ]

roelof19:12:30

Right. if im right this will take care that page is 1 if no value is given

roelof19:12:41

or I have to use this trick : (defn foo [{:keys [a b c], :or {c 42}}]

roelof19:12:00

where c is 42 when no value is given for c

roelof19:12:16

Time for a break. My head is spinning right now

roelof19:12:31

@dominicm thanks, I know I can use & s where s can have 0, 1 ,2 or more

roelof19:12:55

but I do not see how I can make a default value when there are zero arguments

noisesmith19:12:39

(defn defaulted ([x] (defaulted x default)) ([x y] ...))

dominicm19:12:44

(defn x
  ([] (x :default-value))
  ([param] (do-stuff-with-param))

noisesmith19:12:56

or that, yeah

agile_geek19:12:51

but in this case if you have one route that expects a page param you will never have zero args. You always have one....just it might be nil

agile_geek19:12:31

(GET "/" [page] (hame-page page))

roelof19:12:47

oke, then I have to check that in a let so I page has always a value

roelof19:12:20

( if-let (nil? page) (=page 1)) I think

noisesmith19:12:22

roelof a nice pattern for this is (defn find-page [p] (get {nil "/home" "/" "/home"} p p))

noisesmith19:12:37

or map it to "1" or whatever

roelof19:12:41

@agile_geek am I still on the right track ?

adamkowalski19:12:34

How do you work with unsigned longs in clojure?

adamkowalski19:12:44

and how would you convert one into a byte array

agile_geek19:12:47

@roelofw yes although that if-let doesn't look right.

agile_geek19:12:42

Here's a tip - if you want to return the value of a var if it's not nil and a default if it is, instead of if: (if page page "1") you can use or: (or page "1")

agile_geek19:12:47

oh BTW (if page page "1") is the same as (if (not (nil? page)) page "1") as nil is falsey

roelof19:12:47

@agile_geek so I can do (GET "/" [page] (home-page page))

roelof19:12:19

and then this :

(defn home-page [page]
  (let [
        url ""
        options {:as :json :query-params {:key (env :key) :format "json" :type "schilderij" :toppieces "True" :p page }}]
    (or page "1")
    (layout/render
      "home.html" {:paintings (-> (client/get url options)
                                  api/read-numbers
                                  api/fetch-paintings-and-images-front-page)})))  

agile_geek19:12:54

no that (or page "1") needs to set a variable in the let that you then reference in the options as the value of :p

roelof19:12:36

oke, that would then be :

defn home-page [page]
  (let [ page  (or "page" 1 )
        url ""
        options {:as :json :query-params {:key (env :key) :format "json" :type "schilderij" :toppieces "True" :p page }}]
      (layout/render
      "home.html" {:paintings (-> (client/get url options)
                                  api/read-numbers
                                  api/fetch-paintings-and-images-front-page)})))  

agile_geek19:12:46

Yes although I would avoid shadowing page just to avoid confusion:

(defn home-page [page]
  (let [ page-num (or page "1")
        url ""
        options {:as :json :query-params {:key (env :key) :format "json" :type "schilderij" :toppieces "True" :p page-num }}]
      (layout/render
      "home.html" {:paintings (-> (client/get url options)
                                  api/read-numbers
                                  api/fetch-paintings-and-images-front-page)})))  

agile_geek19:12:19

and make sure your code is better formatted. Slack is not an IDE or an editor so hard to keep formatting consistent!

agile_geek20:12:05

BTW can you see why (or page "1") will work? If not have a try of similar expressions in a repl

roelof20:12:27

now testing the whole code again

roelof20:12:36

Thanks for all the help

roelof20:12:58

Tomorrow I try to make a pagination visible on the page

roelof20:12:14

I have some ideas to make that work

roelof20:12:13

oops, something is not right. when I do localhost:3000 I see this error message :

Wrong number of args (0) passed to: home/home-page  

dpsutton20:12:37

roelof, just a heads up, you don't need to post every thing you are going to investigate

dpsutton20:12:53

try to work on stuff on your own and come to us when you need help, but not just for every error that pops up

agile_geek20:12:58

check your routes

roelof20:12:17

Im busy with that

agile_geek20:12:28

@roelofw I agree with @dpsutton. The way to learn is to try and investigate your problems, isolate as much of the problem as you can and create simple experiments to work out what's wrong. If you need to add println or debug. Distil the problem to a simple use case if possible and then you can easily communicate it to us without us having to understand your entire application. Having said all that, we don't mind helping but we want you to help yourself too simple_smile

dpsutton20:12:00

remember to use the repl as much as possible and read documentation and examples of functions

agile_geek20:12:41

I want to +100 ☝️

roelof20:12:45

I have made it work

agile_geek20:12:11

Cool I would leave on a high note and carry on tomorrow

agile_geek20:12:25

let your brain sleep on what you've learned

roelof20:12:13

last question before I goto sleep : the right url for a page is now localhost:3000/?page=n

agile_geek20:12:12

where n is an integer in the range 1 - 470

roelof20:12:34

oke, then I have to look tomorrow why this is not working

roelof20:12:49

when I change n I still see the same paintings

roelof20:12:50

I think I have some logging to do for the urls

roelof20:12:39

Sleep for me now.

roelof20:12:47

Thanks all again

gdeer8121:12:42

every time I see someone leave the beginners channel I'm like "nice, another graduate..." 🙌:skin-tone-2: 🎓 🙌:skin-tone-2:

roelof21:12:32

I think with me It will take a while before can leave this channel

roelof21:12:59

I found this for logging

;; print request info to *out*:
(client/get "" {:debug true})

 

roelof21:12:14

so I did

(defn home-page [page]
  (let [page-num (or "page" 1)
        url ""
        options {:as :json :query-params  {:key (env :key) :format "json" :type "schilderij" :toppieces "True" :p page-num :ps 10} }]
    (layout/render
      "home.html" {:paintings (-> (client/get url options {:debug true})
                                  api/read-numbers
                                  api/fetch-paintings-and-images-front-page)})))  

roelof21:12:28

but no output to see on the console

roelof21:12:04

What is out ?

dpsutton21:12:01

in your repl, evaluate out

roelof21:12:54

#object[java.io.PrintWriter 0x164cd27 "java.io.PrintWriter@164cd27"]

roelof21:12:14

so I have to use print

roelof21:12:06

but when I use print I still do not see the url and the request parameters so no luck

sveri22:12:58

@roelof Please check the number of arguments client/get takes

sveri22:12:45

I am not sure, but I suspect there should only be one options map

roelof22:12:02

oke, when I try (print (client/get url options {:debug true } )) I see only the request back

roelof22:12:36

I want to see the value of url options to see what url is send to the api

roelof22:12:15

to see why I see the same paintings again no mather what the pagenumber is

seancorfield22:12:30

@roelof Think carefully about the number of arguments you are passing to client/get there. You have options — isn’t :debug an option as well?

johnmarinellii23:12:29

i’ve updated my cider nrepl version from 0.8.1 to 0.9 in my .lein/profiles.clj file. does this mean the next time i do lein deps, it’ll update automatically?