5

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?

1 Answer 1

8

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))]))
Sign up to request clarification or add additional context in comments.

2 Comments

A worse alternative (just to illustrate the point) would be to replace (doc f) with (eval `(doc ~f)) in the original code.
Thank you! I've run into the same problem before and solved it the way A. Webb mentioned but your way is more sane.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.