$ clj
Clojure 1.12.0
user=>
The clojure.main
namespace provides functions that allow Clojure programs and interactive sessions to be launched via Java’s application launcher tool java
.
The clojure.main/main
entry point accepts a variety of arguments and flags.
With no options or args, runs an interactive Read-Eval-Print Loop
init options:
-i, --init path Load a file or resource
-e, --eval string Evaluate expressions in string; print non-nil values
--report target Report uncaught exception to "file" (default), "stderr", or "none", overrides System property clojure.main.report (added in 1.10.1)
main options:
-r, --repl Run a repl
path Run a script from a file or resource
- Run a script from standard input
-m, --main A namespace to find a -main function for execution
-h, -?, --help Print this help message and exit
operation:
Establishes thread-local bindings for commonly set!-able vars
Enters the user namespace
Binds *command-line-args*
to a seq of strings containing command line args that appear after any main option
Runs all init options in order
Runs a repl or script if requested
The init options may be repeated and mixed freely, but must appear before any main option. The appearance of any eval option before running a repl suppresses the usual repl greeting message: "Clojure ~(clojure-version)".
Paths may be absolute or relative in the filesystem or relative to classpath. Classpath-relative paths have prefix of @ or @/
The simplest way to launch a Clojure repl is to use the clj command tool, which invokes clojure.main:
$ clj
Clojure 1.12.0
user=>
The REPL prompt shows the name of the current namespace (*ns*), which defaults to user.
Several special vars are available when using the REPL:
*1, *2, *3 - hold the result of the last three expressions that were evaluated
*e - holds the result of the last exception.
The clojure.repl namespace has a number of useful functions for inspecting the source and documentation of available functions:
To run a file full of Clojure code as a script, pass the path to the script to clojure.main
as an argument:
clj -M /path/to/myscript.clj
To pass in arguments to a script, pass them in as further arguments when launching clojure.main
:
clj -M /path/to/myscript.clj arg1 arg2 arg3
The arguments will be provided to your program as a seq of strings bound to the var *command-line-args*
:
*command-line-args* => ("arg1" "arg2" "arg3")
As of Clojure 1.10, Clojure errors categorized into one of several phases:
:read-source
- an error thrown while reading characters at the REPL or from a source file.
:macro-syntax-check
- a syntax error found in the syntax of a macro call, either from spec or from a macro throwing IllegalArgumentException, IllegalStateException, or ExceptionInfo.
:macroexpansion
- all other errors thrown during macro evaluation are categorized as macroexpansion errors.
:compile-syntax-check
- a syntax error caught during compilation.
:compilation
- non-syntax errors caught during compilation.
:execution
- any errors thrown at execution time.
:read-eval-result
- any error thrown while reading the result of execution (only applicable for REPLs that read the result).
:print-eval-result
- any error thrown while printing the result of execution.
Exceptions thrown during all phases (exception :execution
) will have ex-data attached with one or more of the following keys:
:clojure.error/phase
- phase indicator
:clojure.error/source
- file name (no path)
:clojure.error/line
- integer line number
:clojure.error/column
- integer column number
:clojure.error/symbol
- symbol being expanded/compiled/invoked
:clojure.error/class
- cause exception class symbol
:clojure.error/cause
- cause exception message
:clojure.error/spec
- explain-data for a spec error
The clojure.main REPL includes the categorization and printing of errors by default, but the individual steps of this process are exposed as well for other REPLs to use, specifically the functions:
Throwable->map - converts an Exception chain into Clojure data
ex-triage - analyzes Clojure exception data to pull relevant information from the top and bottom of the exception chain into a map describing just the set of data needed to format an exception string
ex-str - produces a phase-appropriate message given a set of exception data
The clojure.main REPL combines these functions in a pipeline to produce the printed exception message: (-> ex Throwable->map clojure.main/ex-triage clojure.main/ex-str)
. Other REPLs can use one or more pieces of this pipeline as necessary when building or customizing their exception printing.
Up to Clojure 1.10.0, clojure.main when used as a program launcher (with -m, -e, or with a script), uncaught exceptions would be automatically printed along with the full nested stack trace. In this case, the error triage and printing process above was not applied.
As of Clojure 1.10.1, uncaught exceptions will now be caught and printed according to the same error triage and printing functionality as the Clojure REPL. The full stack trace, ex-info, and other information will be printed to a target specified by the configuration.
The three available error targets are:
file
- write to a temp file (default, falls back to stderr
)
stderr
- write to stderr stream
none
- don’t write
These error targets can be specified either as options to clojure.main, or as Java system properties (flags take precedence). When invoking clojure.main (or using the clj tool), use --report <target>
. For Java system property, use -Dclojure.main.report=<target>
.
Other programs may wish to take advantage of this functionality, and it is available in report-error, which takes a Throwable and optionally the :target.
user
namespaceBy default, the Clojure REPL starts in the user
namespace and this namespace is typically used for exploratory work.
The Clojure REPL automatically loads the following namespaces and refers the following functions:
If you switch to a different namespace (with in-ns
or ns
), these functions will not be available unless referred there explicitly.
user.clj
The Clojure runtime will look for and load user.clj
on runtime startup, if it is found on the classpath. This is a facility designed to provide development-time facilities, and generally not recommended in production use.
Because the user.clj
file is loaded by the Clojure runtime on initialization, this typically happens before the main namespace in an application executes. Any namespaces or resources loaded by user.clj
thus impacts startup time for your application.
There are many development-time cases where it would be useful to add a library interactively without restarting the JVM - speculative evaluation, adding a known dependency to your project, or adding a library to accomplish a specific task.
The Clojure CLI can be used to declare dependencies loaded at REPL startup time. Since Clojure 1.12, you can also dynamically load libraries at the REPL for interactive use. These functions are available in the clojure.repl.deps
namespace:
add-lib
takes a lib that is not available on the classpath, and makes it available by downloading (if necessary) and adding to the classloader. Libs already on the classpath are not updated. If the coordinate is not provided, the newest Maven version or git tag (if the library has an inferred git repo name) are used.
add-libs
is like add-lib
, but resolves a set of new libraries and versions together.
sync-deps
calls add-libs
with any libs present in deps.edn, but not yet present on the classpath.
These new functions are intended only for interactive use at the repl - using a deps.edn is still the proper way to build and maintain your code. To this end, these functions all check that *repl*
is bound to true
. In a clojure.main REPL, these new functions are automatically referred in the user namespace. In other repls, you may need to (require '[clojure.repl.deps :refer :all])
before use.
tap is a shared, globally accessible system for distributing a series of informational or diagnostic values to a set of (presumably effectful) handler functions. It can be used as a better debug prn
, or for facilities like logging etc.
tap>
sends a value to the set of taps. Taps can be added with add-tap
and will be called with any value sent to tap>. The tap function may (briefly) block (e.g. for streams) and will never impede calls to tap>, but blocking indefinitely may cause tap values to be dropped. If no taps are registered, tap> discards. Remove taps with remove-tap
.
The Clojure runtime now has the ability to start a socket server at initialization based on system properties. One expected use for this is serving a socket-based REPL, but it also has many other potential uses for dynamically adding server capability to existing programs without code changes.
A socket server will be started for each JVM system property like "clojure.server.<server-name>". The value for this property is an edn map representing the configuration of the socket server with the following properties:
server-daemon
- defaults to true, socket server thread doesn’t block exit
address
- host or address, defaults to loopback
port
- positive integer, required
accept
- namespaced symbol of function to invoke on socket accept, required
args
- sequential collection of args to pass to accept
bind-err
- defaults to true, binds *err*
to socket out stream
client-daemon
- defaults to true, socket client thread doesn’t block exit
Additionally, there is a repl function provided that is slightly customized for use with the socket server in clojure.core.server/repl.
Following is an example of starting a socket server with a repl listener. This can be added to any existing Clojure program to allow it to accept external REPL clients via a local connection to port 5555.
-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"
With the Clojure CLI, use -J
flag to pass the option to the JVM (note that this will also start a local REPL in addition to the socket REPL):
clj -J-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}"
An example client you can use to connect to this repl remotely is telnet (could also use netcat
):
$ telnet 127.0.0.1 5555
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
user=> (println "hello")
hello
You can instruct the server to close the client repl session by using the special command :repl/quit
:
user=> :repl/quit
Connection closed by foreign host.
Also see:
Main entry point: clojure.main/main
Reusable REPL: clojure.main/repl
Error handling: clojure.main/ex-triage
clojure.main/ex-str
Allowing set! for the customary REPL vars: clojure.main/with-bindings
Socket server control: clojure.core.server/start-server
clojure.core.server/stop-server
clojure.core.server/stop-servers
Socket repl: clojure.core.server/repl