--- publish: true url: https://clojure.org aliases: tags: - programming/language created: 2022-03-23 12:06:20 modified: 2022-03-23 12:20:33 --- # Clojure ^539406 ## Reference - [home page](https://clojure.org) - [clojure-toolbox.com](https://www.clojure-toolbox.com) - A categorized directory of libraries and tools for Clojure - [clojuredocs.org](https://clojuredocs.org) - community-powered documentation and examples - minutia - [On why symbols and vars are separated in Clojure](https://news.ycombinator.com/item?id=2467809) and why Clojure's compilation unit is top-level forms and its implications. ### Libraries - https://github.com/cgrand/xforms ## Extensible Data Notation (edn) [source](https://github.com/edn-format/edn) - **edn** is an **E**xtensible **D**ata **N**otation. A superset of **edn** is used by Clojure to represent programs, and it is used by Datomic and other applications as a data transfer format. - **edn** supports a rich set of built-in elements, and the definition of extension elements in terms of the others. - **edn** is a system for the conveyance of _values_. It is not a type system, and has no schemas. Nor is it a system for representing objects - there are no reference types - There is no enclosing element at the top level. Thus **edn** is suitable for streaming and interactive applications. ### Built-in elements [source](https://github.com/edn-format/edn#built-in-elements) - `nil` - booleans - `true` and `false` - strings - enclosed in `"double quotes"`, multi-line, C escape characters `\t, \r, \n, \\, and \"` are supported - characters - `\<c>`, `\newline`, `\return`, `\space`, `\tab` - symbols - begin with a non-numeric character and can contain alphanumeric characters and `. * + ! - _ ? $ % & = < >`. - If `-`, `+` or `.` are the first character, the second character (if any) must be non-numeric. - `: #` are allowed as constituent characters in symbols other than as the first character. - `/` has special meaning in symbols. It can be used once only in the middle of a symbol to separate the _prefix_ (often a namespace) from the _name_, e.g. `my-namespace/foo`. `/` by itself is a legal symbol, but otherwise neither the _prefix_nor the _name_ part can be empty when the symbol contains `/`. - If a symbol has a _prefix_ and `/`, the following _name_ component should follow the first-character restrictions for symbols as a whole. - keywords - Keywords are identifiers that typically designate themselves. They are semantically akin to enumeration values. Keywords follow the rules of symbols, except they can (and must) begin with `:`, e.g. `:fred` or `:my/fred`. - integers - floating point numbers - lists - sequence of values, e.g. `(a b 42)` - vectors - sequence of values, random access, e.g. `[a b 42]` - maps - associative unordered collection, e.g. `{:a 1, "foo" :bar, [1 2 3] four}` - sets - collection of unique values, e.g. `#{}`, `#{:a b [1 2 3]}` ### tagged elements [see source](https://github.com/edn-format/edn#tagged-elements) ### built-in tagged elements - instance - [[time#^141c48|RFC-3339]] formatted tagged string, e.g. `#inst "2022-04-19T14:50:56.381-04:00"` - [UUID](http://en.wikipedia.org/wiki/Universally_unique_identifier) - e.g. `#uuid "e70d408a-6bac-21c0-b899-16eac0246bff"` ## Built-in Tooling `tools.deps`, `tools.build` and [[cli|CLI]] [As of version 1.9](https://clojure.org/news/2017/12/08/clojure19), Clojure ships with [spec](https://github.com/clojure/spec.alpha) and a [[cli]] interface, including a dependency management library (`tools.deps`) and build tools (`tools.build`). These are Cognitect's take on contracts and build tooling, holes previously filled by community libraries like [Schema](https://github.com/plumatic/schema) and [leiningen](https://leiningen.org). ### Resources - official - guides - [getting started](https://clojure.org/guides/getting_started) - [deps and cli](https://clojure.org/guides/deps_and_cli) - [tools.build](https://clojure.org/guides/tools_build) - reference - [deps and cli](https://clojure.org/reference/deps_and_cli) - [tools.build tasks](https://clojure.github.io/tools.build/) - [tomekw guide](https://tomekw.com/clojure-deps-edn-a-basic-guide/) - [kozieiev guide](https://kozieiev.com/blog/clojure-cli-tools-deps-deps-edn-guide/) - [Clojure CLI flags](https://practical.li/blog/posts/clojure-which-execution-option-to-use/) - useful libraries - [seancorfield/build-clj](https://github.com/seancorfield/build-clj) - [cognitect-labs/test-runner](https://github.com/cognitect-labs/test-runner) - [practicalli/clojure-deps-edn](https://github.com/practicalli/clojure-deps-edn) - not endorsing the idea behind the project its [deps.edn has many example aliases worth copy-pasting as a starting point](https://github.com/practicalli/clojure-deps-edn/blob/live/deps.edn). ### `clj` and `clojure` `clj` is just an [[cli#^c02b97|rlwrap]] wrapper for `clojure` and provides a much better `stdin` editing experience - emacs keybinding navigation, word edits - history ```bash rlwrap -r -q '\"' -b "(){}[],^%#@\";:'" "$bin_dir/clojure" "[email protected]" ``` - Use `clojure` for scripting and [[CICD]] - use `clj` for interactive shell sessions. ``` Start a REPL clj [clj-opt*] [-Aaliases] [init-opt*] Exec fn(s) clojure [clj-opt*] -X[aliases] a/fn? [kpath v]* kv-map? Run tool clojure [clj-opt*] -T[name|aliases] a/fn [kpath v] kv-map? Run main clojure [clj-opt*] -M[aliases] [init-opt*] [main-opt] [arg*] Prepare clojure [clj-opt*] -P [other exec opts] ``` #### Help Functions [source](https://clojure.org/reference/deps_and_cli#_help_functions) > The `help/doc` and `help/dir` functions introspect how a tool can be used. Because the `:deps` alias does not include the project classpath, these are not currently useful when executing functions in your own project. > - `-X:deps help/doc` - show the doc strings and parameter lists of the functions given with key `:ns` or function specified by an additional key `:fn`; if neither given then `:ns-default` is used > - `-X:deps help/dir` - prints the public functions in namespace provided with key `:ns` or `:ns-default` if not given For usages, see [[#Built-in deps Alias]] #### Options - [[#clj-opt s]] - [[#-M exec-opt]] - run `-main` or a script - [[#-X exec-opt]] - run a function - [[#-T exec-opt]] - run a tool - [[#-P exec-opt]] - prepare - [[#-A aliases]] - run a REPL ##### `clj-opt`s ``` -Jopt Pass opt through in java_opts, ex: -J-Xmx512m -Sdeps EDN Deps data to use as the last deps file to be merged -Spath Compute classpath and echo to stdout only -Spom Generate (or update) pom.xml with deps and paths -Stree Print dependency tree -Scp CP Do NOT compute or cache classpath, use this one instead -Srepro Ignore the ~/.clojure/deps.edn config file -Sforce Force recomputation of the classpath (don't use the cache) -Sverbose Print important path info to console -Sdescribe Print environment and command parsing info as data -Sthreads Set specific number of download threads -Strace Write a trace.edn file that traces deps expansion -- Stop parsing dep options and pass remaining arguments to clojure.main --version Print the version to stdout and exit -version Print the version to stderr and exit ``` ##### `-M` exec-opt Invokes `clojure.main`, to execute the `-main` function in a namespace or execute a Clojure script. ```bash # show docs on main-opts clj -M --help # invoke -main in core namespace clj -M --main core clj -M -m core # execute script.clj clj -M script.clj 1 2 3 # == script.clj == # (println "Script invoked with args: " *command-line-args*) ``` Given this alias in [[#deps edn]]: ```clojure { :aliases { :project/run {:main-opts ["-m" "project.core"]} } } ``` Can invoke with `-M` ```bash clojure -M:project/run ``` Aliases chain ```bash # call with :project/run and :profile aliases clojure -M:project/run:profile ``` ##### `-X` exec-opt Invoke a function that takes a map: ``` clojure [clj-opt*] -X[aliases] [namespace/fn] [kpath v]* kv-map? ``` Given this function ```clojure (ns core) (defn echo-args [argm] (println argm)) ``` ```bash clojure -X core/echo-args :key1 :val1 '{:foo :bar}' # {:key1 :val1, :foo :bar} ``` `-X` is the preferred invocation style over `-M` [in some cases](https://github.com/cognitect-labs/test-runner#invoke-with-clojure--m-clojuremain). ##### `-T` exec-opt [official docs](https://clojure.org/reference/deps_and_cli#_using_named_tools) Invoke a tool by name. To manage tools, use the built-in `tool` tool. > Yo dawg, I heard you like tools. So I put a `tools` tool in your Clojure tool. List functions for tool management ```bash clojure -A:deps -Ttools help/dir ``` Note activating a tool with `-T` activates a default namespace. In the example above, `clojure.tools.tools.api` is active instead of the `:deps` alias default `clojure.tools.cli.api`. To find a tools default namespace: ```bash clojure -A:deps -Ttools show :tool tools # {:lib io.github.clojure/tools.tools, # :coord # {:git/tag "v0.2.5", # :git/sha "76f728dce63f7b881f4e5705ba0d59d795d56f11"}} # Default namespace: clojure.tools.tools.api ``` All you need to be a tool is include this key tree in project's `deps.edn` ```clojure {;;... :tools/usage {:ns-default the.tool.namespace :ns-aliases {} #_"map of aliases to lib symbols"} ;;... } ``` ###### Some Useful Tools - [antq](https://github.com/liquidz/antq#clojure-cli-tools-1103933-or-later) - manage outdated dependencies ##### `-P` exec-opt [source](https://clojure.org/reference/deps_and_cli#_prepare_for_execution) > The -P flag can be used with any other execution mode to "prepare" but not execute. Useful for forcing environment side-effects like downloading maven dependencies, e.g. inside a [[Docker]] image build. ##### `-A` aliases Run a REPL in context of aliases. It's also used to add alias context to other switches like `-S`. ```bash clojure -Atest -Spath ``` ### `deps.edn` Config file, analogous to [leiningen](https://leiningen.org) `project.clj`, with the distinction that the latter is executable and the former is [[#Extensible Data Notation edn|just data]]. #### Precedence [source](https://clojure.org/reference/deps_and_cli#_merging_deps_edn) > The `deps.edn` files found from the source locations (with Clojure tool modifications by any options) are merged to form one master deps map. [...] > The operation is essentially `merge-with merge`, ==except for the `:paths` key, where only the last one found is used (they are not combined)==. In ascending precedence order - Root - `$(dirname $(readlink -f $(which clj)))/../deps.edn` ^223ebd - User - If `$CLJ_CONFIG` is set, then use `$CLJ_CONFIG` (explicit override) - If `$XDG_CONFIG_HOME` is set, then use `$XDG_CONFIG_HOME/clojure` (Freedesktop conventions) - Else use `$HOME/.clojure` (most common) - Project - the `deps.edn` in the current directory - External - a `deps.edn` map passed on the command line The sources can be modified or inspected by the following options: - `-Sverbose` - print all source locations - `-Sdeps` - pass the config data on the command line - `-Srepro` - omit the user deps source (other sources will be used if found) #### Caching See [classpath caching](https://clojure.org/reference/deps_and_cli#_classpath_caching) #### Built-in :deps Alias The [[#^223ebd|Root]] `deps.edn` file has a built-in `:deps` alias. ``` -X:deps mvn-install Install a maven jar to the local repository cache -X:deps git-resolve-tags Resolve git coord tags to shas and update deps.edn -X:deps find-versions Find available versions of a library -X:deps prep Prepare all unprepped libs in the dep tree ``` ```bash # list functions in the namespace: clojure.tools.cli.api clojure -X:deps help/dir # show docstrings for functions in the namespace: clojure.tools.cli.api clojure -X:deps help/doc # show docstrings for functions in the help ns-alias (part of :deps alias) clojure -X:deps help/doc :ns help ``` ## 3rd Party Build Tools ### leiningen before there was [[#deps.edn]] there was [leiningen](https://leiningen.org) - https://leiningen.org/ - [how clojure babies are made](https://www.flyingmachinestudios.com/programming/how-clojure-babies-are-made-lein-run/) - fundamentals of launching and building clojure programs by hand ## Static Checks ### clj-kondo Setup on [[MacOS]] ```bash brew install borkdude/brew/clj-kondo # in project, initialize caches clj-kondo --lint "$(clojure -Spath)" --dependencies --parallel --copy-configs # practicalli/clojure-deps-edn alias clojure -M:lint/clj-kondo # if clj-kondo is on the path, doom emacs ':checkers syntax' integration will "just work" ``` - [clj-kondo/clj-kondo](https://github.com/clj-kondo/clj-kondo#installation) - [borkdude/flycheck-clj-kondo](https://github.com/borkdude/flycheck-clj-kondo) for [[emacs]] integration Doom emacs cheatsheet for fly-check linting ``` <Space> c x - bring up lint list window C-c ! n - next lint error from cursor C-c ! p - previous lint error from cursor ``` ### cljfmt [idiomatic](https://github.com/bbatsov/clojure-style-guide) Clojure code formatting - [cljfmt](https://github.com/weavejester/cljfmt) is a library and [[#leiningen]] plugin for formatting Clojure code. - [cljfmt-graalvm](https://github.com/pmbauer/cljfmt-graalvm) is a native, CLI packaging of cljfmt - provides same stdio interface as used by other language formatting tools, e.g. `gofmt` for [[golang]] - compatible with [format-all](https://github.com/lassik/emacs-format-all-the-code) [[emacs]] module - in addition, exposes same interface as cljfmt lein plugin - `diff` - `fix`