Fork me on GitHub

so I discovered that (via supports an option :skip-whitespace that seems to work just fine, but isn't documented anywhere I could find really. Based on the contrib guidelines I opened an Ask Clojure question about it to stop people like me reinventing it. I'd be happy to do a PR to add a sentence to a docstring or something, but it looks like it has to get created in Jira before I could request a contributor account?


I am new to Clojure. What is the descison point if I want to use Leiningen or CLI or neither on my project? Why do I want these or not?


You can learn to use Clojure command line directly


Both are package managers, you'll probably want to be using one (unless you really want to go raw) Following is purely IMO: Lein is fairly heavyweight but has many years of tooling to do magic (speak the correct incantation and things just happen) CLI is newer, officially supported, and while it has less tooling currently available (still a good amount), it's a lot simpler than lein. A lot of tooling seems to have moved over to CLI now.


CLI is quite fantastic so far, just because of its ability to compose builds together. You'll often see things like clj -A:dev:testwhich is composing the dev and test aliases together (a bunch of options that come with).


For a newcomer though, it doesn't matter that much which you start with. If the tutorial you're using is using lein, use lein. Once you understand things a bit better, it's not a particularly huge amount of work to convert from lein to cli/deps


Agree. for example a basic usage, run a clojurescript repl from CLI is just:

clojure -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.758"}}}' -m cljs.main --repl-env node


If there's no preference in the tutorial, use CLI/deps


if you want to do the same with lein you have to write a project.clj file and import your clojurescript pkg. and after run it from command console


@U016Y40A58A As a data point, we used Leiningen at work when we got started back in 2011. We switched to Boot in 2015 because we had a large, complex monorepo with a dozen or so subprojects and wanted something more "programmable" than lein. We were happy with boot at first, but as our project grew, we began to run into quirks and bugs, so we switched to the (very new at the time) Clojure CLI in 2018. Once we had a few extra bits of tooling in place, we were very happy with that switch.


You'll find lein is used in a lot of books and tutorials so you'll probably want to have it installed, just to get through those. But I would recommend focusing on Clojure CLI for your own projects, coming into Clojure at this point in time.

☝️ 3

You'll probably find my repo for examples of aliases and what you can do with clj and deps.edn.

☝️ 9

@U016Y40A58A For beginners I do recommend Clojure CLI tools and deps.edn projects. It helps with understanding some of the mechanics of Clojure works on top of the JVM (it is a hosted langauge after all). I find Clojure CLI tools much clearer to understand things, where as Leiningen and especially plugins do a lot of work for you and you learn less. If you just want to build something in Clojure though, its more important to find a good tutorial. There is a wide range of community tools on top of the Clojure CLI tools. I am moving my workshops and tutorial over to Clojure CLI tools

Walt Stoneburner19:07:23

Someone told me I needed to add (:gen-class) to all my namespace definitions, so I did. My understanding is that this would do Ahead-Of-Time (AOT) compiling, generating .class files behind the scenes. I thought I remember that some documentation stated that if you're using the REPL, it's ignored. While still a beginner compared to the rest of you, I notice at times I end up stopping and starting my environment (as opposed to in-REPL trickery) when I have "big" changes and want to start from first run as part of my learning experience so that I don't pollute my namespace with hand injected values and delude myself the code is working when it's actually my tinkering. I've noticed that ever since adding that clause, I often get compiler failures that act like an older "cached" copy of the .class file is hanging around, because if I do lein clean, then suddenly I get very clean error messages, filenames, and line numbers like I'm used to. What's the black-magic behind :gen-class, is it like a compiler's #pragma, and have I added it too early on in the development cycle? The only goal in the long run is to be able to build a .jar file with lein uberjar and have that all be Java .class files, not Closure for folks to pick through.


adding gen-class to everything is a terrible idea

👍 3

gen-class causes the namespace to be reified into a class, it causes recursive compilation of everything used in that ns

Walt Stoneburner20:07:35

I'll go ahead and remove it. Thank you for helping me understand what it's doing. At some point I'll want to distribute my application as a uber .jar file, but will not want people poking at the source code. Removing :gen-class isn't going to get me into trouble there, will it?


you can still compile your code to class files without gen-class


in lein the option is :aot :all


If you are planning to build an "uberjar" that you can run with just java -jar path/to/your.jar, then you will need (:gen-class) in just the one namespace that contains your -main function. But there are other ways to run uberjar files without doing that: java -cp path/to/your.jar clojure.main -m your.main.ns -- that will use the uberjar as the entire classpath, run clojure.main/-main to start the process and that in turn will invoke your.main.ns/-main (because of the -m option which clojure.main recognizes).

🙏 3
Micah Redding23:07:53

I'm trying to follow these instructions for using Clojure & Stasis, but quickly run into an error. Is there a good place to understand what I'm encountering here? I recognize that these are kind of dated, and I'm a total beginner, so I'm open to any kind of feedback—including use a different project.

Micah Redding23:07:18

OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
clojure.lang.Compiler$CompilerException: Syntax error macroexpanding clojure.core/fn at (clojure/core/unify.clj:83:18).
#:clojure.error{:phase :macro-syntax-check, :line 83, :column 18, :source "clojure/core/unify.clj", :symbol clojure.core/fn}
Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/fn did not conform to spec.
#:clojure.spec.alpha{:problems ({:path [:fn-tail :arity-1 :params], :pred clojure.core/vector?, :val clojure.core.unify/var-unify, :via [:clojure.core.specs.alpha/params+body :clojure.core.specs.alpha/param-list :clojure.core.specs.alpha/param-list], :in [0]} {:path [:fn-tail :arity-n], :pred (clojure.core/fn [%] (clojure.core/or (clojure.core/nil? %) (clojure.core/sequential? %))), :val clojure.core.unify/var-unify, :via [:clojure.core.specs.alpha/params+body :clojure.core.specs.alpha/params+body], :in [0]}), :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2509 0x78e16155 "clojure.spec.alpha$regex_spec_impl$reify__2509@78e16155"], :value (clojure.core.unify/var-unify [G__800 G__801 G__802 G__803] (clojure.core/if-let [vb__793__auto__ (G__803 G__801)] (clojure.core.unify/garner-unifiers G__800 vb__793__auto__ G__802 G__803) (clojure.core/if-let [vexpr__794__auto__ (clojure.core/and (G__800 G__802) (G__803 G__802))] (clojure.core.unify/garner-unifiers G__800 G__801 vexpr__794__auto__ G__803) (if (clojure.core.unify/occurs? G__800 G__801 G__802 G__803) (throw (java.lang.IllegalStateException. (clojure.core/str "Cycle found in the path " G__802))) (clojure.core.unify/bind-phase G__803 G__801 G__802))))), :args (clojure.core.unify/var-unify [G__800 G__801 G__802 G__803] (clojure.core/if-let [vb__793__auto__ (G__803 G__801)] (clojure.core.unify/garner-unifiers G__800 vb__793__auto__ G__802 G__803) (clojure.core/if-let [vexpr__794__auto__ (clojure.core/and (G__800 G__802) (G__803 G__802))] (clojure.core.unify/garner-unifiers G__800 G__801 vexpr__794__auto__ G__803) (if (clojure.core.unify/occurs? G__800 G__801 G__802 G__803) (throw (java.lang.IllegalStateException. (clojure.core/str "Cycle found in the path " G__802))) (clojure.core.unify/bind-phase G__803 G__801 G__802)))))}