Skip to content

Commit 73ab8ff

Browse files
pkpkpkdnolen
authored andcommitted
new preds, specs, and gens
1 parent 463de00 commit 73ab8ff

File tree

6 files changed

+196
-3
lines changed

6 files changed

+196
-3
lines changed

src/main/cljs/cljs/core.cljs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,23 @@
12631263
(garray/defaultCompare (.valueOf this) (.valueOf other))
12641264
(throw (js/Error. (str "Cannot compare " this " to " other))))))
12651265

1266+
(defprotocol Inst
1267+
(inst-ms* [inst]))
1268+
1269+
(extend-protocol Inst
1270+
js/Date
1271+
(inst-ms* [inst] (.getTime inst)))
1272+
1273+
(defn inst-ms
1274+
"Return the number of milliseconds since January 1, 1970, 00:00:00 GMT"
1275+
[inst]
1276+
(inst-ms* inst))
1277+
1278+
(defn ^boolean inst?
1279+
"Return true if x satisfies Inst"
1280+
[x]
1281+
(satisfies? Inst x))
1282+
12661283
(extend-type number
12671284
IEquiv
12681285
(-equiv [x o] (identical? x o)))
@@ -2064,6 +2081,10 @@ reduces them without incurring seq initialization"
20642081
"Returns true if x is the value true, false otherwise."
20652082
[x] (cljs.core/true? x))
20662083

2084+
(defn ^boolean boolean?
2085+
"Return true if x is a Boolean"
2086+
[x] (or (cljs.core/true? x) (cljs.core/false? x)))
2087+
20672088
(defn ^boolean undefined?
20682089
"Returns true if x identical to the JavaScript undefined value."
20692090
[x]
@@ -2102,6 +2123,26 @@ reduces them without incurring seq initialization"
21022123
(not (identical? n js/Infinity))
21032124
(== (js/parseFloat n) (js/parseInt n 10))))
21042125

2126+
(defn ^boolean long?
2127+
"Return true if x is an instance of goog.math.Long"
2128+
[x] (instance? goog.math.Long x))
2129+
2130+
(defn ^boolean pos-long?
2131+
"Return true if x is a positive Long"
2132+
[x] (and (instance? goog.math.Long x)
2133+
(not (.isNegative x))
2134+
(not (.isZero x))))
2135+
2136+
(defn ^boolean neg-long?
2137+
"Return true if x is a negative Long"
2138+
[x] (and (instance? goog.math.Long x)
2139+
(.isNegative x)))
2140+
2141+
(defn ^boolean nat-long?
2142+
"Return true if x is a non-negative Long"
2143+
[x] (and (instance? goog.math.Long x)
2144+
(or (not (.isNegative x)) (.isZero x))))
2145+
21052146
(defn ^boolean contains?
21062147
"Returns true if key is present in the given collection, otherwise
21072148
returns false. Note that for numerically indexed collections like
@@ -3086,6 +3127,34 @@ reduces them without incurring seq initialization"
30863127
(-namespace ^not-native x)
30873128
(throw (js/Error. (str "Doesn't support namespace: " x)))))
30883129

3130+
(defn ^boolean ident?
3131+
"Return true if x is a symbol or keyword"
3132+
[x] (or (keyword? x) (symbol? x)))
3133+
3134+
(defn ^boolean simple-ident?
3135+
"Return true if x is a symbol or keyword without a namespace"
3136+
[x] (and (ident? x) (nil? (namespace x))))
3137+
3138+
(defn ^boolean qualified-ident?
3139+
"Return true if x is a symbol or keyword with a namespace"
3140+
[x] (and (ident? x) (namespace x) true))
3141+
3142+
(defn ^boolean simple-symbol?
3143+
"Return true if x is a symbol without a namespace"
3144+
[x] (and (symbol? x) (nil? (namespace x))))
3145+
3146+
(defn ^boolean qualified-symbol?
3147+
"Return true if x is a symbol with a namespace"
3148+
[x] (and (symbol? x) (namespace x) true))
3149+
3150+
(defn ^boolean simple-keyword?
3151+
"Return true if x is a keyword without a namespace"
3152+
[x] (and (keyword? x) (nil? (namespace x))))
3153+
3154+
(defn ^boolean qualified-keyword?
3155+
"Return true if x is a keyword with a namespace"
3156+
[x] (and (keyword? x) (namespace x) true))
3157+
30893158
(defn keyword
30903159
"Returns a Keyword with the given namespace and name. Do not use :
30913160
in the keyword strings, it will be added automatically."
@@ -10090,8 +10159,11 @@ reduces them without incurring seq initialization"
1009010159
[multifn] (-dispatch-fn multifn))
1009110160

1009210161
;; UUID
10162+
(defprotocol IUUID "A marker protocol for UUIDs")
1009310163

1009410164
(deftype UUID [uuid ^:mutable __hash]
10165+
IUUID
10166+
1009510167
Object
1009610168
(toString [_] uuid)
1009710169
(equiv [this other]
@@ -10131,6 +10203,9 @@ reduces them without incurring seq initialization"
1013110203
(hex) (hex) (hex) (hex)
1013210204
(hex) (hex) (hex) (hex))))))
1013310205

10206+
(defn ^boolean uuid?
10207+
[x] (implements? IUUID x))
10208+
1013410209
;;; ExceptionInfo
1013510210

1013610211
(defn- pr-writer-ex-info [obj writer opts]

src/main/cljs/cljs/spec.cljc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,25 @@ specified, return speced vars from all namespaces."
377377
[kpred vpred]
378378
`(and (coll-of (tuple ~kpred ~vpred) {}) map?))
379379

380+
(defmacro inst-in
381+
"Returns a spec that validates insts in the range from start
382+
(inclusive) to end (exclusive)."
383+
[start end]
384+
`(let [st# (inst-ms ~start)
385+
et# (inst-ms ~end)
386+
mkdate# (fn [d#] (js/Date. d#))]
387+
(spec (and inst? #(inst-in-range? ~start ~end %))
388+
:gen (fn []
389+
(gen/fmap mkdate#
390+
(gen/large-integer* {:min st# :max et#}))))))
391+
392+
(defmacro long-in
393+
"Returns a spec that validates longs in the range from start
394+
(inclusive) to end (exclusive)."
395+
[start end]
396+
`(spec (and c/long? #(long-in-range? ~start ~end %))
397+
:gen #(gen/large-integer* {:min ~start :max (dec ~end)})))
398+
380399
(defmacro instrument
381400
"Instruments the var at v, a var or symbol, to check specs
382401
registered with fdef. Wraps the fn at v to check :args/:ret/:fn

src/main/cljs/cljs/spec.cljs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,3 +1115,17 @@
11151115
(gen/fmap
11161116
#(if (vector? init) % (into init %))
11171117
(gen/vector (gen pred))))))
1118+
1119+
(defn inst-in-range?
1120+
"Return true if inst at or after start and before end"
1121+
[start end inst]
1122+
(c/and (inst? inst)
1123+
(let [t (inst-ms inst)]
1124+
(c/and (<= (inst-ms start) t) (< t (inst-ms end))))))
1125+
1126+
(defn long-in-range?
1127+
"Return true if start <= val and val < end"
1128+
[start end val]
1129+
(c/and (long? val)
1130+
(.lessThanOrEqual (goog.math.Long.fromNumber start) val)
1131+
(.lessThan val (goog.math.Long.fromNumber end))))

src/main/cljs/cljs/spec/impl/gen.cljs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
; (throw (js/Error. (str "Var " s " is not a generator"))))))
6868

6969
(lazy-combinators hash-map list map not-empty set vector fmap elements
70-
bind choose one-of such-that tuple sample return)
70+
bind choose one-of such-that tuple sample return
71+
large-integer*)
7172

7273
(lazy-prims any any-printable boolean char char-alpha char-alphanumeric char-ascii double
7374
int keyword keyword-ns large-integer ratio simple-type simple-type-printable
@@ -80,16 +81,39 @@ gens, each of which should generate something sequential."
8081
(fmap #(apply concat %)
8182
(apply tuple gens)))
8283

84+
(defn- ^boolean qualified? [ident] (not (nil? (namespace ident))))
85+
8386
(def ^:private
8487
gen-builtins
8588
(c/delay
8689
(let [simple (simple-type-printable)]
8790
{number? (one-of [(large-integer) (double)])
8891
integer? (large-integer)
92+
long? (large-integer)
93+
pos-long? (large-integer* {:min 1})
94+
neg-long? (large-integer* {:max -1})
95+
nat-long? (large-integer* {:min 0})
8996
;float? (double)
9097
string? (string-alphanumeric)
98+
ident? (one-of [(keyword-ns) (symbol-ns)])
99+
simple-ident? (one-of [(keyword) (symbol)])
100+
qualified-ident? (such-that qualified? (one-of [(keyword-ns) (symbol-ns)]))
91101
keyword? (keyword-ns)
102+
simple-keyword? (keyword)
103+
qualified-keyword? (such-that qualified? (keyword-ns))
92104
symbol? (symbol-ns)
105+
simple-symbol? (symbol)
106+
qualified-symbol? (such-that qualified? (symbol-ns))
107+
uuid? (uuid)
108+
inst? (fmap #(js/Date. %)
109+
(large-integer))
110+
seqable? (one-of [(return nil)
111+
(list simple)
112+
(vector simple)
113+
(map simple simple)
114+
(set simple)
115+
(string-alphanumeric)])
116+
indexed? (vector simple)
93117
map? (map simple simple)
94118
vector? (vector simple)
95119
list? (list simple)

src/test/cljs/cljs/core_test.cljs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,13 +702,17 @@
702702

703703
(deftest test-booleans
704704
(testing "Testing boolean predicates"
705-
(is (= [true false true false false false]
705+
(is (= [true false true false false false true true false false]
706706
[(true? true)
707707
(true? false)
708708
(false? false)
709709
(false? true)
710710
(true? js/undefined)
711-
(false? js/undefined)]))))
711+
(false? js/undefined)
712+
(boolean? true)
713+
(boolean? false)
714+
(boolean? nil)
715+
(boolean? js/undefined)]))))
712716

713717
(deftest test-fn-with-metadata
714718
(let [f (fn [x] (* x 2))
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
(ns cljs.predicates-test
2+
(:require [cljs.test :refer-macros [deftest is]])
3+
(:import [goog.math Long]))
4+
5+
6+
(def pred-val-table
7+
(let [now (js/Date.)
8+
uuid (uuid nil)]
9+
[[identity boolean? indexed? seqable? ident? uuid? inst? simple-ident? qualified-ident? simple-symbol? qualified-symbol? simple-keyword? qualified-keyword?]
10+
[0 false false false false false false false false false false false false]
11+
[1 false false false false false false false false false false false false]
12+
[-1 false false false false false false false false false false false false]
13+
[1.0 false false false false false false false false false false false false]
14+
[true true false false false false false false false false false false false]
15+
[[] false true true false false false false false false false false false]
16+
[nil false false false false false false false false false false false false]
17+
[{} false false true false false false false false false false false false]
18+
[:foo false false false true false false true nil false false true nil]
19+
[::foo false false false true false false false true false false false true]
20+
['foo false false false true false false true nil true nil false false]
21+
['foo/bar false false false true false false false true false true false false]
22+
[uuid false false false false true false false false false false false false]
23+
[now false false false false false true false false false false false false]]))
24+
25+
(deftest test-preds
26+
(let [[preds & rows] pred-val-table]
27+
(doseq [row rows]
28+
(let [v (first row)]
29+
(dotimes [i (count row)]
30+
(is (= ((nth preds i) v) (nth row i))
31+
(pr-str (list (nth preds i) v))))))))
32+
33+
(def int-val-table
34+
(let [posint 10e10
35+
negint -10e10
36+
natl (goog.math.Long.getZero)
37+
posl (goog.math.Long.fromNumber posint)
38+
negl (goog.math.Long.fromNumber negint)]
39+
[[identity neg? pos? integer? long? neg-long? pos-long? nat-long?]
40+
[0 false false true false false false false ]
41+
[1 false true true false false false false ]
42+
[-1 true false true false false false false ]
43+
[1.0 false true true false false false false ]
44+
[-1.0 true false true false false false false ]
45+
[posint false true true false false false false ]
46+
[negint true false true false false false false ]
47+
[natl false false false true false false true ]
48+
[posl false true false true false true true ]
49+
[negl true false false true true false false ]]))
50+
51+
(deftest test-int-preds
52+
(let [[preds & rows] int-val-table]
53+
(doseq [row rows]
54+
(let [v (first row)]
55+
(dotimes [i (count row)]
56+
(is (= ((nth preds i) v) (nth row i))
57+
(pr-str (list (nth preds i) v))))))))

0 commit comments

Comments
 (0)