-
-
Notifications
You must be signed in to change notification settings - Fork 54
/
clojuredocs.clj
140 lines (122 loc) · 3.9 KB
/
clojuredocs.clj
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
136
137
138
139
140
(ns orchard.clojuredocs
"Find docs from ClojureDocs and retrieve the result as a map."
{:author "Masashi Iizuka"
:added "0.5"}
(:require
[clojure.edn :as edn]
[clojure.java.io :as io]
[clojure.string :as string]
[orchard.util.os :as os])
(:import
(java.io IOException)
(java.net URL)
(javax.net.ssl HttpsURLConnection)))
(def cache (atom {}))
(def default-edn-file-url
"https://github.com/clojure-emacs/clojuredocs-export-edn/raw/master/exports/export.compact.edn")
(def cache-file-name
(string/join os/file-separator [(os/cache-dir)
"orchard"
"clojuredocs"
"export.edn"]))
(def connect-timeout
"Timeout value for checking connection. Unit is millisecond."
1000)
(defn- write-cache-file! [url]
(.. (io/file cache-file-name)
getParentFile
mkdirs)
(->> url slurp (spit cache-file-name)))
(defn- load-cache-file! [cache-file]
(->> cache-file
slurp
edn/read-string
(reset! cache))
true)
(defn test-remote-url [^String url]
(if-not (.startsWith url "http")
;; Skip checks for non remote url
[true]
(let [url (URL. url)
conn ^HttpsURLConnection (.openConnection url)]
(.setConnectTimeout conn connect-timeout)
(try
(.connect conn)
[true]
(catch IOException ex
[false ex])
(finally
(.disconnect conn))))))
(defn load-docs-if-not-loaded!
"Load exported docs from bundled or cached file when no docs are loaded.
The Cached file take priority."
{:added "0.5"}
[]
(when (empty? @cache)
(let [cache-file (io/file cache-file-name)]
(load-cache-file!
(if (.exists cache-file)
cache-file
(io/resource "clojuredocs/export.edn"))))))
(defn update-cache!
"Load exported docs file from ClojureDocs, and store it as a cache.
A EDN format file is expected to the `export-edn-url` argument.
If `export-edn-url` is omitted, `default-edn-file-url` is used.
If `export-edn-url` is not accessible, `IOException` is thrown.
If `export-edn-url` is not a URL for remote host, `IllegalArgumentException` is thrown."
{:added "0.5"}
([]
(update-cache! default-edn-file-url))
([export-edn-url]
(let [cache-file (io/file cache-file-name)
;; connection check not to wait too long
[downloadable? conn-ex] (test-remote-url export-edn-url)]
(if (not downloadable?)
(throw conn-ex)
(do (write-cache-file! export-edn-url)
(load-cache-file! cache-file))))))
(defn clean-cache!
"Clean the cached ClojureDocs export file and the in memory cache."
{:added "0.5"}
[]
(.delete (io/file cache-file-name))
(reset! cache {}))
(defn get-doc
"Get data for `var-name`.
Bundled documentation will be used when there is no cached documentation."
{:added "0.5"}
[var-name]
(load-docs-if-not-loaded!)
(get @cache (keyword var-name)))
(defn find-doc
"Find documentation matching `ns` and `sym` from the cached documentation.
Bundled documentation will be used when there is no cached documentation.
Return nil if there is no matching documentation."
{:added "0.5"}
[ns sym]
(get-doc (keyword ns sym)))
(defn- var-name
"Convert `v`'s name to a string we can use with `get-doc`."
[v]
(subs (str v) 2))
(defn- try-ns-resolve [ns sym]
(try
(ns-resolve ns sym)
(catch Exception _
nil)))
(defn resolve-and-find-doc
"Resolve `sym` in the context of `ns` and look up the documentation
for the resulting var."
{:added "0.5"}
[ns sym]
(if (special-symbol? sym)
(find-doc "clojure.core" (str sym))
(some-> (try-ns-resolve ns sym) var-name get-doc)))
(defn- kw-to-sym [kw]
(symbol (subs (str kw) 1)))
(defn see-also
"Get the see-alsos for `var-name` if any."
{:added "0.5"}
[var-name]
(when-let [see-alsos (:see-alsos (get-doc var-name))]
(map kw-to-sym see-alsos)))