I want to write a function that returns the names and docstrings of the public functions in my namespace, like so:
(ns familiar.core
(:require [clojure.repl :refer [doc]]
...))
;; various functions with docstrings here
(defn help
"Halp!"
[]
(let [fns (keys (ns-publics 'familiar.core))]
(for [f fns]
[f (with-out-str (doc f))])))
When I call (help)
in the REPL, the docstrings don't come with the functions:
familiar.core=> (help)
([save-experiment ""] [load-experiment ""] [add-data ""] [help ""] ... )
But calling (with-out-str (doc add-data))
in the REPL works as I'd expect:
familiar.core=> (with-out-str (doc add-data))
"-------------------------\nfamiliar.core/add-data\n([& coll])\n
Adds instances of variables with values at active date.\n Examp
le:\n (add-data \"mice\" 6 \"cats\" 2 \"dogs\" 0)\n"
What's going on here?
Most Clojure code consists primarily of pure functions (no side effects), so invoking with the same inputs yields the same output. defn defines a named function: ;; name params body ;; ----- ------ ------------------- (defn greet [name] (str "Hello, " name) )
What is a REPL? A Clojure REPL (standing for Read-Eval-Print Loop) is a programming environment which enables the programmer to interact with a running Clojure program and modify it, by evaluating one code expression at a time.
A namespace is both a name context and a container for vars. Namespace names are symbols where periods are used to separate namespace parts, such as clojure. string . By convention, namespace names are typically lower-case and use - to separate words, although this is not required.
Namespaces are mappings from simple (unqualified) symbols to Vars and/or Classes. Vars can be interned in a namespace, using def or any of its variants, in which case they have a simple symbol for a name and a reference to their containing namespace, and the namespace maps that symbol to the same var.
doc
is a macro, so it cannot evaluate the local f
in the calling context. Instead, you are simply calling (doc f)
ovr and over.
The easiest approach to solve this is to go around the doc
macro, and look directly at the data that it uses to produce documentation: metadata on vars.
(defn help
"Halp!"
[x]
(for [[name var] (ns-publics 'familiar.core)]
[name (:doc (meta var))]))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With