I have a couple of small scripts, all in the root of my scripts folder. It looks like I could factor out some code into a reusable part. What's the best way to require that reusable part in the scripts that use it? (add-classpath ...)
and then (require '[...])
? I'd prefer not to create a project structure if possible... just one flat script folder.
@mmz you can add "."
to the classpath and then you can just require from the flat script folder
provided that you use only one namespace segment. babashka does expect foo.bar
to be in foo/bar.clj
so you could use underscores like (ns foo_bar)
if you want to keep it flat
or (ns foo-bar)
actually, and then code will be in foo_bar.clj
both should work
Thanks! Will try and will keep you posted.
btw load-file
also works, if you don't want to use the classpath
so lots of options =)
works!
Thanks ๐
Is load-file
shorter?
Current test: dep.clj:
(ns dep)
(defn double [x] (* 2 x))
test.clj:
#!/usr/bin/env bb
(require '[babashka.classpath :refer [add-classpath]])
(add-classpath ".")
(require '[dep])
(println (dep/double 4))
That's even better! ๐ค test.clj:
#!/usr/bin/env bb
(load-file "./dep.clj")
(println (dep/double 4))
(except that both won't work if you call the script from another directory ๐ )
@mmz unless you use absolute paths, like:
(require '[<http://clojure.java.io|clojure.java.io> :as io])
(load-file (io/file (.getParent (io/file *file*)) "dep.clj"))
Awesome! Best solution! ๐:skin-tone-3: Thanks!
Think I finally found a rare bb
bug ๐
(loop []
(do
1
(recur)
2))
In clojure this does
Syntax error (UnsupportedOperationException) compiling recur at (form-init7929880134577873038.clj:4:5).
Can only recur from tail position
In babashka it returns 2 ๐yeah, babashka doesn't restrict recur to occur in tail position :P
Ah ok maybe a feature then
it should probably throw or something, but it's just ignored
I accidentally had an extra item in tail position and I was getting weird results
You mean the recur is ignored, right?
(loop []
(println "hi")
(recur)
2)
hi
2
Not really what I would expect. Shall I create a bug report with Sci?yeah, would be good
Can I have a babashka script require some utils from a separate module? I can make it work in the repl, but whe run as a script the util ns isnโt found.
Does that help?
It certainly looks like the same question. Will try it now.
tl;dr; use (babashka.classpath/add-classpath ...)
or load-file
+ *file*
if you want absolute paths
#!/usr/bin/env -S bb -cp ./script
Sort of works in my setting, but maybe I will want use absolute paths insteadโฆ-S
does this allow args in linux?
for the longest time I thought env didn't take args on linux!
Not sure how portable it is.
I just looked it up on my linux vps, appears to work!
The load-file
way works when I run it as a script and if I evaluate the contents of the file in the repl, but it blows up when using the nrepl
load-file
op.
nrepl
โs load-file doesnโt want to read the shabang either of course, but then I can manually load my helper module first and the main module after that and things are dandy.
@pez why put something in a shebang at all? you can do this all in the script itself
(require '[babashka.classpath :as cp])
(cp/add-classpath "script")
and then (require 'script.foo)
or (load-file "script/foo.clj")
I just prefer (:require [script.foo :refer [bar]])
ยฏ\(ใ)/ยฏ
In the ns form.
I am considering a .babashka/config.edn
for projects where you can set the project classpath for example.
But it is pretty normal in scripts to have multiple require forms, for setting the classpath, adding clojure deps (via babashka.deps), loading pods, ...
Maybe there should be a .babashka/setup.clj
where these side effects can occur
instead of a config file
the Boot way ๐
I have too little experience with it to know which one is best. But it would be nice with some way to configure it, keeping the script less concerned with that stuff.
It would also give the nrepl server a chance to read the :require
stuff in the ns form in an informed way, right?
The feedback I got a lot with the config file idea was that many people just use babashka for single scripts, so they would like to have an API for this, instead of an extra config file. But we could make an entry-point function which does this for you:
(defn -setup [..] ...)
which you can "hide" at the bottom of your script, or something, or just below the ns form.
https://github.com/babashka/babashka/issues/680
Not sure about nREPL. If you use the babashka nrepl, then yes, but probably not on the JVMOn the JVM you could make a condition at the bottom which executes the script, but then it should probably go before the ns form
hmm, this issue is labeled "hammock" for a reason
Haha, yeah. Iโm currently using the babashka nrepl. I think Iโll fix clojure-lsp so that it helps with the script too. (Seems like it is just confused by the shebang.)
Meanwhile I was trying this:
/usr/bin/env -S clojure -Sdeps '{:deps {:medley/medley {:mvn/version "1.3.0"}}}'
(println *command-line-args*)
maybe this is why the #_
+ exec trick is needed
I get
Error building classpath. class clojure.lang.Symbol cannot be cast to class clojure.lang.Keyword (clojure.lang.Symbol and clojure.lang.Keyword are in unnamed module of loader 'app')
Even from just:
clojure -Sdeps '{:deps {:medley/medley {:mvn/version "1.3.0"}}}'
yeah sorry, the dep name should be a symbol
but all I get is a REPL when using this approach and the code itself isn't executed in the file