This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-27
Channels
- # aws (8)
- # beginners (172)
- # boot-dev (4)
- # cider (16)
- # cljs-dev (123)
- # cljsjs (4)
- # clojure (90)
- # clojure-brasil (3)
- # clojure-dev (7)
- # clojure-dusseldorf (1)
- # clojure-finland (1)
- # clojure-italy (59)
- # clojure-russia (3)
- # clojure-seattle (2)
- # clojure-seattle-old (1)
- # clojure-spec (40)
- # clojure-uk (28)
- # clojurescript (327)
- # clojurewerkz (3)
- # code-reviews (8)
- # cursive (4)
- # datomic (24)
- # editors (1)
- # emacs (19)
- # fulcro (147)
- # funcool (1)
- # graphql (1)
- # hoplon (34)
- # jobs-rus (1)
- # lein-figwheel (5)
- # leiningen (20)
- # luminus (14)
- # midje (1)
- # off-topic (8)
- # onyx (7)
- # parinfer (47)
- # pedestal (1)
- # perun (1)
- # portkey (46)
- # re-frame (25)
- # reagent (9)
- # remote-jobs (4)
- # ring-swagger (5)
- # rum (1)
- # shadow-cljs (113)
- # slack-help (8)
- # spacemacs (7)
- # sql (9)
- # tools-deps (23)
- # uncomplicate (3)
- # unrepl (3)
- # yada (6)
Async/await is basically just sugar around promise so the only way you could do that is by code rewriting like core.async
, wild guess here of course, haven't looked at the Promesa code
@lee.justin.m yeah, the thing is I can’t see any way to do that using promesa.
Looking at the alet
code, the strange thing is that the await
s should be taken out during macroexpansion.
In this case, I think the mechanism by which the async
can propagate is that the function returns a promise. So in code calling that function, I would also have to use alet
or manually handle the promise.
yea that’s exactly how you’d do it in javascript, and since promesa is using promises i think that’s probably what you need to do there
i would think it’d be something like (alet [x (await (fn [] (alet [x (await something)] x)))])
Right, that’s essentially what I’m doing, except I’m manually handling the promise using then
in the caller.
But I think the issue is that alet
isn’t macroexpanding correctly since the expansion should have removed the await
from the code.
You should also be able to do (-> (alet [x (await something)] x) (.then (fn [x] do-something))
Oh, I think I see the problem. I don’t think I can do (alet [x (when y (await (z)))] ...)
It may be possible to implement that, but alet
doesn’t right now - it just checks that the right hand side of the binding is a coll, and that the first symbol in the coll is 'await
.
Thanks for the help though, I feel like I improved my knowledge of the async stuff in general 🙂
im having a hard time googling this — but does cljs have a built-in fn for converting a cljs ns -> js ns? it would do something like symbol -> string -> replace / with . -> replace - with _
ive been writing an “unsafe” resolve
for cljs which basically just farms-out to js-eval such that it still works under advanced comp
@U0W0JDY4C that sound pretty much impossible?
the intent was to essentially just do window.namespace.name_space.fn
in such a way that advanced compilation will still work, and our “invocation” just becomes window.a.b.c()
when compiled
Hello to everyone
I am trying to start using clojurescript, but I am having a very bad time
Being used to JS this is very hard to setup
Anyone could point me to a more or less modern template for building node-js targeted clojurescript ?
Thans @joelsanchez But that includes figwheel, do I really need it for node-js commandline scripts =
no but you'll need it for development
I'm using this one: https://github.com/yanatan16/cljs-node-app-template
But it is very old, and does not include modern cljs capabilities
you may be able to use lein ancient
on your project and simply update clojure and clojurescript
I say "may" because something might break
I have been updating them manually, currently using [org.clojure/clojure "1.9.0-alpha15"] [org.clojure/clojurescript "1.9.521"]
But I'm affraid there is a lot of boilerplate
An unnecessary stuff like :npm {:dependencies [
instead of npm-deps
I'm quite confused, to be honest
wish I could help you but I'm not familiar with npm-deps or node, sry
I am familiar with node
Very familiar
But not with clojure and lein
@rdanielo what is that is giving you bad time in the vanilla cljs setup?
@richiardiandrea is not the vanilla cljs, is setting up an environment for a non-trivial node-js app
The template provided by @joelsanchez seems to be very good. I discarded it at first because it was using figwheel, which I though was just for the browser
@rdanielo just trying to understand what specifically is failing so that I can help further
But I am a bit confused
How should I manage npm deps ?
Adding them to package.json or adding them to the compile option of project.clj ?
With :npm-deps
Ok, that makes sense. My old template was using :npm { :dependencies
Should I duplicate them both for dev and prod builds ?
Seems redundant
So how you "install" the npm deps this depends on you
You can use npm or let cljs install for you
Yes you need that redundancy at the moment
But a build.cljs
is a program that could potentially parse package.json
But that is already an advanced topic, better to get the basics first
I would prefer to move to the entire cljs ecosystem
So I think I will add them to :npm-deps
Also, this is vanilla cljs - there are also alternatives like shadow-cljs
or lumo
Yep try that out and let me know how it goes, the new quick start cljs.main
makes things super easy
Yes, I've been reading about it here: https://anmonteiro.com/2017/03/requiring-node-js-modules-from-clojurescript-namespaces/
Coincidentally I also need to use an npm module (uppy), am targeting the browser. I use figwheel with leiningen. Does this apply to leiningen as well?
Because I get
---- Could not Analyze src/cljs/cs2/components/widgets/uppy.cljs ----
No such namespace: uppy, could not locate uppy.cljs, uppy.cljc, or JavaScript source providing "uppy"
Seems to make interop very easy
What is that cljs.main that you are talking about ? which kind of quick start is it ?
It has just been released, all the new doc should be up to date
But what is it ? Is a template ? A compiler ? What is it?
Something that I'm missing is something like npm install for lein. I mean, I want to just make 'lein npm-install request' and make that add it to my deps
Scroll down into node.js
This section right ? https://clojurescript.org/guides/quick-start#running-clojurescript-on-node.js
Are you related to the project ?
Because I have feedback about that docs, but not sure where to report
No, I am a contributor as well, feedback can either be sent here or to https://dev.clojure.org/jira/browse/CLJS
They don't accept PRs on GitHub ;)
awesome, thanks
Is there any good cljs http request library ?
I use node stuff directly usually
I see
I started making a wrapper around request, but I did not wanted to re-invent the wheel
Do you use promises on cljs ? Or is it better to use core.async with callbacks ?
depends on the use case, I personally use both
@richiardiandrea I may be wrong but I think the ClojureScript Site does accept issues and PRs via github https://github.com/clojure/clojurescript-site
@tmulvaney @richiardiandrea @rdanielo that’s right they do accept PRs on the clojurescript site for docs--I just submitted my first one.
@rdanielo One point to help you out: much of what you read about “npm-deps” and using npm modules is going to be geared to the specific problems of doing on the browser, not node. Things are actually easier for you on node because you do not need to worry about advanced compilation, which requires some care, and you don’t need to worry about code size. Although I can understand the appeal of moving everything to cljs, I actually recommend that you manage you npm dependencies using npm or yarn and a package.json. Your life will be much easier.
@tmulvaney @rdanielo my bad they do accept PRs for the docs
Since file size may not be a problem, saving some extra bytes will be a great addition
This article seems very clarifying: http://www.functionalbytes.nl/clojure/nodejs/figwheel/repl/clojurescript/cli/2017/12/20/tools-deps-figwheel.html
Ok, so I've tried the new cljs quickstart guide too, and also installed clj cli tools. Everything's smooth, but there are a couple of things I would definitely not like if I was a beginner: 1) I want to start a node repl, but this thing also starts a jvm process (which eats half a gigabye of ram btw); why? Confusing. 2) Stacktraces. Not helpful. I wish they were either hidden completely or written to a logfile. "IllegalArgumentException: Namespace hello-world.core does not exist" is enough to figure out the problem, no need for the stacktrace in the stdout. 3) Exception that are not catched. If I accidentally close the repl page, I get "java.net.SocketException: Broken pipe (Write failed)". I wish it would say "can't connect to the browser; is the repl open?" or something like that. 4) print-length and print-level. I wish they were set to reasonable default values in the repl, so (range) won't blow up in your face. I think that's all. By the way, clj --repl is really fast compared to lein repl, it only takes a second or so to run. Very nice for a beginner.
@just_crashed first thing to understand, we do not change things just because it is good or bad for beginners - that is, it’s something to weigh against everything else
1) ClojureScript is written is Clojure - we remote control JS runtimes - that’s just how it works. JVM has means for managing RAM usage - we’re not going to get into that in the Quick Start
3) other REPLs do fancier error handling, we don’t want to maintain that kind of thing in browser REPL
4) we’re missing support for user.cljs
, would be a nice way for user to set stuff like that
@dnolen I understand that, but at the same time I feel like official getting started guide is kinda meant to be targeted at beginners first and foremost; after all, if you're not a beginner, you probably already have your cider\cursive and .lein/profiles.clj (or whatever build tool you use) set up. At the same time, I understand that maintaining beginner-oriented stuff in core cli tools is probably not a goal.
Hm, can you elaborate a bit? I realise don't quite see the place of clj in the clojure infrastructure then. I thought it was meant as a lighter\more basic\more stable alternative to lein for those who don't need any advanced stuff. Should it replace lein as the main build tool in the future? Also, do you think it might be worth mentioning community projects like maria.cloud on the getting started page then?
but as an experienced user my own opinion is that clj
is better suited to how I want to work
I’ve been using all the various options in anger for years now, and clj
does what I actually want
Tbh I feel kinda uncomfortable about that, since clj and lein use different config formats, library authors have to worry about several build systems, etc. Although probably that's unavoidable anyway, sooner or later alternatives show up anyway.
re cljs.main - yeah, I understand that, but I kinda can see that some people would prefer clj\cljs.main "stack" and others lein\figwheel "stack". But yeah, it's more of an imaginary construct, nvm
I’m struggling here. what’s a good strategy for actually storing the response that comes back from something like this: https://github.com/r0man/cljs-http#async-response-handling
@U060QNFEZ you can use it as a future, you can add all responses to a single channel, it depends; what exactly are you trying to do?
(defn get-weather-data
[]
(go
(let [response (<! (http/get
""
{:with-credentials? false
:query-params {"zip" "53149,us"
"units" "imperial"
"appid" "supersekret"}}))
weather-data (get response :body)]
weather-data)))
@just_crashed the problem is i can only capture this within the go block. i’m missing the mechanism for now i can reference this to get the value on demand so to speak
go block returns the last expression as a channel, so in general you can read a value from a block just like you would read from any channel
so basically it depends on how do you want to store and process your results after you've received them
also, see examples here: http://clojuredocs.org/clojure.core.async/go
@just_crashed what do you think would be the simplest approach if from a high level my goal is to fetch weather-data once an hour
i just want an edn map in my state db called “weather-data” which is the body of that response.
@just_crashed yes the db is pretty small
(def default-db
{:time-current (helper/get-time-data)
:weather-data (helper/get-weather-data)})
i can prn out the response in the repl so the call works. just trying to navigate the async nature of this
thnx for helping me. pretty new to cljs side of things and have barely played with core.sync
well basically you have the value you need inside the go block, right? then you can add it to the db via an event
since you need to check it every n minutes you will have a go-loop with a timout or something like that
so you do your api call, check if it's alright, dispatch an event to re-frame, then wait for a timeout and repeat, something like that?
yeah i have it all set up as far as the event sub and view flow from there. just didn’t understand how to get the value of the channel. as i have it written now it just returns nil
In the code you've posted above, you're getting the value out of the channel into 'response'
oh correct and if i add a prn statement in there i can prove it’s really returning the response
but since the whole things is wrapped in the go block if i call get-weather-data
it returns nil
...and if you replace "prn" with "dispatch-sync" you will add your weather data to the db
i think i get it, im thinking about this a bit wrong. the operation needs to happen inside a go block
so in my initial db state and in my event i need those actions to happen in a go block
and i only need the go block in my helper namespace because i’m referencing the value to grab and return the body
and i have the handler and so on already written as i’m displaying fake static values in the ui
@just_crashed im curious is there a best practice for how to initialize a re-frame app database? i’ve had odd behaviors where and event dispatch updates the db but then flips back to the old data.
I believe initial dispatch-sync should be enough, but I'm not a re-frame expert by any means
are you sure you didn't use the async version? because that might mean some other handler runs before initiliazation is finished
@just_crashed yes the distinction is completely imaginary
if tools were instead a la carte libraries like ClojureScript is as a baseline - we wouldn’t be in this mess
So your idea is to use clj as a single entry point and let all other tools be a libraries that run inside that? But we still at least need config files and stuff, I don't really see how e.g. making lein a library would solve the project.clj vs deps.edn problem. Did I misunderstand you?
Oh, and lein was there long before cli tools, so I guess people didn't really had an option to make it a lib back then?
That being said, I'd really like if build tools followed the Ring example, but that still implies a common spec format
if you want to build specific integrations for lein
or boot
cool do that - but do ^ first
Well then you would automatically "un-lein" anything lein-specific, so it could be used from any repl
But yeah, it'd be a temporary ugly workaround instead of a common sense long-term solution
By the way, I've checked the repl guides at http://clojure.org - damn! That's some awesome documentation! Really great work, don't know how I've missed it. Kudos to everyone involved.
Hey, is anyone using nightlight for ClojureScript nodejs development? Seems like an easy way eon have a cool editor with repl and few configuration
Hello Clojurians! I have a very small problem with my production site, but still annoying enough! In my css I use 'url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2000' height='2000' viewBox='0 0 800 800''..., but after lein uberjar it looks like "url("data:image/svg+xml,%3Csvgxmlns='http://www.w3.org/2000/svg'width='2000'height='2000'viewBox='00800800'%3E%3Cgfill='none'%3E%3Cgstroke='%23ab8e1b'stroke-". So all spaces gets removed. What do you think causes that? I guess some cssminifying from lein uberjar, but I can't manage to find it.
seems like cljs.main is both a "beginner's entry point" and an "expert's clojurescript tool" and lein and boot are still there for "everything in between"
existing projects are likely to use lein
or boot
, but if I was doing something new I would just use clj
these are also not mutually exclusive
I see it more like a tradeoff between rolling your own command line pipeline vs use something battery included...many devs have different ways of tackling how they want to build an artifact
you can use plugins with lein or boot that pull deps from a deps.edn
I see the whole thing now more "pure" cli friendly though, which is good
(because I like cli, subjective 😄)
Having both project.clj and deps.edn (just to fetch git deps I presume?) is, well, less than optimal imo. I would much rather prefer lein supporting everything "natively" so to speak
well, I don’t personally know why that is necessary, or even desirable - but if the lein community wants to sort that it will happen - but doesn’t seem like much of a win to me
also eventually you should start wondering why ClojureScript ~20,000 lines of Clojure starts faster than lein
Sorry for quoting myself, but I think it got missed
@rdanielo maybe check the #nightlight channel? It seems like they definitely support browser based dev
@dnolen well, I don't imply that lein is somehow technically superior or something like that - I really don't - but if I have a choice, I would prefer not to have two config files instead of one (if that doesn't provide some obvious huge benefits). It's just easier: here you have your profile, with source paths and deps. Now if you add e.g. lein-tools-deps you have to add plugin deps to project.clj, other deps to deps.edn. You can argue that it this case it's not a big deal, but things tend to add up. If something goes wrong, the fewer places you have to look = the better. So I would definitely prefer tools.deps to be used as a lib (just as you've said earlier!), with all the possible burden of integration handled by the lein people and NOT exposed to the end-users. Another thing to consider: the notion that clojure(script) is simply a lib, you need the build tool to do things with it (there are other build tools, but you don't have to know about it unless you want to) - this notion is a simple one, easy to understand and explain to someone. Also, one could argue that it's a question of backwards compatibility (of the platform as a whole). I'd definitely not like it if some guy 5 years in the future is working with some project written today, then needs to add some feature to the build process, asks how to do it here in the slack and everyone going "oh, you still use XXX? everyone's already using YYY, you need it for that feature, it's also 25% faster and shinier!" - you see what I mean? So you saying "lein community" kinda makes me a bit nervous (I swear I can hear howls of js developers in my head), given that probably somewhere around 95% of the clojure projects use lein today. I don't mean it at all as a critique of the work you do or something like that, it's just another perspective to consider I guess? Anyway, tl;dr: don't break the web^W lein!
I'll check that channel
Thanks !
I think lein proved that we do like declarative build and dep configurations. But putting it all into one project file has made the whole thing kind of brittle and difficult to compose configurations together. There's also a problem with when there's 30 plugins connected to my project and I don't know what's impacting things.
like a simple deps.edn templating tool that sits behind a clj -Anew ...
alias could replace lein's new
command pretty easily
@john any suggestions on reading material? I don’t really follow what you or dnolan are saying but would like to learn more
in lein you'd normally use lein uberjar
to make a jar, but with clj you can use clj -A:depstar -m hf.depstar.uberjar MyProject.jar
as per this composable library: https://github.com/healthfinch/depstar
But if you'd prefer to use a different jarring method, you could instead make an alias for https://github.com/juxt/pack.alpha
and if you're doing something in dev and you need to fix something in one of these tools, you can just fork them and depend on your fork, right there in the deps.edn file that declares the lib
the key point is that clj is about a) creating classpaths that include some set of deps and b) running programs
and that build tools are nothing more than a set of small programs
clj is designed to make that set of programs composable / customizable
one could potentially contribute a boot tasks/fileset implementation on top of cli
do you mean something more involved than https://github.com/seancorfield/boot-tools-deps ?
isn’t that what boot-tools-deps does? I’m probably just misunderstanding.
do you mean invoking boot with clj?
yes Alex (I don't think boot-tools-deps
does that now, but I am checking 🙂 )
it doesn’t
> Updates Boot's resources, sources, and classpath based on the paths, extra paths, and classpath computed by tools.deps
I guess I don’t know if that would be useful. maybe?
build it and see! :)
yes so I was saying that clj
is lower level and could be used to call boot tasks, well maybe that's not that useful...I am brainstorming after your statement above 😄
it would be more like the clj -m boot.main
or something...but again, don't know about its value...
just saying it is doable 😄
maybe it would be if it opened the set of boot tasks through clj
lemme try one thing
not sure. aliases affect either how you build the classpath or the main opts you pass (but those replace, not add)
the composition model is different
seems like if you want to do that, you’re better off using boot and boot-tools-deps
so basically what you'd need it to convert this to a clj entry point: https://github.com/boot-clj/boot/blob/30ba3ce69dcd8b2b3e00677a14db05c8ce49d59c/boot/base/src/main/java/boot/App.java
because boot.main/-main
requires the worker pod and other things: https://github.com/boot-clj/boot/blob/30ba3ce69dcd8b2b3e00677a14db05c8ce49d59c/boot/base/src/main/java/boot/App.java#L398
(sorry for spamming 😄 )
I am also off-topic, this should probably go in #boot-dev
or #tools-deps
just anecdotal evidence[1], if you wanted people to run clojure code as scripts from sources without forcing them to use specific build tooling (lein/boot/etc) you had to jump through hoops like I did there the good news is that what used to be 50+ lines of dirty and fragile bash/maven is now a one-liner with rock-solid clojure tool 🙂 [1] https://github.com/binaryage/dirac/commit/a7eae5e855fe7480bd949fde04f26a33d3388ecd
@john and others, thanks for the illuminating discussion and links. I’ve read all of that material and looked through alex miller’s slides now. I understand now the concept that tools.deps does this classpath resolution and construction. In your example, you pointed out that you could do clj -A:depstar -m hf.depstar.uberjar MyProject.jar
to make an uberjar. But where are we supposed to keep recipes for builds? Still in lein? E.g., if you need to compile your sass into css, bundle up some static resources, run tests, build an uberjar, you’ll need a repeatable process somewhere. I don’t see how tools.deps helps with that.
@lee.justin.m I think the Golang folks do that: use Makefile pseudo tasks to manage the various command-line invocations for their projects.
Yeah, I think of a Makefile as a shell script, basically with some extra interesting features.
the steps need to be written down somewhere. right now they are written down in project.clj
With clj
you have a lot of different invocations, one for test, one for uberjar, another for repl: it’s hard to remember them all, so, put them in a script, set of scripts, a makefile, etc?
That’s been my assumption. Probably not easily cross platform (if one of those platforms is windows).
@lee.justin.m yes, use whatever tools fit the best, for me shell is the best glue at the moment, I tend to create scripts
subfolder and keep my commands there as plain shell scripts
but yeah, you'll need to provide collections of configs to various libs that are compiling css, etc, and we'll have to settle on a way to manage the various configs, rather than using one single project file
I used to escape horrors of complex lein configuration by escaping into shell scripts (via lein-shell plugin) and then returning back invoking lein which often caused multiple JVM instanced stacked as a sandwich in my virtual memory - luckily enough I have a pretty beefy machine 😉
but in this new model lein in just another unix tool at my disposal, I might decide to use it, maybe having multiple smaller config files and use them ad-hoc for specific tasks. instead of maintaining one monolithic one and rely on it as “central dispatcher” of all-things-clojure
it may well be you need to make available garden.edn
and advanced-testing-tool.edn
as specific config files for each lib
huh well i’ll guess we’ll just have to see. this is all very :face_with_monocle:. the thing is the unix tools are generally not built with 30 second startup times in mind.
well, if startup time is your issue then you should build suite of commands in your repl, fire it up once a day and then use your favorite repl prompt for invoking them
actually, with the new socket server, maybe you could have a sort of repld
or cljd
that always runs and just does nothing until you invoke something
will, if we're going down the make road, there's mach: https://github.com/juxt/mach
this is cool stuff!
Regular make is fine for providing targets (short cuts for commands) and a few pre-condition checks for directories.
the vast majority of the “build” things I do are single step (but I rarely use cljs)
The last line of that stolen from a Golang project (that now uses Mage (a go build tool).)
Anyway, it does seem like using clj
requires remembering several potentially complicated command-lines, or writing them down to be launched and/or cut/pasted.
@lee.justin.m @zentrope and I don't think I'll need remember where to put different config files and their defaults because I can still just use some project templating tool. Then I just remember the invocations and config touch points, similar to how I do now.
@john that sort of kicks the can down the road. what is the project templating tool going to do?
you were saying that you viewed lein's project.clj as a sort of recipe. I'm just saying, you can still have that, it'll just be two or three recipes you compose together. And it'll be just as easy to construct those default recipes with some templating tool, just like lein.
but who knows, if folks built something cool around using mach, maybe folks will take it a different direction
I am having trouble using let
in a macro. The macro
(defmacro foo [arg]
`(let [bar (+ 1 ~arg)]
bar))
gives me the error
myproject.core> (foo 1)
---- Could not Analyze <cljs form> line:1 column:1 ----
Invalid local name: myproject.core/bar at line 1 <cljs repl>
1 (foo 1)
^---
---- Analysis Error ----
nil
Any ideas why?Here is the macro expansion:
myproject.core> (macroexpand '(foo 1))
(let* [myproject.core/bar (clojure.core/+ 1 1)] myproject.core/bar)
Syntax-quote is expanding bar
into myproject.core/bar
and fully-qualified symbols are not valid in let bindings. To get an unqualified symbol you can “unquote a quoted symbol” like ~'bar
in your macro and you will get what you intend. However, that introduces bar
into the scope which can be dangerous (it could shadow something already defined in the namespace) so Clojure provides a feature called automatic gensyms for this. If you just write bar#
instead of bar
Clojure will pick a good generated symbol (unqualified) and this is the correct way to do it. So you would write it like:
(defmacro foo [arg]
`(let [bar# (+ 1 ~arg)]
bar#))
Sorry for the long-winded reply 🙂Wow! Amazing. Both forms work exactly as you described. Where can I find this information for future reference? I didn’t see it on https://clojure.org/reference/macros
https://aphyr.com/posts/305-clojure-from-the-ground-up-macros has some info on gensym’s about a third of the way in (recommend searching for “gensym”). I couldn’t find many resources that talk about gensym’s that don’t introduce macro basics as well
Clojure For the Brave And True also has a chapter on macros and again you have to search for “gensym”: https://www.braveclojure.com/writing-macros/
no, but you could provide your figwheel.edn
and garden.edn
and build.edn
all separately. And you could use some clj -m foo.new chestnut my-project
to automatically create those files and folders in their correct places, if that was your thing.
Depending on what you invoke with CLJ, it would pick up the appropriate whatever.edn
(in addition to deps.edn
)?
Yeah, I wouldn’t mind that. All the figwheel things are named figwheel. Easier to debug a complicated build (of which NONE SHOULD EVER EXIST! ;).
Coincidentally I also need to use an npm module (uppy), am targeting the browser. I use figwheel with leiningen. Does this apply to leiningen as well?