-
-
Notifications
You must be signed in to change notification settings - Fork 54
/
misc.clj
203 lines (173 loc) · 5.58 KB
/
misc.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
(ns orchard.misc
;; These will be added in clojure 1.11:
(:refer-clojure :exclude [update-keys update-vals])
(:require
[clojure.java.io :as io]
[clojure.string :as string]
[orchard.util.io :as util.io]))
(require 'clojure.core.protocols)
(defn os-windows? []
(.startsWith (System/getProperty "os.name") "Windows"))
(defn boot-fake-classpath
"Retrieve Boot's fake classpath.
When using Boot, fake.class.path contains the original directories with source
files, which makes it way more useful than the real classpath.
See https://github.com/boot-clj/boot/issues/249 for details."
[]
(System/getProperty "fake.class.path"))
(defn boot-project?
"Check whether we're dealing with a Boot project.
We figure this by checking for the presence of Boot's fake classpath."
[]
(not (nil? (boot-fake-classpath))))
(defn url?
"Check whether the argument is an url"
[u]
(instance? java.net.URL u))
(defn directory?
"Whether the argument is a directory or an url that points to a directory"
[f]
(if (url? f)
(and (util.io/direct-url-to-file? f)
(.isDirectory (io/as-file f)))
(.isDirectory (io/as-file f))))
(defn file-ext?
"Whether the argument's path ends in one of the specified case-insensitive
file extensions"
[f & exts]
(when-let [file (if (url? f)
(when (util.io/direct-url-to-file? f)
(io/as-file f))
(io/as-file f))]
(and
;; Check for file-ness because having a specific extension implies we assume `f` is a file:
(not (directory? f))
(some (fn [ext]
(.endsWith (.. file getName toLowerCase) ext))
exts))))
(defn clj-file? [f] (file-ext? f ".clj" ".cljc"))
(defn java-file? [f] (file-ext? f ".java"))
(defn jar-file? [f] (file-ext? f ".jar"))
(defn archive? [f] (file-ext? f ".jar" ".zip"))
(defn as-sym
[x]
(cond
(symbol? x) x
(string? x) (if-let [[_ ns sym] (re-matches #"(.+)/(.+)" x)]
(symbol ns sym)
(symbol x))))
(defn namespace-sym
"Return the namespace of a fully qualified symbol if possible, as a symbol.
It leaves the symbol untouched if not."
[sym]
(if-let [ns (and sym (namespace sym))]
(as-sym ns)
sym))
(defn name-sym
"Return the name of a fully qualified symbol if possible, as a symbol.
It leaves the symbol untouched if not."
[sym]
(if-let [n (and sym (name sym))]
(as-sym n)
sym))
(defn update-vals
"Update the values of map `m` via the function `f`."
[f m]
(reduce (fn [acc [k v]]
(assoc acc k (f v)))
{} m))
(defn update-keys
"Update the keys of map `m` via the function `f`."
[f m]
(reduce (fn [acc [k v]]
(assoc acc (f k) v))
{} m))
(defn deep-merge
"Merge maps recursively. When vals are not maps, last value wins."
[& xs]
(let [f (fn f [& xs]
(if (every? map? xs)
(apply merge-with f xs)
(last xs)))]
(apply f (filter identity xs))))
(defn parse-java-version
"Parse a Java version string according to JEP 223 and return the appropriate version."
[java-ver]
(try
;; the no-opt split is because a java version string can end with
;; an optional string consisting of a hyphen followed by other characters
(let [[no-opt _] (string/split java-ver #"-")
[major minor _] (string/split no-opt #"\.")
major (Integer/parseInt major)]
(if (> major 1)
major
(Integer/parseInt (or minor "7"))))
(catch Exception _ 7)))
(def java-api-version
(parse-java-version (System/getProperty "java.version")))
;; TODO move back to analysis.cljs
(defn add-ns-macros
"Append $macros to the input symbol"
[sym]
(some-> sym
(str "$macros")
symbol))
;; TODO move back to analysis.cljs
(defn remove-macros
"Remove $macros from the input symbol"
[sym]
(some-> sym
str
(string/replace #"\$macros" "")
symbol))
(defn ns-obj?
"Return true if n is a namespace object"
[ns]
(instance? clojure.lang.Namespace ns))
;; Drop this in favor of clojure.core/requiring-resolve at some point?
(defn require-and-resolve
"Try to require the namespace and get a var for the symbol, return the
var if successful, nil if not."
{:added "0.5"}
[sym]
(when-let [ns (some-> sym namespace symbol)]
(when-not (find-ns ns)
(try
(require ns)
(catch Exception _ nil)))
(some-> sym find-var var-get)))
(def datafy?
"True if Datafy and Nav (added in Clojure 1.10) are supported,
otherwise false."
(some? (resolve 'clojure.core.protocols/datafy)))
(def tap?
"True if tap> (added in Clojure 1.10) is supported,
otherwise false."
(some? (resolve 'clojure.core/tap>)))
(defn call-when-resolved
"Return a fn that calls the fn resolved through `var-sym` with the
arguments passed to it. `var-sym` will be required and resolved
once. If requiring failed or the `var-sym` can't be resolved the
function always returns nil."
[var-sym]
(try (require (symbol (namespace var-sym)))
(catch Exception _))
(let [resolved-var (resolve var-sym)]
(fn [& args]
(when resolved-var
(apply resolved-var args)))))
(defn lazy-seq?
"Return true if `x` is a lazy seq, otherwise false."
[x]
(and (seq? x) (not (counted? x))))
(defn safe-count
"Call `clojure.core/count` on `x` if it is a collection, but not a lazy seq."
[x]
(when (and (coll? x) (not (lazy-seq? x)))
(count x)))
(defn normalize-subclass [s]
(string/replace s "$" "."))
(defn remove-type-param [s]
(-> s
(string/replace #"<.*" "")
(string/replace #"\[.*" "")))