Clojure
Unbind all vars in a namespace
(doseq [[sym var] (ns-publics *ns*)] (ns-unmap *ns* sym))
Installation
The clojure site suggests using the following:
brew install clojure/tools/clojure
There is also a slightly different formula in homebrew core:
brew install clojure
This one depends_on "openjdk"
, so it will also install the latest openjdk
homebrew package. The first method is preferred, which requires you to set up
and configure a JDK yourself.
Project Creation
Minimal
All you need is a project directory with a deps.edn
and a src/core.clj
.
(require '[clojure.java.io]) (def deps "{:deps {org.clojure/clojure {:mvn/version \"RELEASE\"}}} ") (def core "(ns core) (defn -main [& args] (println \"hello world!\")) ") (let [deps-path "hello_world/deps.edn" core-path "hello_world/src/core.clj"] (clojure.java.io/make-parents deps-path) (spit deps-path deps) (spit core-path core))
Run with:
clojure -M -m core
neil
This looks like the best way! Try this out!
My deps-new template
clojure \ -Sdeps '{:deps {net.clojars.cfclrk/minimal {:local/root "/Users/cclark/Projects/codenotes/clojure/minimal"}}}' \ -Tnew \ create \ :template cfclrk/minimal \ :name $user/$projectName
deps-new
First, make sure deps-new is installed:
clojure -Ttools install \ io.github.seancorfield/deps-new \ '{:git/tag "v0.4.9"}' :as new
Create a new app:
clojure -Tnew app :name cfclrk/$projectName
Create a new lib:
clojure -Tnew lib :name cfclrk/$projectName
Leiningen
lein new app cfclrk/$projectName
clj vs clojure
clj
is just a program that wraps clojure
with readline
support.
find /usr/local/Cellar/clojure -name clj \ | sed -n '2 p' \ | xargs cat \ | grep exec
readline
provides support for editing a command in the terminal (e.g. using
arrow keys and C-a
C-e
C-f
C-b
for movement, and stuff like that.
So, clj
just provides better interactivity in the terminal REPL.
Install a package
Find package versions
Say you want to install integrant:
clj -X:deps \ find-versions \ :lib integrant/integrant
Add that dependency, then build the project.
Start clj with package
clj -Sdeps '{:deps {cider/orchard {:mvn/version "0.9.2"}}}'
Tools
Ok, so there is:
- tools.build
- tools.tools
From the tools.build guide:
In the Clojure CLI, "tools" are programs that provide functionality and do not use your project deps or classpath. Tools executed with
-T:an-alias
remove all project deps and paths, add ".
" as a path, and include any other deps or paths as defined in:an-alias
.
Where do tools live?
Defined by an alias in deps.edn
.
Code Format
Good article: Clojure formatting with cljstyle.
cljstyle
Install
brew install --cask cljstyle
cljfmt
Format a project using cljfmt
. Note, the check
argument can also be
"fix
" to make the changes in-place.
clojure -Sdeps '{:deps {cljfmt/cljfmt {:mvn/version "0.8.0"}}}' \ -M -m cljfmt.main check
Classpath
This is how cider grabs it:
(seq (.split (System/getProperty "java.class.path") ":"))
Directories on the classpath:
(let [classpath-entries (.split (System/getProperty "java.class.path") ":") classpath-as-files (map clojure.java.io/file classpath-entries) classpath-dirs (filter #(.isDirectory %) classpath-as-files)] classpath-dirs)
(#object[java.io.File 0x43602f98 "src"] #object[java.io.File 0x2b9120c6 "resources"])
Cmd Execution and REPL
Call a single function
clj -X $nsname/$funcname
Start a REPL that I can attach to from Emacs.
clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "RELEASE"}}}' \ -m nrepl.cmdline \ --middleware "[cider.nrepl/cider-middleware]"
Emacs Cider
Basic workflow is described in the cider docs here.
- Open a file in the project
M-x cider-jack-in
- Load a project file using
C-c C-k
(cider-load-buffer
) - In the
*cider-repl
buffer, you know call the fully-qualified functions in that file.- Or,
(in-ns 'the.ns.name)
to call functions in that file without namespace qualification. - Then also
(use 'clojure.core)
and(use 'clojure.repl)
'
- Or,
- Edit a function, and
C-c C-e
on that function to reload it.
Tips
- From source file,
C-u C-c C-z
to jump to cider buffer already namespaced to the source file. - Quit a long-running eval with
C-c C-b
(cider-interrupt
).
Doc
Function doc: C-c C-d d
(cider-doc
)
Quickies
Print environment variables
(doseq [[k v] (System/getenv)] (println k v))
Read and write a binary file
(import java.net.URI) (import java.nio.file.Paths) (import java.nio.file.Files) (defn read-file-bytes "Load the file at `path` into a byte[]. `path` is a String relative to the this service's root directory." [^String path] (let [file-uri (.toURI (io/resource path)) nio-path (Paths/get file-uri)] (Files/readAllBytes nio-path))) ;; Read file (def mypdf (read-file-bytes "resources/my.pdf")) ;; Write file (let [p (Paths/get (URI. "file:///Users/cclark/Downloads/bar.pdf")) opts (into-array java.nio.file.OpenOption [])] (Files/write p mypdf opts))
Org mode
(use 'inflections.core) (plural "word")
(range 3)
#js {:foo "bar"}
(= *file* (System/getProperty "babashka.file"))
core.async
There are some great examples from O'Reilly here, which is supplemental content for their excellent video course Communicating Sequential Processes with core.async.