Clojure
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/foo.clj
.
However it should be namespaced properly (TODO: work on this).
touch $d/deps.edn $d/src/core.clj echo "{:deps {org.clojure/clojure {:mvn/version \"RELEASE\"}}}" > $d/deps.edn echo "(ns core) (defn -main [] (println \"hello world\"))" >> src/core.clj clj -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
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
exec rlwrap -r -q '\"' -b "(){}[],^%#@\";:'" "$bin_dir/clojure" "$@"
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
Hello world, the time is 10:00 AM
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 C-d
(cider-doc
)
Quickies
Print environment variables
(doseq [[k v] (System/getenv)] (println k v))
Clojure and Java versions
*clojure-version* (System/getProperty "java.version")
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")
words
(range 10)
(0 1 2 3 4 5 6 7 8 9)
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.