Fork me on GitHub

Hi, I am not very clear, why liberator.core/defresoure is used for??


Plus, do I need to them too alongside functions?


my second question is, can we call functions inside liberator?


defresource is for serving content out of a jar that started as a file in your repo before building


so if you want a static file that isn't represented by code or a string in a source file, and want to be able to serve it directly from the jar without unzipping or whatever


commonly used for index.html


liberator is a collection of http libs, you typically call whatever functions you need in order to serve a request from inside your handler function for an individual route / method


correcting the above: that liberator calls a "resource" isn't what we'd usually call a resource - it's a way ot describe an endpoint (and can include arbitrary function calls)


so, they are just defined for end points ?


I'm sad they decided to use the word "resource" for this, as it already has a meaning in the clojure http handling world :/


yeah, they define endpoints that can be called if a certian route is hit


@gagan.chohan this intro shows using an arbitrary function for :handle-ok (the non-error case)


(defroutes app
  (ANY "/foo" [] (resource :available-media-types ["text/html"]
                           :handle-ok (fn [ctx]
                                        (format "<html>It's %d milliseconds since the beginning of the epoch."


and of course that function can call other functions


cool, Thanks for the detailed explanation.


is there a way to check in testing that what functions did function being tested called?


not that I know of (it may well exist in a third party lib I haven't used), clojure (and fp generally) tends to lead you toward using example based and property based tests that are focused on input values and return values, and not the control flow of the code executed


There’s a function that calls S3 or cache to retrieve data, I want to test both scenarios, in case of S3 and cache, they both call different functions


come to think of it, I have seen this done with with-redefs


output will be same in both cases


so, what do you recommend to test such a function


I take back what I said before: the pattern is (let [executed (atom [])] (with-redefs [some-ns/call-s3 (fn [& args] (swap! executed conj {:f :some-ns/call-s3 :args [args]}))] (some-other-fn))


after you execute some-other-fn you check the contents of executed (it could contain zero or more entries of course)


and you would "redef" every function you want to track / stub


I'm personally not a fan of this sort of test, and with-redefs shouldn't be used in a multi-threaded context, but it does work


so , is there any preferred approach to test what is being called, S3 or Cache, considering both of them returns same data


that's what the above will do (add another redef for other-ns/hit-cache)


it replaces the function you want to track with something that records its invocation - which is then data you can make an assertion about


okay, I will first look at with-redefs docs



user=> (def calls (atom []))
user=> (with-redefs [clojure.core/println (fn [& args] (swap! calls conj {:f 'println :args args}))] (println :OK))
[{:f println, :args (:OK)}]
user=> @calls
[{:f println, :args (:OK)}]


it shouldn't be used with multiple threads in use, because two overlapping with-redefs calls can lead to losing the original function definition


so you're committing to single-threaded execution during tests if using this


(or very careful usage of threads and redefs)


Difficulty in testing is (to me) a sign that you need to refactor. If you can change this to have two (or arbitrarily many) strategies to do whatever you might get more adaptable code and more easily tested code at the same time

Godwin Ko01:08:02

don’t know why this doesn’t work (map #(.autoSizeColumn sheet %) (range 2)) while call it one-by-one (.autoSizeColumn sheet 0) & (.autoSizeColumn sheet 1) works?


what error are you getting?


try doall or mapv? perhaps laziness is involved?

👍 4
Godwin Ko02:08:17

you save my day, thx a lot!!

👍 4

be wary of side effects from a map


does .autoSizeColumn return a new value? If its all just for side effects, use doseq instead.


or, as you are looping over indexes, have a look at dotimes


Hi. After setting JAVA_CMD to C:\Program Files\Java\jdk1.8.0_211\bin\javac.exe running lein install produces

javac: invalid flag: -Dclojure.compile.path=C:\git\xx\mranderson/target/classes
Usage: javac <options> <source files>
use -help for a list of possible options
Does anyone know what I'm doing wrong/how to fix?


JAVA_CMD should have been set to C:\Program Files\Java\jdk1.8.0_211\bin\java. 🙂

Godwin Ko08:08:37

I try to export a large excel file using docjure, and the jvm keep crashing due to OutOfMemoryError, GC overhead limit exceed. Which jvm options should I alter? Thx in advance 🙇:skin-tone-2:


try -Xmx2G -Xms2G and replace 2G with however much memory you want!


often i'm faced with making a serious of changes to a map (as part of some data munging), I generally use the -> thread macro to change update/assoc ops, however it gets awkward when I want to , for example, change/add a key based on the value of another key. is there no function in cloure core for doing this?


i can workaround it by using as-> but .. 😕 i don't see that macro used much in code in the wild vs ->, which makes me think i'm missing something


I just use destructuring in let's in combination with the threaded assoc/updates or bind to one var (usually it's %) and use get-in's.



(->> collection
     (map #(let [{:keys [one two]} %]
             (-> %
                 (assoc-in [:key :path 1] (get-in % [:other :key :path]))
                 (assoc :two one)
                 (assoc :one two)
                 (update-in [:yet :another] inc)))))


you can also destructure in the (fn ...) arg list instead of using anonymous inline func


(->> collection
     (map (fn [{:keys [one two] :as arg}]
            (-> arg
                (assoc-in [:key :path 1] (get-in arg [:other :key :path]))
                (assoc :two one)
                (assoc :one two)
                (update-in [:yet :another] inc)))))


thanks for sharing. using destructuring to bind the values before threading is nice


@ramblurr Clojure core is intentionally limited when it comes to stuff like this, so I recommend either writing your own helper functions or to check out something like and see if that might be of use


I have a dev scenario / lein question. Say that I have two Clojure projects, libfoo and svcbar. svcbar has libfoo as one of its dependencies. Now I want to make a change in libfoo and try it out in svcbar. I bump the version i libfoo from 1.1 to 1.2-SNAPSHOT, I test, I build a JAR -- I'm happy. Then I change over to the svcbar dir and change its dependency on libfoo to 1.2-SNAPSHOT, but of course that build fails because that version isn't published. How do I make a locally built version of a library available to lein when building something that depends on it?


You can lein install it to install it to your local maven repo


or you can use "checkouts" so you don't even need to install it


oh. just saw this was answered below... heh.


What is a Maven repo? Is the cache in ~/.m2 actually a full-blown Maven repo?


@magnus_clojurians there are 2 ways: if you are done with dev work on libfoo you can run lein install from the root directory of libfoo on your dev machine. This will install the new version of libfoo on your local machine and should allow svcbar to find it as a dependency. If you are still working on libfoo and want to dynamically pick up changes in svcbar leiningen has a feature called checkouts. You can set up a directory in svcbar that has a symbolic link to libfoos project root. Lein should use this as a source for dependency resolution. The main advantage to this approach is you don’t have to run lein install every time you make a change to libfoo. But both approaches should be the same otherwise.


I've seen lein install, but it refers to lein deploy which only refers to publishing to public repositories. Is there some documentation on how to use it locally? I've never seen anything about checkins, it's not a command I guess... so where can I find information about how to actually use it?


Correct. It’s actually checkouts and it would be a sub directory of svcbar. You should be able to find the documentation here if you search the page: Sorry I couldn’t find a direct link, responding from my phone. 😳


Also, deploy does push the Jar but I think install simply installs it on the machine where the command is run. Could be wrong about that but I think that is how it works.


Thanks, that ought to get me started 😃

👍 4
Noah Bogart14:08:49

is reduce lazy? It doesn't look like it, but my experiments are proving inconclusive


what data points to it being possibly lazy?

Noah Bogart15:08:50

on second thought, i (naively) assume every iteration tool in clojure is lazy. the language does a good job with being consistent on that front (all of the seq-related tools are lazy), and the reduce docs don't say either way. the impl isn't wrapped in a lazy-seq, which points to it not being lazy

Noah Bogart14:08:37

my bad programming, i think

Noah Bogart14:08:21

i had a doseq, and wanted to save the results, so i switched to a for loop wrapped in a doall, but on closer inspection i was seeing some weird behavior, so i thought i'd try using reduce to make sure, and then weird behavior persisted, so the problem looks to be an error in my logic somewhere

Noah Bogart15:08:45

thanks for the quick answer!


is there a reason at this time not to just openjdk 12?


and prefer openjdk 11


8, 11, 14 are the LTS (Long Term Support) versions which is why folks tend to prefer those versions, even in the openjdk camp.


ahh 👍 yeah, ok. for some reason in my head I was thinking 12 was LTS


time to add in the adoptopenjdk cask then. 😄


We're stuck on openjdk8 because some pieces of our infrastructure won't run on jdk9+ but I'm testing a lot of stuff on both jdk8 and jdk11 at this point.

Alex Miller (Clojure team)17:08:46

for Clojure, we're trying to emphasize the LTS versions so we recommend 8 and 11 as primary right now (but the matrix tests with 12 too)

Alex Miller (Clojure team)17:08:28

we are making no effort to test with 9 or 10 right now (although we did prior to 11 and there are no particular issues with them)

Ashley Smith22:08:26

I need some help - I'm doing my first ever POST request and so I'm a little unsure what to expect. I have a successful connection between API and website but the data I POST just seemingly disappears. Its the end of my night and I feel like I don't know where to go from here. Here's a gist with my code and the output I've got from print statements:


I don't use Compojure but I think I see the issue: In the line 32 of core.clj you have

(c/POST "/forum/submit" post (db/submit-forum-post post))
But in this case, post is not the parameters you sent in the request. It is the whole request object. If you wanted the params you'd have to destructure it like:
(c/POST "/forum/submit" {params :params} (db/submit-forum-post params))

Ashley Smith22:08:51

If you look at the gist I sent, the params inside the request is empty - I was trying that at first but I thought for the sake of getting some help with this I'd show the whole request in the print statement


Another thing I noticed is that you're not ussing any middleware. If you expect JSON you should probably use something like If you're using url encoded forms there is already a function on ring.middleware.params called wrap-params that handles that.


@ULLSSKY00 Yep! That's due to not using any middleware to handle the request.

Ashley Smith22:08:14

Yeah I don't really understand any of this middleware stuff - so is that why my data is just disappearing?

Ashley Smith22:08:21

okay getting somwhere

Ashley Smith22:08:41

Do you know how hard it'd be to get that middleware up and running? Do I wrap it like I do with cors or something?


It is not dissappearing! It is on the :body property IIRC. It's just not in a format you can use. You're already using a middleware! wrap-cors is exactly that.


So you could write (wrap-params (wrap-cors router .....)) Or in a more readable way:

(-> router
    (wrap-cors :access-control.......))

Ashley Smith22:08:42

trying that ring/json middleware

👍 4
Ashley Smith22:08:08

I don't really like that syntax unless the brackets get reaally bad


It's much more readable when you get used to it 😅

Ashley Smith22:08:16

;; Wraps middleware around router
(def api-handler
    (cors/wrap-cors router
      :access-control-allow-origin [#""]
      :access-control-allow-methods [:get :put :post :delete])))
Does this look okay? As my data still doesn't appear in my print statemnt

Ashley Smith22:08:29

sorry if im missing something, I just really want to get this done before bed if its a simple thing

Ashley Smith22:08:26

Thank you ❤️

Ashley Smith22:08:33

Thank you thank you thank you! ❤️


Congrats ❤️ and good night for you haha 😅

Ashley Smith23:08:50

I got past that problem, my current problem is with postgresql

Ashley Smith23:08:19

2019-08-08 00:06:21.167:WARN:oejs.HttpChannel:qtp878530251-18: /forum/submit
org.postgresql.util.PSQLException: This ResultSet is closed.
	at org.postgresql.jdbc2.AbstractJdbc2ResultSet.checkClosed(
	at org.postgresql.jdbc2.AbstractJdbc2ResultSet.setFetchSize(
	at org.postgresql.jdbc4.Jdbc4Statement.createResultSet(

Ashley Smith23:08:03

at least the POST is out of the way!


That could mean you're closing the connection to postgres before you read from the ResultSet 😮


Do you have a gist for that?

Ashley Smith23:08:03

I'm afraid I'm not quite sure of what you mean, but if you mean what the actual statement is here you go

Ashley Smith23:08:06

thank you for trying to help!

Ashley Smith23:08:20

I cannot wait to sleep but if I don't finish this I will be awake all night on my laptop trying to do it


Don't worry, I have some free time at work today so this keeps me busy parrot give me a minute to check that

Ashley Smith23:08:12

its my first time working with all these things so hopefully its just an amateur mistake you're looking for 🙂


Is this where you are getting the error? 😮 I can't really find anything wrong with this.

Ashley Smith23:08:08

error triggers when I do submit-forum-post

Ashley Smith23:08:01

It says the error comes from opening and closing the connection or something but there's only two things I do with SQL - my GET for the forum posts and pages (done on another page) and this POST


Yeah. It works on my end 😮 (I made a dummy db).

Ashley Smith23:08:33

and the get stuff works fine even now. Commenting out the sql/insert! stuff makes this work

Ashley Smith23:08:40

let me try deleting my db maybe?


It all works for me here 😮 and I can't see anything obvious

Ashley Smith23:08:28

  TagID bigserial NOT NULL,
  TagLabel varchar(18)

  UserID bigserial NOT NULL,
  Username varchar(18) NOT NULL,
  UserHandle varchar(12) NOT NULL UNIQUE,
  JoinDate timestamptz NOT NULL,
  IsAdmin bool NOT NULL,

  PostID bigserial NOT NULL,
  PosterID bigserial,
  PostDate timestamptz NOT NULL,
  PostTitle varchar(100) NOT NULL,
  PostContent text NOT NULL,

Ashley Smith23:08:32

These are my tables

Ashley Smith23:08:45

is there something in the tablet that's making it crash?

Ashley Smith23:08:43

Oh- could it be that I'm not passing PostDate? I was expecting that to just insert the current time in though?


That does give me an error 😮

Ashley Smith23:08:10

If only I knew how to pass current time in


You can add DEFAULT NOW() to the table definition.

Ashley Smith23:08:52

Just tag it on after not null?


Yep, that's it 😉

Ashley Smith23:08:37

hmm the error is still there


Another thing, PosterID is defined as a bigserial. Which means it will try to autoincrement whenever you create a new record. I imagine you want to add it yourself, so bigint would be a better type

Ashley Smith23:08:13

Does it not have to match the same type as the other table? It's like linked to the Users table?


(But then you'd have to send PosterID from your API).


They are! int and serial are both integers. Their difference is their behaviour.

Ashley Smith00:08:20

Nice! Right now I'm not worrying about the user as im doing a guest post so I'm expecting that to be null

Ashley Smith00:08:06

unfortunately I am still getting my error 😞