Clojure "apropos"
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 anapropos
-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 \newline. 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) - 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.
In the meantime, I advise people that might be bitten by all the shortcomings in the API docs, to do what I did: read a free book, read the Reference, then take some time to go over all the clojure.core
functions once or twice. The last bit shouldn't take more than a couple of hours of focused work, and will be tough if you're not used to math-like precise writing, but it will pay off in many ways.