-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathclojure.clj
More file actions
135 lines (118 loc) · 3.78 KB
/
clojure.clj
File metadata and controls
135 lines (118 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
(ns codeina.reader.clojure
"Read raw documentation information from Clojure source directory."
(:require [clojure.java.io :as io]
[clojure.tools.namespace.find :as ns]
[clojure.string :as str]
[codeina.utils :refer (assoc-some update-some correct-indent)])
(:import java.util.jar.JarFile))
(defn- sorted-public-vars
[namespace]
(->> (ns-publics namespace)
(vals)
(sort-by (comp :name meta))))
(defn- no-doc?
"Return true if a var contains no-doc label."
[var]
(let [{:keys [skip-wiki no-doc]} (meta var)]
(or skip-wiki no-doc)))
(defn- proxy?
"Return true if provided var has reference to proxy
unstance?"
[var]
(re-find #"proxy\$" (-> var meta :name str)))
(defn- macro?
[var]
(:macro (meta var)))
(defn- multimethod?
[var]
(instance? clojure.lang.MultiFn (var-get var)))
(defn- protocol?
[var]
(let [value (var-get var)]
(and (map? value)
(not (sorted? value)) ; workaround for CLJ-1242
(:on-interface value))))
(defn- protocol-method?
[vars var]
(if-let [p (:protocol (meta var))]
(some #{p} vars)))
(defn- protocol-methods
[protocol vars]
(filter #(= protocol (:protocol (meta %))) vars))
(defn- var-type
[var]
(cond
(macro? var) :macro
(multimethod? var) :multimethod
(protocol? var) :protocol
:else :var))
(defn- read-var
[vars var]
(-> (meta var)
(select-keys [:name :file :line :arglists :doc :dynamic
:added :deprecated :doc/format])
(update-some :doc correct-indent)
(assoc-some :type (var-type var)
:members (seq (map (partial read-var vars)
(protocol-methods var vars))))))
(defn- read-publics
[namespace]
(let [vars (sorted-public-vars namespace)]
(->> vars
(remove proxy?)
(remove no-doc?)
(remove (partial protocol-method? vars))
(map (partial read-var vars))
(sort-by (comp str/lower-case :name)))))
(defn- read-ns
[namespace]
(try
(require namespace)
(-> (find-ns namespace)
(meta)
(assoc :name namespace)
(assoc :publics (read-publics namespace))
(update-some :doc correct-indent)
(list))
(catch Exception e
(println
(format "Could not generate clojure documentation for %s - root cause: %s %s"
namespace
(.getName (class e))
(.getMessage e))))))
(defn- jar-file?
[file]
(and
(.isFile file)
(-> file .getName (.endsWith ".jar"))))
(defn- find-namespaces
[file]
(cond
(.isDirectory file) (ns/find-namespaces-in-dir file)
(jar-file? file) (ns/find-namespaces-in-jarfile (JarFile. file))))
(defn read-namespaces
"Read Clojure namespaces from a source directory (defaults to
\"src\"), and return a list of maps suitable for documentation
purposes.
Any namespace with {:no-doc true} in its metadata will be skipped.
The keys in the maps are:
:name - the name of the namespace
:doc - the doc-string on the namespace
:author - the author of the namespace
:publics
:name - the name of a public function, macro, or value
:file - the file the var was declared in
:line - the line at which the var was declared
:arglists - the arguments the function or macro takes
:doc - the doc-string of the var
:type - one of :macro, :protocol, :multimethod or :var
:added - the library version the var was added in
:deprecated - the library version the var was deprecated in"
([] (read-namespaces "src"))
([path]
(->> (io/file path)
(find-namespaces)
(mapcat read-ns)
(remove :no-doc)))
([path & paths]
(mapcat read-namespaces (cons path paths))))