Is there a way to run the lein task after the uberjar? e.g java -jar foo-snapshot.jar -task foobar ?
I have db migration which I need to run before I deploy (ragtime migration). My build process builds the jar, I am trying to figure out how to run db migration from uberjar.
I typically do this by defining a my.project.migrations namespace, and then java -cp my.jar clojure.main -m my.project.migrations arg arg1 arg2
clojure is flexible enough to use its main to run any ns that has a -main, so you can have as many entry points as you like in one jar (but this is all totally outside the world of lein, which is a build / dep tool not an app runner)
maybe - best treated as a build/dep tool rather than an app runner
I don't think you can pass main args if you use -jar
you can java -cp foo-snapshot.jar the.main -task foobar
though
assuming the.main is your ns with a -main and it takes -task foobar
got it.
Are there any good resources for clojure testing patterns and best practices?
@c.westrom @jumar Thanks I’ll check out both of these
https://practicalli.github.io/clojure/testing/unit-testing/ Perhaps this one.
How does one read edn from a file in clojurescript? I usually just slurp.
Using shadow-cljs:
(def fe-config (edn/read-string (shadow.resource/inline "/config/fe-config.edn")))
where the /config/...
is on your classpathIt's essentially just the usual - wrapper around slurp in a macro, but with the (amazing) benefit of having changes to that edn file trigger hot reloads
@danvingo Dude, this is fucking awesome. Imma try it out now!
I’m starting to change my mind. I might end up not using react after all. I started migrating my site to use this generator called https://github.com/OrgPad-com/volcano, and I’m starting to think that the react magic may be useful.
Not that I agree with all of that but this can be useful: https://github.com/plumatic/eng-practices/blob/master/clojure/20130821-testing-principles.md
@seancorfield Thank you for a super nice documentation. https://cljdoc.org/d/seancorfield/next.jdbc/1.1.646/doc/datafy-nav-and-schema
cljs running in the browser? Won’t you need to slurp the file on the server and send it to the client?
Documenting datafy
and nav
seems very problematic because the semantics are both very poorly documented in Clojure itself and very poorly understood even by people who implement these protocols.
As an EDN file is Clojure data, the data could instead be put into a namespace in the ClojureScript project as a def and required in the relevant namespace. This assumes you don't need a specific edn file, just the data of course.
So here’s what I’m doing. I’m generating a SPA using reagent. I want to be able to have all my data (stuff that I want to swap out later, like names, emails, links, localization) in a separate file. I would just call a cljs file with my data, but I also a clj file to read that data as well. I tried using cljc instead, but unfortunately it doesn’t work.
In the end, it’s a static site that I want to create, and I don’t want react in there. I’d much rather have it use hiccup to spit some static html. The only reason I’m using this approach at the moment is because of a couple npm libraries and shadow-cljs. Both shadow and tailwind make it so easy to do iterative design.
A single data model is my default starting point. It helps keep the overall design of the code simple. If components of a system are very distinct or have little interaction with each other, then it seems more likely that they would be treated as individual sub-systems (or even spilt into their own system), so a specific data model would seem more appropriate. If components are highly integrated, then typically I would expect them to share a common data structure. These are my general guidelines, every system has its own constraints that need to be considered carefully.
For static sites I have just used figwheel-main +reagent and included http://bluma.io CSS library via the html page from a CDN. No npm overhead. I haven't dived into shadow, sorry. Perhaps more help on the #shadow-cljs channel
Hi everyone, Would someone be able to point me to beginner resources about building a browser extension in clj or cljs? I cannot find a great deal of things out there and struggling with making my own tooling from existing tools as I’m at the very, very beginning of my learning 🙂
I did not do this but my guesses are that if you did not yet check how to build extension without cljs first check that like google how to make browser extension then look how to compile cljs file to javascript then check how to reference variables that webextension would reference from cljs like globals in browser
so if your extension would in javascript do something like window.navigator bla bla then you can reference same global from clojurescript you just have to compile clojurescript and make sure when you package extension you put everything clojurescript needs in there
There is chromex:
https://github.com/binaryage/chromex/ with good documentation
…and examples https://github.com/binaryage/chromex/tree/master/examples
From my limited experience anything but a trivial extensions, can actually be quite tricky (so if you’re really “at the very, very beginning of my learning” be prepared for that 😉 )
Hello!
I can't seem to find where the loading of user.clj
is documented. Can someone please point me in the right direction?
Background: Wanted to start my ring-based webserver automatically when starting nREPL in Cursive and discovered the existence of user.clj
in https://cognitect.com/blog/2013/06/04/clojure-workflow-reloaded by coincidence more or less.
user.clj is loaded if found on the classpath, when you load a file all the code in it gets run
that's really all there is to know (besides of course idioms / cleverness for setting up your dev env by putting fun and useful things in user.clj)
I personally have a ~/user.clj that isn't on class path, and use load-file
to source it into a repl, because having to explicitly source it eliminates a source of weirdness from my dev flow
just like any other clojure file, any top level side effects run when the file loads, and any definitions get installed in that file's ns (user, for user.clj, of course)
I think of it as clojure's dot file for local dev (and similarly I keep my dot files as empty as possible except when it comes to UI flow tweaks)
Thanks.
also - don't put a user.clj file in your repo - instead, use config to add its location to that repo's classpath, a user.clj shouldn't end up in your jar / deploy
I understood that already, but was looking for more in-depth information to understand the platform as a whole.
there's nothing else to know frankly
it can do what any other clojure file can do when loaded
Yeah, but I kind of wonder why it's not mentioned anywhere on official http://clojure.org.
probably because it's so simple / supported but not encouraged? but that's mind reading, a clojure core dev should answer that
Anyway, I appreciate you answers nonetheless.
one design concern is the conflict between a personal project-agnostic user.clj and a user.clj that provides behavior to one project, arguably the latter is better off being a custom entry point (nothing stops you from having a -main
for dev that both launches a web server and an nrepl server)
Thank you @prnc I’m going to look at Chromex. Cheers @nikola806 – seems like this is more “the clojure way”: understand it properly, then build it youself 🙂
Is it a REPL's job to load user.clj? Or is it baked into clojure core?
clojure core
the load happens in the core init https://github.com/clojure/clojure/blob/b1b88dd25373a86e41310a525a21b497799dbbf2/src/jvm/clojure/lang/RT.java#L486
that has to be my easiest clojure search source yet the only mention of the string in the codebase
some of us are not a fan of user.clj -- the presence of it can lead to a surprising initialization process
There we go, thanks!
yeah I consider checking a user.clj into a repo bad hygiene, similar to putting a .emacs or .vim file in a project
Me too.
Next logical question would be: How else do I bring nREPL to execute some app init code on startup?
add nrepl as a dev profile lib, have a main that starts it
nearly a one liner
"it" being the server? In my case the ring.adapter.jetty.run-jetty call
it being nrepl, the jetty call is a second one liner
https://github.com/nrepl/nrepl
https://nrepl.org/nrepl/usage/server.html
(start-server :port 7888)
that doc also has build tool config for implicitly starting nrepl alongside another task
for safety you might want the ns that starts nrepl to not end up in your build
with tools.cli, can i parse an option with an optional value? so somehow --opt 123 --other
and --opt --other
should parse to {:opt 123 :other true}
and {:opt true :other true}
(not to {:opt "--other"}
)
Ah, thanks. Guess I should have explained my setup better, though. My current noob setup is to start the REPL and within the REPL start the jetty-adapter with my root request handler. If I understand correctly, you suggest to have an ordinary main and start the REPL in there. The reverse somewhat.
Btw, I am aware that I should probably not operate my webserver via a REPL in production.
@ban.istvan No. An option either has a value (argument) or it is a boolean toggle. It can’t be both.
@seancorfield I liked the ddl on the old next.jdbc, I couldn't find ddl docs on the seancorfield/next.jdbc, any pointer? I can also use the old one just for the migration, wondering what is the recommended way.
@munichlinux What DDL in c.j.j do you mean?
You’re just going to call jdbc/execute-one!
with a SQL string to do DDL stuff, right?
c.j.j only provided half-hearted CREATE TABLE
and DROP TABLE
helper functions — you still had to execute that SQL. If you want more of a DSL for building SQL, look at HoneySQL: it has extensive DDL support in v2. See https://cljdoc.org/d/com.github.seancorfield/honeysql/2.0.0-beta2/doc/getting-started/sql-clause-reference#ddl-clauses and https://cljdoc.org/d/com.github.seancorfield/honeysql/2.0.0-beta2/api/honey.sql.helpers for details.
@seancorfield got it
@munichlinux Feel free to ask any related Qs in #honeysql and/or #sql (I’ll be more likely to see Qs there than here).
nice, Thank you
And don’t be put off by HoneySQL v2’s Beta status — quite a few folks are already using it in production. We have a mix of v1 and v2 in production ourselves.
perfect! I am taking all that to production as well.
FWIW, at work we wrote our own ad hoc migration setup, but if I was starting over with that I would use migratus
(and we just use standalone SQL files, with a Clojure script that sucks them in and runs jdbc/execute-one!
on each statement)
Looking at migratus. I was thinking about using ragtime.
I have a function like:
(defn a-fn []
(let [v1 (compute-v1)
v2 (compute-v2 v1)
v3 (compute-v3 v2)
v4 (compute-v4 v3)]
v4))
Every computation compute{v1..v4}
might fail (indeed - they are expected to often do so). In that case I'd like to show a nice error message (perhaps with more metadata and suggestions for what might have gone wrong) to the user. Is there a nice pattern for doing this? I could have a lot of try/catches but that feels non-functional.instead of returning just the value return a map of {:error ...}
or {:value ...}
and write all your compute functions to pass maps that contain :error through unchanged
(the Either monad if you need a name for it)
Feels very functional (monadic-ish). Thanks!
I should have thought of it.
if you can then add things like (defn app [f] (fn [x] (if (contains? x :error) x (f (:value x)))))
or I guess (defn app [f x] (if (contains? x :error) x (f (:value x))))
would be better for the name app
sweet! migratus supports https://github.com/yogthos/migratus#defining-a-code-based-migration
Sometimes the error messages occur in libraries I use. I rely on stuartsierra/dependency
which throws an error in case of a circular DAG for example:
(-> (dep/graph)
(dep/depend :a :a))
;; Execution error (ExceptionInfo) at com.stuartsierra.dependency.MapDependencyGraph/depend (dependency.cljc:89).
;; Circular dependency between :a and :a
What is the best way to collect such errors?Yes, yes clever! I have played around with Haskell, so I like this solution a lot.
Just have a general catch Exception
and put the Exception
s collected into the map I pass around? Also, this feels like it would be a lot of duplication of code. In Python it seems like the kind of thing I'd do with decorators. Should really read up on this.
(defn app [f x] (if (contains? x :error) x (try (f (:value x)) (catch Exception e (assoc x :error (ex-data e))))))
ex-data
probably isn't what you want but it's probably a part of what you want to get from any errors
@endrebak85 most libraries do not throw exceptions, except to mean 1) "you're holding it wrong" or 2) this is unrecoverable
e.g. network disconnect -> that's an exception
carefully choose places to catch and turn exceptions into data
I see and agree. I never throw exceptions, but a few of the libraries I use might.
Also I like the map of :error
and :value
approach because then I can add a :warnings
-key too.
cognitect.anomalies is another approach in this space:
It's interesting reading the ongoing discussion about error handling. I know Java pretty much demands the use of lots of try/catch blocks, but I don't use them at all in Clojure ...
you'll need to use them any time you interact with IO
I'm actually tempted to just have a top level try/catch
for now. I'll use a more advanced pattern when I see a need for it.
Clojure isn't isolated from having to handle problems coming from disk or network or buggy libs
that's a fair point. so mainly for IO
I am getting this error when trying to pprint a vec in my code:
java.lang.ClassCastException: class clojure.lang.PersistentVector cannot be cast to class java.io.Writer (clojure.lang.PersistentVector is in unnamed module of loader 'app'; java.io.Writer is in module java.base of loader 'bootstrap')
When I try in a REPL it works just fine.
What might be wrong?somewhere something has the arguments reversed
The problem was that I was sending two arguments to pprint
. (print "a" "b")
works, but not pprint.
A very basic question: (In Clojurescript) I generate some <input> tags (hiccup), and the first one should be set with {:autofocus true}
, the rest without. So how to single out the first element as such. (Very basic if you control the RAM, but in FP not so much.) PS: I loop via (for [x map] ...)
. Thanks!!
there are many ways, but probably you want something more idiomatic for generating UI than a for loop
I've used for quite a lot for streamlining hiccup style code in ClojureScript.
So I am curious at so what is more idiomatic than for
in Clojure in this case.
This has been mentioned to me before, but haven't been offered alternatives.
The constraint I am aware of is that for
is not composable, but that is not an issue for the hiccup generation code I'm writing.
could be totally fine in that particular case 🙂 I hope my casual comment doesn't lead to people questioning their working practice, that would be the opposite of what I wish for
if you share some example, that would be easier to discuss specifically without making bad general judgments :)
Just curious as someone said something similar a few years ago but didnt elaborate. I like for as its list comprehension is very simple and very powerful for specific cases.
@bastilla perhaps (for [[x auto] (map vector your-data (cons true (repeat false)))] ...)
so auto
will be true for the first item and false for all the rest.
I would probably write something like:
(for [[i x] (map-indexed vector xs)
:let [first? (zero? i)]]
[:div (merge {:normal-prop "foo"}
(when first?
{:autofocus true}))
...])
I'd take the "most" idiomatic approach there is. Especially if that info (first element) is then easily accessable. So far I did't see any probs with for
.
(but there are all sorts of possible answers)
Any ideas why running lein run
on a luminus project wouldn’t generate an .nrepl-port
file even though nrepl is starting up?
I get your approach @seancorfield. And @smith.adriane, I don't know map-indexed
yet, but will definitely have a look at it. Meanwhile I came up with this idea:
(doall (for [x map :let [first? (= x (first map))]] ...))
If this is horrendous, pls grab my arm. I'd also like to say (again) how awesome it is to have folks like @seancorfield and all these illuminaries answer to noobs like me. Again, this community is really supportive. ok, 'nuff lickspittling, just saying.How can I filter on a nested data structure, eg. I want to filter out all even numbers in [{:a [0 1 2 3 4]} {:b [5 7 8 9]}] => [{:a [1 3]} {:b [5 7 9]}]
?
I would advise against checking (= x (first map))
since it may return true if map
contains duplicates.
Instead of (doall (for [x map] (do-stuff :to x)))
you could do (mapv #(do-stuff :to %) map)
and then you’re guaranteed a vector result and you could just (assoc-in result [0 :autofocus] true)
— or whatever is the appropriate path into that first element.
I guess it won't have duplicates in the case that map
is a hashmap, but if you reuse the same code elsewhere, it might get you into trouble
Given it’s using for
, I wouldn’t expect it to be a hash map but maybe…?
right, but it is called map
🤷
the easiest way to do this is via (mapv #(into {} (map (fn [[k v]] [k (filterv odd? v)]) %)) xs)
, if you need to do this for arbitrarily nested lists then you might need to use something from clojure.walk
(let [arr ["a", "b", "c"]] (vec (concat [(clojure.string/upper-case (first arr))] (rest arr))))
Yes, it's a map. Thanks a lot (and
@seancorfield @smith.adriane @ashnur`)`. I have plenty of mind food again.
@bastilla You know that hash maps are unordered, so you’ll get your fields in a random order, depending on how many items are in the map and what their keys are?
So there’s really no sense of “first” in a hash map — it’s just a random element that happens to appear in the first slot when the hash map is converted to a sequence…
Yes, I know. Idea was: first
should get the same elem as for
(at first take).
But I guess this isn't guarantueed.
True, it does — because seq
is repeatable for the same hash map. But getting your HTML fields in a random order seems… weird…
Concerning HTML forms, you're right. I was just curious and had this question at other occasions, too.
I’d rather do this purely for readability purposes
(for [entry data
[k v] entry]
{k (filter odd? v)})
Is there an idiomatic way of assigning a conditional value? For example; if foo is empty then assign x to “bar” else assign x to “baz”
(let [x (if foo "bar" "baz")] ...)
Hm, I could swear I tried that.
Ah, I see what I did wrong. Thanks @hiredman!