On my 25 days of Clojure post I made a passing reference to Clojure needing an "apropos" command:

The Clojure documentation can be hard to decipher, and the clojure.core namespace is huge. ClojureDocs helps, but I believe there's a need for an apropos -like functionality built into the system.

In case you're not familiar with /usr/bin/apropos , here's what it looks like:

~> apropos audio SoX(1) - Sound eXchange, the Swiss Army knife of audio manipulation faad(1) - Process an Advanced Audio Codec stream flac(1) - Free Lossless Audio Codec gst-visualise-0.10(1), gst-visualise(1) - Run a GStreamer pipeline to display an audio visualisation lame(1) - create mp3 audio files libsox(3) - SoX, an audio file-format and effect library libswresample(3) - audio resampling library sndfile-cmp(1) - compares two audio files sndfile-concat(1) - concatenates two or more audio files soxeffect(7), SoX(7) - Sound eXchange, the Swiss Army knife of audio manipulation soxformat(7), SoX(7) - Sound eXchange, the Swiss Army knife of audio manipulation twolame(1) - an optimised MPEG Audio Layer 2 (MP2) encoder bluetoothaudiod(8) - The Mac OS X Bluetooth audio daemon mount_cddafs(8) - mount an Audio CD

This generated a couple of responses via tweets and private emails pointing out that Clojure does indeed have an apropos function:

(apropos str-or-pattern) Given a regular expression or stringable thing, return a seq of all public definitions in all currently-loaded namespaces that match the str-or-pattern.

However, even in the ClojureDocs apropos example you can see how it's not really what I had in mind:

user=> (apropos "temp") () user=> (require 'clojure.template) nil user=> (apropos "temp") (apply-template do-template)

... since it only searches the currently-loaded namespace. If you don't know what you're looking for, you probably won't have loaded the containing namespace in the first place. Of course, most of the time you're looking for something in clojure.core which is loaded by default, so let's move on.

Phrasing

Let's try another example. Let's say I want to add something to a collection. The keywords I'm thinking of are "add", "append", "prepend", "push", "insert". Here's what the output of apropos for all those are:

user=> (apropos "add") (clojure.core/add-classpath clojure.core/add-watch clojure.core/unchecked-add clojure.core/unchecked-add-int clojure.java.javadoc/add-local-javadoc clojure.java.javadoc/add-remote-javadoc clojure.tools.nrepl.middleware.session/add-stdin)

user=> (apropos "append") (clojure.core/chunk-append)

user=> (apropos "prepend") ()

user=> (apropos "push") (clojure.core/push-thread-bindings clojure.tools.reader.reader-types/indexing-push-back-reader clojure.tools.reader.reader-types/input-stream-push-back-reader clojure.tools.reader.reader-types/push-back-reader clojure.tools.reader.reader-types/source-logging-push-back-reader clojure.tools.reader.reader-types/string-push-back-reader)

user=> (apropos "insert") ()

Of course, the function I'm looking for is conj . Here's the built-in documentation for it:

user=> (doc conj) ------------------------- clojure.core/conj ([coll x] [coll x & xs]) conj[oin]. Returns a new collection with the xs 'added'. (conj nil item) returns (item). The 'addition' may happen at different 'places' depending on the concrete type.

You can see that "add" is mentioned twice, so you'd expect this would show up when doing (apropos "add") — but the fact is that clojure.repl/apropos searches only function names. This, combined with the very short names of most functions, results in very limited functionality.

Update: @mfikes on Twitter pointed out find-doc . It produces a ton of output though and it's not easily skimmable (I had to constrain the height of this code block to avoid messing the whole post up):

user=> (find-doc "add") ------------------------- clojure.tools.nrepl.middleware.session/add-stdin ([h]) stdin middleware. Returns a handler that supports a "stdin" :op-eration, which adds content provided in a :stdin slot to the session's *in* Reader. Delegates to the given handler for other operations. Requires the session middleware. ------------------------- clojure.tools.nrepl.middleware.session/session ([h]) Session middleware. Returns a handler which supports these :op-erations: * "ls-sessions", which results in a response message containing a list of the IDs of the currently-retained sessions in a :session slot. * "close", which drops the session indicated by the ID in the :session slot. The response message's :status will include :session-closed. * "clone", which will cause a new session to be retained. The ID of this new session will be returned in a response message in a :new-session slot. The new session's state (dynamic scope, etc) will be a copy of the state of the session identified in the :session slot of the request. Messages indicating other operations are delegated to the given handler, with the session identified by the :session ID added to the message. If no :session ID is found, a new session is created (which will only persist for the duration of the handling of the given message). Requires the interruptible-eval middleware (specifically, its binding of *msg* to the currently-evaluated message so that session-specific *out* and *err* content can be associated with the originating message). ------------------------- clojure.test/add-ns-meta ([key coll]) Adds elements in coll to the current namespace metadata as the value of key. ------------------------- clojure.tools.nrepl.server/start-server ([& {:keys [port bind transport-fn handler ack-port greeting-fn], :or {port 0}}]) Starts a socket-based nREPL server. Configuration options include: * :port — defaults to 0, which autoselects an open port on localhost * :bind — bind address, by default "localhost") * :handler — the nREPL message handler to use for each incoming connection; defaults to the result of `(default-handler)` * :transport-fn — a function that, given a java.net.Socket corresponding to an incoming connection, will return an value satisfying the clojure.tools.nrepl.Transport protocol for that Socket. * :ack-port — if specified, the port of an already-running server that will be connected to to inform of the new server's port. Useful only by Clojure tooling implementations. Returns a (map) handle to the server that is started, which may be stopped either via `stop-server`, (.close server), or automatically via `with-open`. The port that the server is open on is available in the :port slot of the server map (useful if the :port option is 0 or was left unspecified. ------------------------- clojure.core.server/start-server ([opts]) Start a socket server given the specified opts: :address Host or address, string, defaults to loopback address :port Port, integer, required :name Name, required :accept Namespaced symbol of the accept function to invoke, required :args Vector of args to pass to accept function :bind-err Bind *err* to socket out stream?, defaults to true :server-daemon Is server thread a daemon?, defaults to true :client-daemon Are client threads daemons?, defaults to true Returns server socket. ------------------------- cljs.stacktrace/parse-stacktrace Parse a JavaScript stacktrace string into a canonical data form. The arguments: repl-env - the repl environment, an optional map with :host and :port keys if the stacktrace includes url, not file references st - the original stacktrace string to parse err - an error map. :ua-product key defines the type of stacktrace parser to use, for example :chrome opts - additional options. :output-dir maybe given in this argument if :host and :port do not apply, for example, a file path The canonical stacktrace representation can easily be mapped to a ClojureScript one see mapped-stacktrace and mapped-stacktrace-str ------------------------- cljs.module-graph/add-cljs-base ([modules]) Adds :cljs-base module to compiler :modules if not already present. ------------------------- cljs.module-graph/add-cljs-base-dep ([modules]) Adds :cljs-base to any module in compiler :modules with an empty :depends-on. ------------------------- cljs.module-graph/inputs->assigned-modules ([inputs modules]) Given compiler inputs assign each to a single module. This is done by first starting with :entries. Dependencies for every entry in a module are also added to that module. Inputs may of course be assigned to several modules initially but we must eventually choose one. User supplied module :entries are respected but all other input assignments are computed automatically via deepest-common-parent. This function returns a map assigning all inputs (indexed by munged name) to a single module. Any orphan inputs will be assigned to :cljs-base. ------------------------- clojure.pprint/*print-miser-width* The column at which to enter miser style. Depending on the dispatch table, miser style add newlines in more places to try to keep lines short allowing for further levels of nesting. ------------------------- clojure.pprint/add-english-scales ([parts offset]) Take a sequence of parts, add scale numbers (e.g., million) and combine into a string offset is a factor of 10^3 to multiply by ------------------------- cljs.analyzer/add-consts ([compiler-state constants-map]) Given a compiler state and a map from fully qualified symbols to constant EDN values, update the compiler state marking these vars as const to support direct substitution of these vars in source. ------------------------- clojure.set/join ([xrel yrel] [xrel yrel km]) When passed 2 rels, returns the rel corresponding to the natural join. When passed an additional keymap, joins on the corresponding keys. ------------------------- cljs.repl/repl ([repl-env & opts]) Generic, reusable, read-eval-print loop. By default, reads from *in* using a c.t.r.reader-types/source-logging-push-back-reader, writes to *out*, and prints exception summaries to *err*. If you use the default :read hook, *in* must either be an instance of c.t.r.reader-types/PushbackReader or duplicate its behavior of both supporting unread and collapsing CR, LF, and CRLF into a single

ewline. Options are sequential keyword-value pairs. The first argument is the JavaScript evaluation environment, the second argument is an extended version of the standard ClojureScript compiler options. In addition to ClojureScript compiler build options it also take a set of options similar to clojure.main/repl with adjustments for ClojureScript evalution and compilation model: Available clojure.main/repl style options and their defaults: - :init, function of no arguments, initialization hook called with bindings for set!-able vars in place. default: #() - :need-prompt, function of no arguments, called before each read-eval-print except the first, the user will be prompted if it returns true. default: #(if (c.t.r.readers-types/indexing-reader? *in*) (== (c.t.r.reader-types/get-column-number *in*) 1) (identity true)) - :prompt, function of no arguments, prompts for more input. default: repl-prompt - :flush, function of no arguments, flushes output default: flush - :read, function of two arguments, reads from *in*: - returns its first argument to request a fresh prompt - depending on need-prompt, this may cause the repl to prompt before reading again - returns its second argument to request an exit from the repl - else returns the next object read from the input stream default: repl-read - :eval, function of one argument, returns the evaluation of its argument. The eval function must take repl-env, the JavaScript evaluation environment, env, the ClojureScript analysis environment, the form and opts, the standard ClojureScript REPL/compiler options. default: eval - :print, function of one argument, prints its argument to the output default: println - :caught, function of three arguments, a throwable, called when read, eval, or print throws an exception or error default. The second argument is the JavaScript evaluation environment this permits context sensitive handling if necessary. The third argument is opts, the standard ClojureScript REPL/compiler options. In the case of errors or exception in the JavaScript target, these will be thrown as clojure.lang.IExceptionInfo instances. default: repl-caught - :reader, the c.t.r reader to use. default: c.t.r.reader-types/source-logging-push-back-reader - :print-no-newline, print without a newline. default: print - :source-map-inline, whether inline source maps should be enabled. Most useful in browser context. Implies using a fresh reader for each form. default: true ------------------------- clojure.java.javadoc/add-local-javadoc ([path]) Adds to the list of local Javadoc paths. ------------------------- clojure.java.javadoc/add-remote-javadoc ([package-prefix url]) Adds to the list of remote Javadoc URLs. package-prefix is the beginning of the package name that has docs at this URL. ------------------------- clojure.tools.nrepl/client-session ([client & {:keys [session clone]}]) Returns a function of one argument. Accepts a message that is sent via the client provided with a fixed :session id added to it. Returns the head of the client's response seq, filtered to include only messages related to the :session id that will terminate when the session is closed. ------------------------- clojure.tools.nrepl/message ([client {:keys [id], :as msg, :or {id (uuid)}}]) Sends a message via [client] with a fixed message :id added to it. Returns the head of the client's response seq, filtered to include only messages related to the message :id that will terminate upon receipt of a "done" :status. ------------------------- clojure.tools.nrepl/url-connect Connects to an nREPL endpoint identified by the given URL/URI. Valid examples include: nrepl://192.168.0.12:7889 telnet://localhost:5000 http://your-app-name.heroku.com/repl This is a multimethod that dispatches on the scheme of the URI provided (which can be a string or java.net.URI). By default, implementations for nrepl (corresponding to using the default bencode transport) and telnet (using the clojure.tools.nrepl.transport/tty transport) are registered. Alternative implementations may add support for other schemes, such as HTTP, HTTPS, JMX, existing message queues, etc. ------------------------- cljs.closure/add-core-macros-if-cljs-js ([compiled]) If a compiled entity is the cljs.js namespace, explicitly add the cljs.core macros namespace dependency to it. ------------------------- cljs.closure/add-dep-string ([opts input]) Return a goog.addDependency string for an input. ------------------------- cljs.closure/add-dependencies ([opts & inputs]) Given one or more IJavaScript objects in dependency order, produce a new sequence of IJavaScript objects which includes the input list plus all dependencies in dependency order. ------------------------- cljs.closure/add-dependency-sources ([inputs] [inputs compile-opts]) Given list of IJavaScript objects, produce a new sequence of IJavaScript objects of all dependencies of inputs. ------------------------- cljs.closure/add-js-sources ([inputs opts]) Given list of IJavaScript objects, add foreign-deps, constants-table IJavaScript objects to the list. ------------------------- cljs.closure/add-preloads ([inputs opts]) Add :preloads to a given set of inputs (IJavaScript). Returns a new list of inputs where the preloaded namespaces and their deps come immediately after cljs.core or the constants table depending on the optimization setting. Any files needing copying or compilation will be compiled and/or copied to the appropiate location. ------------------------- cljs.closure/watch ([source opts] [source opts compiler-env] [source opts compiler-env quit]) Given a source directory, produce runnable JavaScript. Watch the source directory for changes rebuilding when necessary. Takes the same arguments as cljs.closure/build in addition to some watch-specific options: - :watch-fn, a function of no arguments to run after a successful build. - :watch-error-fn, a function receiving the exception of a failed build. ------------------------- clojure.tools.nrepl.middleware/topologically-sort ([comparator stack]) Topologically sorts the given middlewares according to the comparator, with the added huristic that any middlewares that have no dependencies will be sorted toward the end. ------------------------- clojure.tools.reader.impl.errors/eof-error ([rdr & msgs]) Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided ------------------------- clojure.tools.reader.impl.errors/illegal-arg-error ([rdr & msgs]) Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided ------------------------- clojure.tools.reader.impl.errors/reader-error ([rdr & msgs]) Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided ------------------------- clojure.core/add-classpath ([url]) DEPRECATED Adds the url (String or URL object) to the classpath per URLClassLoader.addURL ------------------------- clojure.core/add-watch ([reference key fn]) Adds a watch function to an agent/atom/var/ref reference. The watch fn must be a fn of 4 args: a key, the reference, its old-state, its new-state. Whenever the reference's state might have been changed, any registered watches will have their functions called. The watch fn will be called synchronously, on the agent's thread if an agent, before any pending sends if agent or ref. Note that an atom's or ref's state may have changed again prior to the fn call, so use old/new-state rather than derefing the reference. Note also that watch fns may be called from multiple threads simultaneously. Var watchers are triggered only by root binding changes, not thread-local set!s. Keys must be unique per reference, and can be used to remove the watch with remove-watch, but are otherwise considered opaque by the watch mechanism. ------------------------- clojure.core/assoc! ([coll key val] [coll key val & kvs]) When applied to a transient map, adds mapping of key(s) to val(s). When applied to a transient vector, sets the val at index. Note - index must be <= (count vector). Returns coll. ------------------------- clojure.core/completing ([f] [f cf]) Takes a reducing function f of 2 args and returns a fn suitable for transduce by adding an arity-1 signature that calls cf (default - identity) on the result argument. ------------------------- clojure.core/conj ([coll x] [coll x & xs]) conj[oin]. Returns a new collection with the xs 'added'. (conj nil item) returns (item). The 'addition' may happen at different 'places' depending on the concrete type. ------------------------- clojure.core/conj! ([] [coll] [coll x]) Adds x to the transient collection, and return coll. The 'addition' may happen at different 'places' depending on the concrete type. ------------------------- clojure.core/defn ([name doc-string? attr-map? [params*] prepost-map? body] [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?]) Macro Same as (def name (fn [params* ] exprs*)) or (def name (fn ([params* ] exprs*)+)) with any doc-string or attrs added to the var metadata. prepost-map defines a map with optional keys :pre and :post that contain collections of pre or post conditions. ------------------------- clojure.core/defrecord ([name [& fields] & opts+specs]) Macro (defrecord name [fields*] options* specs*) Options are expressed as sequential keywords and arguments (in any order). Supported options: :load-ns - if true, importing the record class will cause the namespace in which the record was defined to be loaded. Defaults to false. Each spec consists of a protocol or interface name followed by zero or more method bodies: protocol-or-interface-or-Object (methodName [args*] body)* Dynamically generates compiled bytecode for class with the given name, in a package with the same name as the current namespace, the given fields, and, optionally, methods for protocols and/or interfaces. The class will have the (immutable) fields named by fields, which can have type hints. Protocols/interfaces and methods are optional. The only methods that can be supplied are those declared in the protocols/interfaces. Note that method bodies are not closures, the local environment includes only the named fields, and those fields can be accessed directly. Method definitions take the form: (methodname [args*] body) The argument and return types can be hinted on the arg and methodname symbols. If not supplied, they will be inferred, so type hints should be reserved for disambiguation. Methods should be supplied for all methods of the desired protocol(s) and interface(s). You can also define overrides for methods of Object. Note that a parameter must be supplied to correspond to the target object ('this' in Java parlance). Thus methods for interfaces will take one more argument than do the interface declarations. Note also that recur calls to the method head should *not* pass the target object, it will be supplied automatically and can not be substituted. In the method bodies, the (unqualified) name can be used to name the class (for calls to new, instance? etc). The class will have implementations of several (clojure.lang) interfaces generated automatically: IObj (metadata support) and IPersistentMap, and all of their superinterfaces. In addition, defrecord will define type-and-value-based =, and will defined Java .hashCode and .equals consistent with the contract for java.util.Map. When AOT compiling, generates compiled bytecode for a class with the given name (a symbol), prepends the current ns as the package, and writes the .class file to the *compile-path* directory. Two constructors will be defined, one taking the designated fields followed by a metadata map (nil for none) and an extension field map (nil for none), and one taking only the fields (using nil for meta and extension fields). Note that the field names __meta and __extmap are currently reserved and should not be used when defining your own records. Given (defrecord TypeName ...), two factory functions will be defined: ->TypeName, taking positional parameters for the fields, and map->TypeName, taking a map of keywords to field values. ------------------------- clojure.core/ex-info ([msg map] [msg map cause]) Create an instance of ExceptionInfo, a RuntimeException subclass that carries a map of additional data. ------------------------- clojure.core/find-keyword ([name] [ns name]) Returns a Keyword with the given namespace and name if one already exists. This function will not intern a new keyword. If the keyword has not already been interned, it will return nil. Do not use : in the keyword strings, it will be added automatically. ------------------------- clojure.core/gen-class ([& options]) Macro When compiling, generates compiled bytecode for a class with the given package-qualified :name (which, as all names in these parameters, can be a string or symbol), and writes the .class file to the *compile-path* directory. When not compiling, does nothing. The gen-class construct contains no implementation, as the implementation will be dynamically sought by the generated class in functions in an implementing Clojure namespace. Given a generated class org.mydomain.MyClass with a method named mymethod, gen-class will generate an implementation that looks for a function named by (str prefix mymethod) (default prefix: "-") in a Clojure namespace specified by :impl-ns (defaults to the current namespace). All inherited methods, generated methods, and init and main functions (see :methods, :init, and :main below) will be found similarly prefixed. By default, the static initializer for the generated class will attempt to load the Clojure support code for the class as a resource from the classpath, e.g. in the example case, ``org/mydomain/MyClass__init.class``. This behavior can be controlled by :load-impl-ns Note that methods with a maximum of 18 parameters are supported. In all subsequent sections taking types, the primitive types can be referred to by their Java names (int, float etc), and classes in the java.lang package can be used without a package qualifier. All other classes must be fully qualified. Options should be a set of key/value pairs, all except for :name are optional: :name aname The package-qualified name of the class to be generated :extends aclass Specifies the superclass, the non-private methods of which will be overridden by the class. If not provided, defaults to Object. :implements [interface ...] One or more interfaces, the methods of which will be implemented by the class. :init name If supplied, names a function that will be called with the arguments to the constructor. Must return [ [superclass-constructor-args] state] If not supplied, the constructor args are passed directly to the superclass constructor and the state will be nil :constructors {[param-types] [super-param-types], ...} By default, constructors are created for the generated class which match the signature(s) of the constructors for the superclass. This parameter may be used to explicitly specify constructors, each entry providing a mapping from a constructor signature to a superclass constructor signature. When you supply this, you must supply an :init specifier. :post-init name If supplied, names a function that will be called with the object as the first argument, followed by the arguments to the constructor. It will be called every time an object of this class is created, immediately after all the inherited constructors have completed. Its return value is ignored. :methods [ [name [param-types] return-type], ...] The generated class automatically defines all of the non-private methods of its superclasses/interfaces. This parameter can be used to specify the signatures of additional methods of the generated class. Static methods can be specified with ^{:static true} in the signature's metadata. Do not repeat superclass/interface signatures here. :main boolean If supplied and true, a static public main function will be generated. It will pass each string of the String[] argument as a separate argument to a function called (str prefix main). :factory name If supplied, a (set of) public static factory function(s) will be created with the given name, and the same signature(s) as the constructor(s). :state name If supplied, a public final instance field with the given name will be created. You must supply an :init function in order to provide a value for the state. Note that, though final, the state can be a ref or agent, supporting the creation of Java objects with transactional or asynchronous mutation semantics. :exposes {protected-field-name {:get name :set name}, ...} Since the implementations of the methods of the generated class occur in Clojure functions, they have no access to the inherited protected fields of the superclass. This parameter can be used to generate public getter/setter methods exposing the protected field(s) for use in the implementation. :exposes-methods {super-method-name exposed-name, ...} It is sometimes necessary to call the superclass' implementation of an overridden method. Those methods may be exposed and referred in the new method implementation by a local name. :prefix string Default: "-" Methods called e.g. Foo will be looked up in vars called prefixFoo in the implementing ns. :impl-ns name Default: the name of the current ns. Implementations of methods will be looked up in this namespace. :load-impl-ns boolean Default: true. Causes the static initializer for the generated class to reference the load code for the implementing namespace. Should be true when implementing-ns is the default, false if you intend to load the code via some other method. ------------------------- clojure.core/import ([& import-symbols-or-lists]) Macro import-list => (package-symbol class-name-symbols*) For each name in class-name-symbols, adds a mapping from name to the class named by package.name to the current namespace. Use :import in the ns macro in preference to calling this directly. ------------------------- clojure.core/init-proxy ([proxy mappings]) Takes a proxy instance and a map of strings (which must correspond to methods of the proxy superclass/superinterfaces) to fns (which must take arguments matching the corresponding method, plus an additional (explicit) first arg corresponding to this, and sets the proxy's fn map. Returns the proxy. ------------------------- clojure.core/keyword ([name] [ns name]) Returns a Keyword with the given namespace and name. Do not use : in the keyword strings, it will be added automatically. ------------------------- clojure.core/partial ([f] [f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more]) Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable number of additional args. When called, the returned function calls f with args + additional args. ------------------------- clojure.core/partition ([n coll] [n step coll] [n step pad coll]) Returns a lazy sequence of lists of n items each, at offsets step apart. If step is not supplied, defaults to n, i.e. the partitions do not overlap. If a pad collection is supplied, use its elements as necessary to complete last partition upto n items. In case there are not enough padding elements, return a partition with less than n items. ------------------------- clojure.core/proxy ([class-and-interfaces args & fs]) Macro class-and-interfaces - a vector of class names args - a (possibly empty) vector of arguments to the superclass constructor. f => (name [params*] body) or (name ([params*] body) ([params+] body) ...) Expands to code which creates a instance of a proxy class that implements the named class/interface(s) by calling the supplied fns. A single class, if provided, must be first. If not provided it defaults to Object. The interfaces names must be valid interface types. If a method fn is not provided for a class method, the superclass methd will be called. If a method fn is not provided for an interface method, an UnsupportedOperationException will be thrown should it be called. Method fns are closures and can capture the environment in which proxy is called. Each method fn takes an additional implicit first arg, which is bound to 'this. Note that while method fns can be provided to override protected methods, they have no other access to protected members, nor to super, as these capabilities cannot be proxied. ------------------------- clojure.core/refer ([ns-sym & filters]) refers to all public vars of ns, subject to filters. filters can include at most one each of: :exclude list-of-symbols :only list-of-symbols :rename map-of-fromsymbol-tosymbol For each public interned var in the namespace named by the symbol, adds a mapping from the name of the var to the var to the current namespace. Throws an exception if name is already mapped to something else in the current namespace. Filters can be used to select a subset, via inclusion or exclusion, or to provide a mapping to a symbol different from the var's name, in order to prevent clashes. Use :use in the ns macro in preference to calling this directly. ------------------------- clojure.core/remove-watch ([reference key]) Removes a watch (set by add-watch) from a reference ------------------------- clojure.core/require ([& args]) Loads libs, skipping any that are already loaded. Each argument is either a libspec that identifies a lib, a prefix list that identifies multiple libs whose names share a common prefix, or a flag that modifies how all the identified libs are loaded. Use :require in the ns macro in preference to calling this directly. Libs A 'lib' is a named set of resources in classpath whose contents define a library of Clojure code. Lib names are symbols and each lib is associated with a Clojure namespace and a Java package that share its name. A lib's name also locates its root directory within classpath using Java's package name to classpath-relative path mapping. All resources in a lib should be contained in the directory structure under its root directory. All definitions a lib makes should be in its associated namespace. 'require loads a lib by loading its root resource. The root resource path is derived from the lib name in the following manner: Consider a lib named by the symbol 'x.y.z; it has the root directory /x/y/, and its root resource is /x/y/z.clj. The root resource should contain code to create the lib's namespace (usually by using the ns macro) and load any additional lib resources. Libspecs A libspec is a lib name or a vector containing a lib name followed by options expressed as sequential keywords and arguments. Recognized options: :as takes a symbol as its argument and makes that symbol an alias to the lib's namespace in the current namespace. :refer takes a list of symbols to refer from the namespace or the :all keyword to bring in all public vars. Prefix Lists It's common for Clojure code to depend on several libs whose names have the same prefix. When specifying libs, prefix lists can be used to reduce repetition. A prefix list contains the shared prefix followed by libspecs with the shared prefix removed from the lib names. After removing the prefix, the names that remain must not contain any periods. Flags A flag is a keyword. Recognized flags: :reload, :reload-all, :verbose :reload forces loading of all the identified libs even if they are already loaded :reload-all implies :reload and also forces loading of all libs that the identified libs directly or indirectly load via require or use :verbose triggers printing information about each load, alias, and refer Example: The following would load the libraries clojure.zip and clojure.set abbreviated as 's'. (require '(clojure zip [set :as s])) ------------------------- clojure.core/transduce ([xform f coll] [xform f init coll]) reduce with a transformation of f (xf). If init is not supplied, (f) will be called to produce it. f should be a reducing step function that accepts both 1 and 2 arguments, if it accepts only 2 you can add the arity-1 with 'completing'. Returns the result of applying (the transformed) xf to init and the first item in coll, then applying xf to that result and the 2nd item, etc. If coll contains no items, returns init and f is not called. Note that certain transforms may inject or skip items. ------------------------- clojure.core/unchecked-add ([x y]) Returns the sum of x and y, both long. Note - uses a primitive operator subject to overflow. ------------------------- clojure.core/unchecked-add-int ([x y]) Returns the sum of x and y, both int. Note - uses a primitive operator subject to overflow. ------------------------- clojure.core/update-proxy ([proxy mappings]) Takes a proxy instance and a map of strings (which must correspond to methods of the proxy superclass/superinterfaces) to fns (which must take arguments matching the corresponding method, plus an additional (explicit) first arg corresponding to this, and updates (via assoc) the proxy's fn map. nil can be passed instead of a fn, in which case the corresponding method will revert to the default behavior. Note that this function can be used to update the behavior of an existing instance without changing its identity. Returns the proxy. ------------------------- clojure.core/use ([& args]) Like 'require, but also refers to each lib's namespace using clojure.core/refer. Use :use in the ns macro in preference to calling this directly. 'use accepts additional options in libspecs: :exclude, :only, :rename. The arguments and semantics for :exclude, :only, and :rename are the same as those documented for clojure.core/refer. ------------------------- cljs.core/defn ([name doc-string? attr-map? [params*] prepost-map? body] [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?]) Macro Same as (def name (core/fn [params* ] exprs*)) or (def name (core/fn ([params* ] exprs*)+)) with any doc-string or attrs added to the var metadata. prepost-map defines a map with optional keys :pre and :post that contain collections of pre or post conditions. ------------------------- cljs.core/defrecord ([rsym fields & impls]) Macro (defrecord name [fields*] options* specs*) Currently there are no options. Each spec consists of a protocol or interface name followed by zero or more method bodies: protocol-or-Object (methodName [args*] body)* The record will have the (immutable) fields named by fields, which can have type hints. Protocols and methods are optional. The only methods that can be supplied are those declared in the protocols. Note that method bodies are not closures, the local environment includes only the named fields, and those fields can be accessed directly. Method definitions take the form: (methodname [args*] body) The argument and return types can be hinted on the arg and methodname symbols. If not supplied, they will be inferred, so type hints should be reserved for disambiguation. Methods should be supplied for all methods of the desired protocol(s). You can also define overrides for methods of Object. Note that a parameter must be supplied to correspond to the target object ('this' in JavaScript parlance). Note also that recur calls to the method head should *not* pass the target object, it will be supplied automatically and can not be substituted. In the method bodies, the (unqualified) name can be used to name the class (for calls to new, instance? etc). The type will have implementations of several ClojureScript protocol generated automatically: IMeta/IWithMeta (metadata support) and IMap, etc. In addition, defrecord will define type-and-value-based =, and will define ClojureScript IHash and IEquiv. Two constructors will be defined, one taking the designated fields followed by a metadata map (nil for none) and an extension field map (nil for none), and one taking only the fields (using nil for meta and extension fields). Note that the field names __meta and __extmap are currently reserved and should not be used when defining your own records. Given (defrecord TypeName ...), two factory functions will be defined: ->TypeName, taking positional parameters for the fields, and map->TypeName, taking a map of keywords to field values. ------------------------- cljs.core/import ([& import-symbols-or-lists]) Macro import-list => (closure-namespace constructor-name-symbols*) For each name in constructor-name-symbols, adds a mapping from name to the constructor named by closure-namespace to the current namespace. Use :import in the ns macro in preference to calling this directly. ------------------------- cljs.core/require ([& args]) Macro Loads libs, skipping any that are already loaded. Each argument is either a libspec that identifies a lib or a flag that modifies how all the identified libs are loaded. Use :require in the ns macro in preference to calling this directly. Libs A 'lib' is a named set of resources in classpath whose contents define a library of ClojureScript code. Lib names are symbols and each lib is associated with a ClojureScript namespace. A lib's name also locates its root directory within classpath using Java's package name to classpath-relative path mapping. All resources in a lib should be contained in the directory structure under its root directory. All definitions a lib makes should be in its associated namespace. 'require loads a lib by loading its root resource. The root resource path is derived from the lib name in the following manner: Consider a lib named by the symbol 'x.y.z; it has the root directory /x/y/, and its root resource is /x/y/z.clj. The root resource should contain code to create the lib's namespace (usually by using the ns macro) and load any additional lib resources. Libspecs A libspec is a lib name or a vector containing a lib name followed by options expressed as sequential keywords and arguments. Recognized options: :as takes a symbol as its argument and makes that symbol an alias to the lib's namespace in the current namespace. :refer takes a list of symbols to refer from the namespace. :refer-macros takes a list of macro symbols to refer from the namespace. :include-macros true causes macros from the namespace to be required. :rename specifies a map from referred var names to different symbols (and can be used to prevent clashes) Flags A flag is a keyword. Recognized flags: :reload, :reload-all, :verbose :reload forces loading of all the identified libs even if they are already loaded :reload-all implies :reload and also forces loading of all libs that the identified libs directly or indirectly load via require or use :verbose triggers printing information about each load, alias, and refer Example: The following would load the library clojure.string :as string. (require '[clojure.string :as string]) ------------------------- clojure.test A unit testing framework. ASSERTIONS The core of the library is the "is" macro, which lets you make assertions of any arbitrary expression: (is (= 4 (+ 2 2))) (is (instance? Integer 256)) (is (.startsWith "abcde" "ab")) You can type an "is" expression directly at the REPL, which will print a message if it fails. user> (is (= 5 (+ 2 2))) FAIL in (:1) expected: (= 5 (+ 2 2)) actual: (not (= 5 4)) false The "expected:" line shows you the original expression, and the "actual:" shows you what actually happened. In this case, it shows that (+ 2 2) returned 4, which is not = to 5. Finally, the "false" on the last line is the value returned from the expression. The "is" macro always returns the result of the inner expression. There are two special assertions for testing exceptions. The "(is (thrown? c ...))" form tests if an exception of class c is thrown: (is (thrown? ArithmeticException (/ 1 0))) "(is (thrown-with-msg? c re ...))" does the same thing and also tests that the message on the exception matches the regular expression re: (is (thrown-with-msg? ArithmeticException #"Divide by zero" (/ 1 0))) DOCUMENTING TESTS "is" takes an optional second argument, a string describing the assertion. This message will be included in the error report. (is (= 5 (+ 2 2)) "Crazy arithmetic") In addition, you can document groups of assertions with the "testing" macro, which takes a string followed by any number of assertions. The string will be included in failure reports. Calls to "testing" may be nested, and all of the strings will be joined together with spaces in the final report, in a style similar to RSpec (testing "Arithmetic" (testing "with positive integers" (is (= 4 (+ 2 2))) (is (= 7 (+ 3 4)))) (testing "with negative integers" (is (= -4 (+ -2 -2))) (is (= -1 (+ 3 -4))))) Note that, unlike RSpec, the "testing" macro may only be used INSIDE a "deftest" or "with-test" form (see below). DEFINING TESTS There are two ways to define tests. The "with-test" macro takes a defn or def form as its first argument, followed by any number of assertions. The tests will be stored as metadata on the definition. (with-test (defn my-function [x y] (+ x y)) (is (= 4 (my-function 2 2))) (is (= 7 (my-function 3 4)))) As of Clojure SVN rev. 1221, this does not work with defmacro. See http://code.google.com/p/clojure/issues/detail?id=51 The other way lets you define tests separately from the rest of your code, even in a different namespace: (deftest addition (is (= 4 (+ 2 2))) (is (= 7 (+ 3 4)))) (deftest subtraction (is (= 1 (- 4 3))) (is (= 3 (- 7 4)))) This creates functions named "addition" and "subtraction", which can be called like any other function. Therefore, tests can be grouped and composed, in a style similar to the test framework in Peter Seibel's "Practical Common Lisp" (deftest arithmetic (addition) (subtraction)) The names of the nested tests will be joined in a list, like "(arithmetic addition)", in failure reports. You can use nested tests to set up a context shared by several tests. RUNNING TESTS Run tests with the function "(run-tests namespaces...)": (run-tests 'your.namespace 'some.other.namespace) If you don't specify any namespaces, the current namespace is used. To run all tests in all namespaces, use "(run-all-tests)". By default, these functions will search for all tests defined in a namespace and run them in an undefined order. However, if you are composing tests, as in the "arithmetic" example above, you probably do not want the "addition" and "subtraction" tests run separately. In that case, you must define a special function named "test-ns-hook" that runs your tests in the correct order: (defn test-ns-hook [] (arithmetic)) Note: test-ns-hook prevents execution of fixtures (see below). OMITTING TESTS FROM PRODUCTION CODE You can bind the variable "*load-tests*" to false when loading or compiling code in production. This will prevent any tests from being created by "with-test" or "deftest". FIXTURES Fixtures allow you to run code before and after tests, to set up the context in which tests should be run. A fixture is just a function that calls another function passed as an argument. It looks like this: (defn my-fixture [f] Perform setup, establish bindings, whatever. (f) Then call the function we were passed. Tear-down / clean-up code here. ) Fixtures are attached to namespaces in one of two ways. "each" fixtures are run repeatedly, once for each test function created with "deftest" or "with-test". "each" fixtures are useful for establishing a consistent before/after state for each test, like clearing out database tables. "each" fixtures can be attached to the current namespace like this: (use-fixtures :each fixture1 fixture2 ...) The fixture1, fixture2 are just functions like the example above. They can also be anonymous functions, like this: (use-fixtures :each (fn [f] setup... (f) cleanup...)) The other kind of fixture, a "once" fixture, is only run once, around ALL the tests in the namespace. "once" fixtures are useful for tasks that only need to be performed once, like establishing database connections, or for time-consuming tasks. Attach "once" fixtures to the current namespace like this: (use-fixtures :once fixture1 fixture2 ...) Note: Fixtures and test-ns-hook are mutually incompatible. If you are using test-ns-hook, fixture functions will *never* be run. SAVING TEST OUTPUT TO A FILE All the test reporting functions write to the var *test-out*. By default, this is the same as *out*, but you can rebind it to any PrintWriter. For example, it could be a file opened with clojure.java.io/writer. EXTENDING TEST-IS (ADVANCED) You can extend the behavior of the "is" macro by defining new methods for the "assert-expr" multimethod. These methods are called during expansion of the "is" macro, so they should return quoted forms to be evaluated. You can plug in your own test-reporting framework by rebinding the "report" function: (report event) The 'event' argument is a map. It will always have a :type key, whose value will be a keyword signaling the type of event being reported. Standard events with :type value of :pass, :fail, and :error are called when an assertion passes, fails, and throws an exception, respectively. In that case, the event will also have the following keys: :expected The form that was expected to be true :actual A form representing what actually occurred :message The string message given as an argument to 'is' The "testing" strings will be a list in "*testing-contexts*", and the vars being tested will be a list in "*testing-vars*". Your "report" function should wrap any printing calls in the "with-test-out" macro, which rebinds *out* to the current value of *test-out*. For additional event types, see the examples in the code. ------------------------- clojure.pprint A Pretty Printer for Clojure clojure.pprint implements a flexible system for printing structured data in a pleasing, easy-to-understand format. Basic use of the pretty printer is simple, just call pprint instead of println. More advanced users can use the building blocks provided to create custom output formats. Out of the box, pprint supports a simple structured format for basic data and a specialized format for Clojure source code. More advanced formats, including formats that don't look like Clojure data at all like XML and JSON, can be rendered by creating custom dispatch functions. In addition to the pprint function, this module contains cl-format, a text formatting function which is fully compatible with the format function in Common Lisp. Because pretty printing directives are directly integrated with cl-format, it supports very concise custom dispatch. It also provides a more powerful alternative to Clojure's standard format function. See documentation for pprint and cl-format for more information or complete documentation on the the clojure web site on github. ------------------------- cljs.closure Compile ClojureScript to JavaScript with optimizations from Google Closure Compiler producing runnable JavaScript. The Closure Compiler (compiler.jar) must be on the classpath. Use the 'build' function for end-to-end compilation. build = find-sources -> add-dependencies -> compile -> optimize -> output Two protocols are defined: IJavaScript and Compilable. The Compilable protocol is satisfied by something which can return one or more IJavaScripts. With IJavaScript objects in hand, calling add-dependencies will produce a sequence of IJavaScript objects which includes all required dependencies from the Closure library and ClojureScript, in dependency order. This function replaces the closurebuilder tool. The optimize function converts one or more IJavaScripts into a single string of JavaScript source code using the Closure Compiler API. The produced output is either a single string of optimized JavaScript or a deps file for use during development. nil

Grouping

Since I'm talking about function discoverability, here's another thing I complained about:

... the clojure.core namespace is huge...

How huge?

user=> (count (keys (ns-publics 'clojure.core))) 621

(I tried to figure this out on my own, but in the end I had to resort to StackOverflow)

This includes:

special forms

arithmetic, bitwise, boolean operators

global variables

some string functions (but others are in clojure.string

regex functions

flow control functions & macros

introspection & type stuff

concurrency stuff (though core.async is separate)

is separate) stuff that deal with functions (e.g. fn , defn , partial )

, , ) Java interop

Collections and related functions

IO

and much more — a more complete overview can be found on the ClojureDocs quickref.

I understand the reasoning behind this; you need most of those for day to day work, and making you require a namespace just to get map / filter would get old really quick. However, this makes it really difficult for a newcomer to discover what they are looking for.

Proposal

I believe that fixing the above stated problems is quite doable and can be even done in parallel:

Expand or add to the somewhat dry and too-concise function documentation. Use a format that can link to other functions, show in-line examples etc.

Group the various functions into related functionality. The ClojureDocs quick reference linked above goes a long way towards this, but needs to be officially adopted and maintained.

Link the API docs back to the Reference and Guides (the Reference already links to the API docs).

Do all this in a way that lends itself to better doc generation, incl. integration with 3rd-party tools like Dash.

Update: See also the 2017 ClojuTRE talk Towards Awesome Clojure Documentation by Bozhidar Batsov that goes into some more examples and proposals.

Meanwhile

I'd like to thank all the Clojure contributors for their work on the language. I hope I will have time in the future to contribute my own time towards some of those ideas, as this is the only feasible way to grow a language.