Babashka `bb` and Not Babashka `nbb`
29 August, 2024
bb
Babashka is a native Clojure interpreter for scripting with fast startup. Its main goal is to leverage Clojure in places where you would be using bash otherwise.
TLDR;
bb -e '(+ 1 20)'
bb -e '(-> (org.httpkit.client/get "https://datafy.id") deref :status)'
bb tasks
cat <<EOF > bb.edn
{:tasks {hello (println "hello there")}}
EOF
bb hello # run the task named hello
nbb
Not Babashka. Node.js Babashka!? nbb is bb atop JS runtime, e.g.
bun or nodejs.
Getting Started
# Using bun, this will automatically download nbb if necessary
# and compute bcrypt hash of given password
bunx --bun nbb -e '(js/Bun.password.hash "pass" #js {:algorithm "bcrypt"})'
We can make it more organized by creating config file nbb.edn and create a
cljs file.
mkdir x && cd x
touch nbb.edn
touch hello.cljs
Config file nbb.edn could be as simple as this:
{:paths ["."]}
And the hello.cljs content, for example shown here, we will use bun hash
api.
(ns hello)
(defn greeting [& {:keys [to]}]
(println (str "Hello " to)))
(defn -main [& [password]]
;; note that if we return promise, it will be automatically waited
;; and then result is printed
(js/Bun.password.hash password #js {:algorithm "bcrypt"}))
(defn bcrypt [& {:keys [password]
:or {password "pass"}}]
(-> (js/Bun.password.hash password #js {:algorithm "bcrypt"})
(.then (fn [x]
{:password password
:hash x}))))
With these two files, now we could execute the script with nbb like this:
bunx --bun nbb -x hello/greeting --to "Ridho"
bunx --bun nbb -x hello/bcrypt --password your_strong_password
bunx --bun nbb -x hello/bcrypt :password "your_strong_password" # same like above
bunx --bun nbb -m hello your_strong_password
nbb Api
See latest api doc here.
Builtin NS: clojure.core, clojure.set, clojure.edn, clojure.string,
clojure.walk, clojure.data, clojure.test and clojure.pprint.
nbb.core: *file*, load-file, load-string, slurp, time.
nbb.repl: repl, socket-repl.
nbb.error: print-error-report.
babashka.cli: auto-coerce, coerce, dispatch, format-opts,
format-table, merge-opts, number-char?, opts->table, pad, pad-cells,
parse-args, parse-cmds, parse-keyword, parse-keyword, rows,
spec->opts.
promesa.core: *loop-run-fn*, ->, ->>, TimeoutException, all,
any, as->, bind, cancel!, cancelled?, catch, catch', chain,
chain', create, deferred, deferred?, delay, do, do!, done?,
err, error, finally, future, handle, let, loop, map, mapcat,
pending?, plet, promise, promise?, promisify, race, recur,
reject!, rejected, rejected?, resolve!, resolved, resolved?, run!,
then, then', thenable?, timeout, with-redefs, wrap.
reagent.core: atom, as-element, with-let, cursor, create-class,
create-compiler.
reagent.ratom: with-let-values, reactive?.
reagent.dom.server: render-to-string, render-to-static-markup.
applied-science.js-interop: get, get-in, contains?, select-keys,
lookup, assoc!, assoc-in!, update!, extend!, push!, unshift!,
call, apply, call-in, apply-in, obj, let, fn, defn, lit.
clojure.tools.cli: format-lines, summarize, get-default-options,
parse-opts, make-summary-part.
cognitect.transit: write, writer, write-handler, write-meta,
read, read, read-handler, tagged-value.
cljs-bean.core: bean, bean?, object, ->js, ->clj.