beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
sova-soars-the-sora 2020-11-20T00:10:25.054800Z

So I'm trying to get the size of a file ... (.length (io/file "filename")) is not working ;/

sova-soars-the-sora 2020-11-20T00:10:35.055Z

am i missing something?

phronmophobic 2020-11-20T00:12:37.055300Z

are you getting an error?

sova-soars-the-sora 2020-11-20T00:15:28.056200Z

Aha. I was getting zero as the file size. but it's because I did not have the full path "resources/"

sova-soars-the-sora 2020-11-20T00:15:39.056600Z

because I'm also using resource-response (which adds in "resources/" on its own)

sova-soars-the-sora 2020-11-20T00:17:14.057100Z

I'm trying to get this .m4a to play on iOS mobile [webkit] and apparently it needs 3 headers set,

sova-soars-the-sora 2020-11-20T00:17:44.057800Z

it works on desktop firefox and stuff... but on iOS mobile it just doesn't want to play nice. It used to say "Live Broadcast" and now it just says "Error" where there ought be a seek bar x/

2020-11-20T00:22:06.058400Z

mixing files / resources sometimes works accidentally, but it's not going to work in the general case

sova-soars-the-sora 2020-11-20T00:25:11.058800Z

(GET "/members/:filename" [filename :as r]
  	(let [file-size-in-bytes (.length (io/file (str "resources/members/" filename)))
  		  content-range (str "bytes 0-" (dec file-size-in-bytes) "/" file-size-in-bytes)]
    (println filename ": " file-size-in-bytes ": " content-range ": " )
      (->
  		(response/resource-response (str "members/" filename))
  		(response/header "Content-Length" file-size-in-bytes)
  		(response/header "Content-Range" content-range)
  		(response/header "accept-ranges" "bytes") 
  		)))

2020-11-20T00:27:42.059500Z

small thing, you don't need that str call, io/file already composes varargs into a path

sova-soars-the-sora 2020-11-20T00:29:07.059700Z

hmmm okay, let's do that...

sova-soars-the-sora 2020-11-20T00:31:06.060500Z

Is very weird ... webkit just says "Error" where there ought be a seek bar. And so I try and undo the code I have added, and it doesn't go back to saying "Live Broadcast" but remains on "Error" x/

phronmophobic 2020-11-20T00:31:20.060800Z

it probably doesn't matter, but I would also capitalize

Accept-Ranges

sova-soars-the-sora 2020-11-20T00:31:36.061Z

πŸ˜„ open to any suggestions

sova-soars-the-sora 2020-11-20T00:31:51.061200Z

anybody got Tim Cook on speed dial?

sova-soars-the-sora 2020-11-20T00:32:00.061400Z

I have words.

phronmophobic 2020-11-20T00:32:45.061700Z

are accessing the page from iOS safari?

phronmophobic 2020-11-20T00:33:27.062500Z

if so, I believe you can pull up a dev panel using safari on your computer and connecting to the safari running on your iOS device

phronmophobic 2020-11-20T00:33:38.062800Z

that dev panel might be able to give you more information

sova-soars-the-sora 2020-11-20T00:34:12.063200Z

whaat that's awesome i gotta figure out how to do that.

phronmophobic 2020-11-20T00:35:03.063300Z

yea, it's quite useful

phronmophobic 2020-11-20T00:41:34.064500Z

progress! try adding a Content-Type header

Sergio 2020-11-20T09:47:20.080100Z

I suspect your problem is related to the Parts (http-ranges). I did some implementation in the past on java+spring but the principle of the solution I think applies. Here you can find how to calculate the parts in java and that maybe gives you an indication on how to use it in CLJ: https://stackoverflow.com/questions/28427339/how-to-implement-http-byte-range-requests-in-spring-mvc

Sergio 2020-11-20T09:50:08.080400Z

it might be an interesting exercise to have it working on clj:smile: … I will need the weekend for that

sova-soars-the-sora 2020-11-20T15:35:58.098200Z

Haha awesome. Thanks @sdmoralesma i'm just gonna throw jQuery in there and configure jPlayer to do it and call it a day on that one

πŸ‘ 1
sova-soars-the-sora 2020-11-20T15:39:12.098400Z

I thought flash player was being retired... I wonder if this will be a thing in the future for the flash fallback on jPlayer x|

sova-soars-the-sora 2020-11-21T02:44:53.161Z

Hey what is this `

"Content-Range", "bytes */"

sova-soars-the-sora 2020-11-21T03:10:27.161200Z

https://stackoverflow.com/a/43133607/440887

sova-soars-the-sora 2020-11-21T03:10:42.161500Z

Use Absolute File Path instead of Relative File Path for html5 Audio elements and it works

sova-soars-the-sora 2020-11-21T03:10:50.161700Z

do I stop screaming into the void now or keep going?

phronmophobic 2020-11-20T00:42:44.064800Z

probably one of these video mime types https://www.iana.org/assignments/media-types/media-types.xhtml#video

sova-soars-the-sora 2020-11-20T00:44:43.065100Z

Hmmm, it's just an audio file... I tried both audio/m4a and video/m4a as a "Content-Type" but curiously I get byte-ranges 0-1 as an error and also the content type remains "other" ...

sova-soars-the-sora 2020-11-20T00:46:12.065300Z

It thinks the size is 8.00KB but it transferred all 4.2MB x/

sova-soars-the-sora 2020-11-20T00:47:59.065500Z

one resource suggests audio/x-m4a ... let's see

phronmophobic 2020-11-20T00:48:19.066100Z

oops. assumed it was video for some reason

sova-soars-the-sora 2020-11-20T00:48:57.066800Z

np. it's really weird that it thinks the file size is 8kb but transfers 4.2MB

sova-soars-the-sora 2020-11-20T00:49:38.067700Z

pretty badass to move the mouse on the main machine and see the highlights on the device...

🦜 1
phronmophobic 2020-11-20T00:49:38.067900Z

if there’s another site that works right, you can try curling their site and copying what they do

sova-soars-the-sora 2020-11-20T00:50:17.068100Z

an impressive level of difficulty from the makers of the iPod portable music playing thing.

sova-soars-the-sora 2020-11-20T00:53:04.068700Z

maybe a lil too distracting

sova-soars-the-sora 2020-11-20T00:53:15.069100Z

didn't expect an embed x)

sova-soars-the-sora 2020-11-20T00:57:55.069300Z

Welp. Back to screaming into the void. I have mp3 versions of all the files and the mp3 version works but it says "Live Broadcast" instead of being able to seek to arbitrary points.

phronmophobic 2020-11-20T01:00:24.070400Z

i would try finding a site that supports what you want and use the devtools to see they’re doing different

sova-soars-the-sora 2020-11-20T01:00:34.070600Z

1
sova-soars-the-sora 2020-11-20T01:01:04.071Z

that's a great idea, i'm not sure how i'd find one πŸ˜„

phronmophobic 2020-11-20T01:01:38.071700Z

what about sound cloud? or maybe a podcast site

sova-soars-the-sora 2020-11-20T01:20:41.072100Z

Hmm that's an idea

sova-soars-the-sora 2020-11-20T01:20:52.072300Z

apparently it's trying to get range 0-1 and it's not working so it says hey there's no file here

sova-soars-the-sora 2020-11-20T01:21:05.072500Z

the mp3 fallback works, but there is no seekbar, which is what i'm afta

phronmophobic 2020-11-20T01:26:47.074700Z

yea, if normal google-fu is failing, i would also consider searching http://greg.app for the content type and content range headers you’re using and see if anyone else has figured it out

st3fan 2020-11-20T01:36:20.075300Z

Is there an easy way to benchmark some code?

st3fan 2020-11-20T01:36:37.075600Z

ideally a single function in the repl

practicalli-john 2020-11-20T09:21:22.079800Z

criterium is excellent for producing more accurate results than time as it warms up the JVM and runs testsany times to give tha average. I also use memory meter too https://github.com/practicalli/clojure-deps-edn#performance-testing

st3fan 2020-11-20T18:37:26.108500Z

Oh that is very nice

st3fan 2020-11-20T21:18:02.132200Z

I have not figured out what the deal is with deps.edn yet - i'm "simply" using lein now because that is what I know - but it looks like I need to investigate πŸ™‚

practicalli-john 2020-11-20T23:49:53.140200Z

With Leiningen and Clojure CLI tools (deps.edn), the Clojure code is the same (unless lein plugins are writing code for you). However Clojure CLI is a simple wrapper around the JVM with some tools to manage dependencies. One advantage is this is faster than Leiningen, which spins up two virtual machines. The list of community tools that are in practicalli/clojure-deps-edn are used instead of a specific plugin system like Leiningen, so it's easier to add all sorts of tooling to Clojure CLI. This approach is being extended via Clojure exec (and there are whispers about something called tools.build...)

phronmophobic 2020-11-20T01:43:07.076700Z

time: eg.

> (time (count (range 1e7)))
"Elapsed time: 1466.041527 msecs"                                                                                                                                                       
10000000  

sova-soars-the-sora 2020-11-20T01:52:01.077Z

Okay it looks like response/status 206 for "partial content" is important

sova-soars-the-sora 2020-11-20T01:52:24.077200Z

and it now knows the correct file type (m4a) with audio/x-m4a content-type

sova-soars-the-sora 2020-11-20T01:52:31.077400Z

but still an error ;/

phronmophobic 2020-11-20T01:56:18.077800Z

what’s the error?

alexmiller 2020-11-20T02:09:43.078Z

but note that a) Java uses a just in time compiler, so code gets faster as you run it more and b) garbage collection can throw unexpected pauses into the mix

sova-soars-the-sora 2020-11-20T02:10:11.078300Z

It tries to get bytes 0-1 and that doesn't work

alexmiller 2020-11-20T02:10:23.078800Z

so even doing a repeated series of (time (dotimes [_ 1000] (whatever))) will give you a much better sense than timing one op

st3fan 2020-11-20T02:56:28.079Z

Yeah that is what I did .. it is good enough for an indication ...

seancorfield 2020-11-20T03:49:28.079200Z

criterium is a good library for benchmarking

seancorfield 2020-11-20T03:51:13.079400Z

If you're using the CLI and my dot-clojure file, you can just use the :bench alias to bring that in:

seanc@DESKTOP-30ICA76:~/clojure$ clj -M:bench
Downloading: criterium/criterium/maven-metadata.xml from clojars
Downloading: criterium/criterium/0.4.6/criterium-0.4.6.pom from clojars
Downloading: criterium/criterium/0.4.6/criterium-0.4.6.jar from clojars
Clojure 1.10.1
user=> (require '[criterium.core :refer [bench quick-bench]])
nil
user=> (defn foo [n] (* n n n))
#'user/foo
user=> (quick-bench (foo 13))
Evaluation count : 71598534 in 6 samples of 11933089 calls.
             Execution time mean : 2.927325 ns
    Execution time std-deviation : 2.830385 ns
   Execution time lower quantile : 0.853802 ns ( 2.5%)
   Execution time upper quantile : 7.650605 ns (97.5%)
                   Overhead used : 7.242216 ns

Found 1 outliers in 6 samples (16.6667 %)
        low-severe       1 (16.6667 %)
 Variance from outliers : 83.1399 % Variance is severely inflated by outliers
nil
user=>

william 2020-11-20T10:19:58.081600Z

this query using clojure core.logic baffles me:

(logic/run* [what]
  (logic/membero '(a b ~what) '((a b c))))
it returns () when I would have expected '((a b c)) . Could you explain me why?

william 2020-11-20T10:21:30.082600Z

I see that

(logic/run* [what]
  (logic/membero '(a b c) '((a b c))))
is always satisfied, so there must be something wrong in the way I'm using the logical variable

william 2020-11-20T10:24:26.083Z

nevermind, figured it out. The correct form is:

(logic/run* [what]
  (logic/membero ('a 'b what) '((a b c))))

william 2020-11-20T10:24:39.083200Z

hindsight is 20/20 πŸ˜‚

william 2020-11-20T10:26:39.084Z

but why is ('a 'b what) not equivalent to

`(a b ~what)
?

2020-11-20T10:29:48.084100Z

because a and b will be transformed into (quote user/a) not to simple symbol a

william 2020-11-20T10:31:10.084300Z

I see, so I probably should use keywords instead of symbols in this case, right?

william 2020-11-20T10:32:25.084500Z

wait who transforms a in (quote user/a)?

william 2020-11-20T10:33:01.084700Z

oh I see, the backtick... why does it do that?

william 2020-11-20T10:34:05.085500Z

when I'm in emacs with cider, how do I get documentation for a library function?

william 2020-11-20T10:35:52.085800Z

cider-doc unsurprisingly

william 2020-11-20T10:39:06.087400Z

I'd like to know why in:

(logic/run* [what]
  (logic/membero (:a :b what) '((:a :b :c))))
I don't need to quote (:a :b what) , and in fact why quoting it is wrong, and how should I have known

2020-11-20T11:03:18.087500Z

Inside of backtick symbols expand to fully qualified form. Unless symbol is not quoted

2020-11-20T11:05:07.089Z

I guess because membero is macro and expects a form.

william 2020-11-20T11:09:04.090100Z

but where is that documented? How would I know? By reading the source code of membero?

william 2020-11-20T11:09:36.090400Z

(defne membero
  "A relation where l is a collection, such that l contains x."
  [x l]
  ([_ [x . tail]])
  ([_ [head . tail]]
    (membero x tail)))

william 2020-11-20T11:10:30.090700Z

(defmacro defne
  "Define a goal fn. Supports pattern matching. All
   patterns will be tried. See conde."
  [& rest]
  `(defnm conde ~@rest))

william 2020-11-20T11:10:46.091Z

it's unclear for me where I should get that information

bronsa 2020-11-20T11:21:19.091200Z

membero is not a macro

bronsa 2020-11-20T11:21:26.091400Z

the only macro there is run* , and that's what defines the evaluation semantics of its whole body

Iulian 2020-11-20T12:00:28.092800Z

Is there any way to add an "id" attribute to a re-com component? I tried all the combinations of adding the :id in a map or straight into the component, but it does not work. This is my component:

[single-dropdown
    :width     "200px"
    :choices (reagent/atom tags)
    :model (reagent/atom nil)
    :placeholder "Issue Group"
    :filter-box? true
    :on-change #(print "Dropdown: " %)]

gregg 2020-11-22T01:58:49.248600Z

Regarding :model (reagent/atom nil), every time through the render loop, the component will be passed a new reagent atom with value nil, so while I haven't tested it, I don't think that's what you want. I would move the atom to a let block, using a Form-2 component: https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#form-2--a-function-returning-a-function

uosl 2020-11-20T12:02:47.093100Z

Did you try using the :attr param? e.g. :attr {:id "myid"}

Iulian 2020-11-20T12:04:44.093300Z

I did not, and it worked πŸ™ˆ Thank you!

πŸŽ‰ 1
2020-11-20T12:05:47.093600Z

Just checked with source code. You right this is not a macro but it meant to work in macro context as a function transforming unevaluated arguments into a form.

Lyderic Dutillieux 2020-11-20T14:59:11.096500Z

Hey guys, I just checked my system's deps.edn located at /usr/local/lib/clojure/deps.edn and I found this :

:aliases {
    :deps {:replace-deps {org.clojure/tools.deps.alpha {:mvn/version "0.9.833"}
                          org.slf4j/slf4j-nop {:mvn/version "1.7.25"}}
           :ns-default clojure.tools.cli.api}
    :test {:extra-paths ["test"]}
  }
Does anyone know what the :deps alias can be used for ?

kschltz 2020-11-20T15:03:07.097100Z

It seems to me it is there to provide some tooling to mess around with your project dependencies/structure

Lyderic Dutillieux 2020-11-20T15:12:15.097300Z

You mean for editor integration for example ? So it should not be used manually

alexmiller 2020-11-20T15:41:12.098600Z

no, it should :)

alexmiller 2020-11-20T15:41:43.098800Z

see https://clojure.org/reference/deps_and_cli#_other_programs

πŸ‘ 2
alexmiller 2020-11-20T15:42:09.099Z

it provides a number of built-in apps you can run

alexmiller 2020-11-20T15:42:45.099300Z

probably will be more over time

Lyderic Dutillieux 2020-11-20T15:43:14.099500Z

Alright, great ! Thanks, it will be usefull

Rebecca Nzioki 2020-11-20T15:45:25.100400Z

Hey guys, how else can you write this code without using macros?

(defn hex->rgb [[_ & rgb]]
  (map #(->> % (apply str "0x") (Long/decode))
       (partition 2 rgb)))

dpsutton 2020-11-20T15:47:47.101300Z

defn is a macro but you're probably ok with that one? Do you just want to not use the threading macro ->>?

Lyderic Dutillieux 2020-11-20T15:47:52.101400Z

I'll keep track of this then : https://github.com/clojure/tools.deps.alpha/blob/master/src/main/clojure/clojure/tools/cli/api.clj

Rebecca Nzioki 2020-11-20T15:48:14.102100Z

yes

dpsutton 2020-11-20T15:48:49.103Z

(fn [rgbs] (Long/decode (apply str "0x" rgbs)) should do it then as the function you are mapping

2020-11-20T15:49:09.103400Z

The expression (->> % (apply str "0x") (Long/decode)) is equivalent to (Long/decode (apply str "0x" %))

dpsutton 2020-11-20T15:50:25.103900Z

# is the dispatch macro so i got rid of that one too πŸ™‚

dpsutton 2020-11-20T15:51:23.104300Z

why did you want to get rid of the macro? just curious

Rebecca Nzioki 2020-11-20T15:53:33.105600Z

thanks! it's just for learning, i'm reading the web-dev-with-clojure and I read that you can choose to use the threading-macros or not..

dpsutton 2020-11-20T15:55:43.106500Z

great reason! πŸ™‚ Take some time to see how that worked as threading macros are pretty much everywhere and often used interchangeably with what they expand to

Rebecca Nzioki 2020-11-20T15:56:07.106700Z

will do

dpsutton 2020-11-20T15:56:23.106900Z

also try evaluating (macroexpand '(->> (range 3) (map inc) (map dec)))

βœ”οΈ 1
st3fan 2020-11-20T18:36:40.108400Z

What is the deal with globals in Clojure? Are they acceptable because they are mostly immutable? Or should I work on eliminating them?

dgb23 2020-11-20T18:43:16.111300Z

> Are they acceptable because they are mostly immutable? @st3fan As I understand you can manipulate just about everything in Clojure at any time. Your vars, namespaces and so on.

st3fan 2020-11-20T18:44:49.112900Z

I now realize that what I am really asking is probably more about how do I structure an application that has some state associated with it. Both static (configuration settings) and dynamic (a redis connection). In Go I usually create an application struct to capture these things .. create one in main, then call functions on that struct.

st3fan 2020-11-20T18:45:09.113300Z

Understanding how this maps to Clojure is a gap in my knowledge

dgb23 2020-11-20T18:47:05.114300Z

There is a distinction of side-effects, like opening and closing connections, writing to sockets etc. And state, which lives inside your application.

st3fan 2020-11-20T18:48:37.115900Z

Are there some good examples available?

dgb23 2020-11-20T18:48:44.116100Z

There are patterns and libraries that are specifically used to deal with side-effects and configuration in a nice way like integrant. But generally yes, you’d use (def…) and store your connections there

dgb23 2020-11-20T18:50:30.117500Z

Generally people don’t concern themselves too much with making stuff inaccessible. Its rather a matter of communicating clearly what your public API is

st3fan 2020-11-20T18:51:27.118300Z

I am not so worried about visibility (inaccessible) - more about good structure and being able to test properly.

Darin Douglass 2020-11-20T18:54:06.119500Z

the standard trifecta for application state usually are: β€’ https://github.com/stuartsierra/component β€’ https://github.com/weavejester/integrant β€’ https://github.com/tolitius/mount each has their drawbacks/paradigms so you'll have to find what suits your needs best

πŸ‘ 2
Darin Douglass 2020-11-20T18:54:44.120200Z

there are others like https://github.com/juxt/clip and https://github.com/aroemers/mount-lite (my current fav, though i haven't tried clip yet)

2020-11-20T19:01:54.122200Z

Is there a way to destructure a map parameter to get the remaining keys? I thought it might look like this:

(defn f [{:keys [a & remaining]}] remaining)

dgb23 2020-11-20T19:03:00.122700Z

(let [[item1 :as all] names]
  (println "The first name from" all "is" item1))

dgb23 2020-11-20T19:03:10.123Z

from: https://clojure.org/guides/destructuring

dgb23 2020-11-20T19:03:29.123200Z

you mean this?

2020-11-20T19:04:48.123600Z

Yes like that but for a map rather than a vector

dorab 2020-11-20T19:08:58.124200Z

Not quite what you want, but close (defn f [{:keys [a b] :as all}] (println "All: " all)) ?

alexmiller 2020-11-20T19:09:36.124800Z

no, there is no way to do that

2020-11-20T19:10:48.125700Z

ok makes sense, I couldn't find a section on it. I'll just dissoc the other keys from map

st3fan 2020-11-20T19:23:21.127600Z

Probably preaching before the choir here - but the thing I love the most about working in Clojure is the REPL - I just figured out a weird base64 decoding bug by augmenting my server code to store data in a temp var and then I figured out the problem by just playing around with that interactively.

πŸ‘ 4
Xarlyle0 2020-11-20T19:36:42.130300Z

Heyo! I'm looking to improve my more professional coding skills, so I completed question 140 on 4clojure with the goal of creating the most understandable solution, with concise documentation that can lead someone through a difficult problem. Would anyone be willing to take a look at my solution and give feedback with regards to that goal? My username on 4clojure is xarlyle0.

2020-11-20T19:40:00.130400Z

I think #code-reviews is the right place for that, you can post it there without asking permission

2020-11-20T19:40:06.130600Z

This message is perfectly appropriate for the #beginners channel. I also wanted to point out #code-reviews channel.

Xarlyle0 2020-11-20T19:41:48.130800Z

Cool! I didn't know about the #code-reviews channel. Good to know, thanks

Xarlyle0 2020-11-20T19:51:34.131100Z

There are a lot of helpful people in the #beginners channel so I figured this would be a good place

Xarlyle0 2020-11-20T19:52:08.131300Z

But I don't know if people can actually access my code on 4clojure, so I didn't know if I would need to post the code here or not.

2020-11-20T20:01:10.131600Z

people can access it based on your user name, if they have an account that has solved the problem already

2020-11-20T20:01:14.131800Z

probably best to share the code here

Xarlyle0 2020-11-20T20:04:48.132Z

okay. Here is the code.

(fn [s]
  (letfn [; take a set #{A b c D}, and make #{#{A b c "D"} #{A b "C" D} #{A "B" c D} #{"A" b c D}}, note both lower and upper case symbols become capital Strings
          (get-subsets [coll] (set (map #(conj (disj coll %) (clojure.string/upper-case (str %))) coll))) 
          
          ; for each set #{A b c D}, make a map entry: {#{A b c D}, #{#{A b c "D"} #{A b "C" D} #{A "B" c D} #{"A" b c D}}}
          (get-subset-map [sets] (into {} (map #(vector % (get-subsets %)) sets))) 
          
          ; take one of the subsets #{A b c "D"} #{A b "C" D} #{A "B" c D} #{"A" b c D} and filter them by if they have a copy in the other subsets
          (get-intersect [subset-map pair] 
            (clojure.set/intersection
              (second pair)
              (apply clojure.set/union (vals (dissoc subset-map (first pair))))))
          
          ; #{A b "C" D} -> #{A b D}
          (remove-strings [i] 
            (set (map #(set (filter (comp (partial not= java.lang.String) type) %)) i)))
          
          ; for each answer, filter the original sets by whether none of the other answers is a subset. If the result is empty, then that answer is redundant, and is removed
          (remove-redundant [sets] (set 
            (filter (fn [ex] (seq
              (filter
                (fn [entry] (not-any? (fn [a] (clojure.set/subset? a entry)) (disj sets ex)))
                s)))
              sets)))
          
          ; Create a subset-map and use get-intersect on the values of each entry to see if there are any copies in the subsets.
          ; If not, then the key for that entry is NOT SIMPLIFIABLE. Then, remove the strings from the intersection to get the new simplified sets.
          ; Repeat until all sets are NOT SIMPLIFIABLE
          (simplify [sets]
            (let [subsets (get-subset-map sets)
                  intersect (partial get-intersect subsets)
                  final-entries (set (keys (filter (comp empty? intersect) subsets)))
                  remaining-entries (remove-strings (apply clojure.set/union (map intersect subsets)))]
              (if (empty? remaining-entries)
                final-entries
                (clojure.set/union (simplify remaining-entries) final-entries))))]
  
    (remove-redundant (simplify s))))

2020-11-20T21:48:26.133Z

For lein projects I use lein test-refresh, is their an equivalent test runner that watches for changes and re-runs tests for deps.edn projects?

seancorfield 2020-11-20T21:58:12.133700Z

@qmstuart Most CLI tools are listed on this page https://github.com/clojure/tools.deps.alpha/wiki/Tools#testing and it looks like Kaocha has a "watch" mode...

2020-11-20T21:58:59.134200Z

@seancorfield, thank you, wasn't aware of that page

seancorfield 2020-11-20T22:02:08.136700Z

...that said, I think it's a better workflow to get used to evaluating code as you write it and running tests against them from your editor, so you don't need to switch contexts, and you don't need to worry about saving partially edited code causing a test watcher to fail etc. If you're evaluating code as you write it (and have "test" expressions in Rich Comment Forms) you can get fast, localized feedback directly in your editor (against the REPL), and you can eval and test code without even needing to save it to disk.

seancorfield 2020-11-20T22:03:30.138100Z

I stopped using test watchers completely after I'd been doing Clojure for a couple of years. I still run test suites from the command-line as sanity checks on features/bug fixes before I push a branch, but mostly I run tests in my editor, as I'm working on code.

2020-11-20T22:05:08.138500Z

by rich comment blocks you mean (comment ,,, )

seancorfield 2020-11-20T22:07:32.139700Z

Yes. A term coined by Stu Halloway to describe Rich Hickey's use of (comment ,,,) forms in code to contain scratch code/setup/REPL-based tests etc. I'd been doing that myself for quite a while before I heard Stu call them that -- has a nice ring to it!

seancorfield 2020-11-20T22:09:41.140Z

Examples in one of my OSS projects: https://github.com/seancorfield/next-jdbc/search?q=comment&type=code

πŸ‘ 1