Skip to content

Commit 7ea0a83

Browse files
committed
:map-of now works with an entry model instead of separated key model and value model. (Fixes #8)
1 parent 1748c1b commit 7ea0a83

File tree

7 files changed

+62
-73
lines changed

7 files changed

+62
-73
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Versions prior to v0.1.0 are considered experimental, their API may change.
1111

1212
- `describe` on a tuple where at least one entry has a defined :key will return
1313
a map of the entries with a key instead of a vector of all the entries.
14+
- :map-of no longer work with a key model and/or a value model. It works with an entry model insead.
15+
`describe` on a :map-of returns a vector of the description of its entries.
1416

1517
## [0.0.7] - 2020-09-20
1618

src/minimallist/core.cljc

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,8 @@
105105
(-valid? context (:model entry) (get data (:key entry)))
106106
(:optional entry)))
107107
(:entries model)))
108-
(implies (contains? model :keys)
109-
(every? (partial -valid? context (-> model :keys :model)) (keys data)))
110-
(implies (contains? model :values)
111-
(every? (partial -valid? context (-> model :values :model)) (vals data)))
108+
(implies (contains? model :entry-model)
109+
(every? (partial -valid? context (:entry-model model)) data))
112110
(implies (contains? model :condition-model)
113111
(-valid? context (:condition-model model) data)))
114112
(:sequence-of :sequence) (and (sequential? data)
@@ -218,9 +216,7 @@
218216
:desc data}
219217
:set-of (if (set? data)
220218
(let [entries (when (contains? model :elements-model)
221-
(into #{}
222-
(map (partial -describe context (:elements-model model)))
223-
data))
219+
(mapv (partial -describe context (:elements-model model)) data))
224220
valid? (and (implies (contains? model :elements-model)
225221
(every? :valid? entries))
226222
(implies (contains? model :count-model)
@@ -230,25 +226,12 @@
230226
{:valid? valid?
231227
:desc (into #{} (map :desc) entries)}))
232228
:map-of (if (map? data)
233-
(let [key-model (-> model :keys :model)
234-
values-model (-> model :values :model)
235-
entries (into {}
236-
(map (fn [[key value]]
237-
[(if key-model
238-
(-describe context key-model key)
239-
{:valid? true, :desc key})
240-
(if values-model
241-
(-describe context values-model value)
242-
{:valid? true, :desc key})]))
243-
data)
244-
valid? (and (implies (contains? model :keys)
245-
(every? :valid? (keys entries)))
246-
(implies (contains? model :values)
247-
(every? :valid? (vals entries)))
229+
(let [entries (mapv (partial -describe context (:entry-model model)) data)
230+
valid? (and (every? :valid? entries)
248231
(implies (contains? model :condition-model)
249232
(:valid? (-describe context (:condition-model model) data))))]
250233
{:valid? valid?
251-
:desc (into {} (map (fn [[k v]] [(:desc k) (:desc v)])) entries)})
234+
:desc (mapv :desc entries)})
252235
{:valid? false})
253236
:map (if (map? data)
254237
(let [entries (into {}

src/minimallist/generator.cljc

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@
8787
(contains? model :elements-model)
8888
(reduce-update :elements-model walk (conj path :elements-model)))
8989
:map-of (-> [[stack walked-bindings] model]
90-
(reduce-update-in [:keys :model] walk (conj path :keys :model))
91-
(reduce-update-in [:values :model] walk (conj path :values :model)))
90+
(reduce-update :entry-model walk (conj path :entry-model)))
9291
(:and :or
9392
:map :sequence
9493
:alt :cat) (cond-> [[stack walked-bindings] model]
@@ -144,11 +143,10 @@
144143
[model stack path]
145144
(let [distance (case (:type model)
146145
(:fn :enum) 0
147-
:map-of (let [key-distance (-> model :keys :model ::leaf-distance)
148-
value-distance (-> model :values :model ::leaf-distance)]
146+
:map-of (let [entry-distance (-> model :entry-model ::leaf-distance)]
149147
(cond
150148
(zero? (min-count-value model)) 0
151-
(and key-distance value-distance) (inc (max key-distance value-distance))))
149+
(some? entry-distance) (inc entry-distance)))
152150
(:set-of
153151
:sequence-of
154152
:repeat) (if (or (not (contains? model :elements-model))
@@ -186,11 +184,12 @@
186184
(:fn :enum) (::min-cost model 1)
187185
:map-of (let [container-cost 1
188186
min-count (min-count-value model)
189-
key-min-cost (-> model :keys :model ::min-cost)
190-
value-min-cost (-> model :values :model ::min-cost)
187+
entry-min-cost (-> model :entry-model ::min-cost
188+
; cancel the cost of the entry's vector
189+
(some-> dec))
191190
content-cost (if (zero? min-count) 0
192-
(when (and min-count key-min-cost value-min-cost)
193-
(* min-count (+ key-min-cost value-min-cost))))]
191+
(when (and min-count entry-min-cost)
192+
(* min-count entry-min-cost)))]
194193
(some-> content-cost (+ container-cost)))
195194
(:set-of
196195
:sequence-of
@@ -392,10 +391,8 @@
392391

393392
:map-of (cond->> (let [budget (max 0 (dec budget)) ; the collection itself costs 1
394393
count-model (:count-model model)
395-
keys-model (-> model :keys :model)
396-
values-model (-> model :values :model)
397-
entry-min-cost (+ (::min-cost keys-model)
398-
(::min-cost values-model))
394+
entry-model (:entry-model model)
395+
entry-min-cost (::min-cost entry-model)
399396
coll-max-size (int (/ budget entry-min-cost))
400397
coll-size-gen (if count-model
401398
(generator context count-model 0)
@@ -407,10 +404,7 @@
407404
entries-gen (gen/bind budgets-gen
408405
(fn [entry-budgets]
409406
(apply gen/tuple
410-
(mapv (fn [entry-budget]
411-
(gen/tuple
412-
(generator context keys-model entry-budget)
413-
(generator context values-model entry-budget)))
407+
(mapv (partial generator context entry-model)
414408
entry-budgets))))
415409
map-gen (gen/fmap (fn [entries]
416410
(into {} entries))

src/minimallist/helper.cljc

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,10 @@
121121
:elements-model elements-model})
122122

123123
(defn map-of
124-
"Model of a hashmap associating values of a specific model
125-
to values of another specific model."
126-
[keys-model values-model]
124+
"Model of a hashmap made of entries (2-vector) of a specific model."
125+
[entry-model]
127126
{:type :map-of
128-
:keys {:model keys-model}
129-
:values {:model values-model}})
127+
:entry-model entry-model})
130128

131129
(defn sequence-of
132130
"Model of a sequence of values, all matching a specific model."

src/minimallist/minimap.cljc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@
1616
(h/with-optional-entries [:count-model (h/ref 'model)]
1717
[:elements-model (h/ref 'model)]
1818
[:condition-model (h/ref 'model)]))]
19-
[:map-of (-> (h/map [:type (h/val :map-of)])
20-
(h/with-optional-entries [:keys (h/map [:model (h/ref 'model)])]
21-
[:values (h/map [:model (h/ref 'model)])]
22-
[:condition-model (h/ref 'model)]))]
19+
[:map-of (-> (h/map [:type (h/val :map-of)]
20+
[:entry-model (h/ref 'model)])
21+
(h/with-optional-entries [:condition-model (h/ref 'model)]))]
2322
[:map (-> (h/map [:type (h/val :map)])
2423
(h/with-optional-entries [:entries (h/vector-of (-> (h/map [:key (h/fn any?)]
2524
[:model (h/ref 'model)])

test/minimallist/core_test.cljc

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@
8989
{:a 1, :b 'bar, [1 2 3] "soleil !"}]
9090

9191
;; map, keys and values
92-
(h/map-of (h/fn keyword?)
93-
(h/fn int?))
92+
(h/map-of (h/vector (h/fn keyword?) (h/fn int?)))
9493
[{} {:a 1, :b 2}]
9594
[{:a 1, :b "2"} [[:a 1] [:b 2]] {true 1, false 2}]
9695

@@ -317,15 +316,23 @@
317316
; extra entry
318317
{:a 1, :b 2, :c 3} {:a 1, :b 2}]
319318

320-
;; map-of - :keys
321-
(h/map-of (h/fn keyword?) (h/fn any?))
322-
[{:a 1, :b 2} {:a 1, :b 2}
319+
;; map-of - entry-model
320+
(h/map-of (h/vector (h/fn keyword?) (h/fn int?)))
321+
[{:a 1, :b 2} [[:a 1] [:b 2]]
323322
{"a" 1} :invalid]
324323

325-
;; map-of - :values
326-
(h/map-of (h/fn any?) (h/fn int?))
327-
[{:a 1, "b" 2} {:a 1, "b" 2}
328-
{:a "1"} :invalid]
324+
;; map-of - real world use case
325+
(h/map-of (h/alt [:symbol (h/vector (h/fn simple-symbol?) (h/fn keyword?))]
326+
[:keys (h/vector (h/val :keys) (h/vector-of (h/fn symbol?)))]
327+
[:as (h/vector (h/val :as) (h/fn simple-symbol?))]))
328+
'[{first-name :first-name
329+
last-name :last-name
330+
:keys [foo bar]
331+
:as foobar}
332+
[[:symbol [first-name :first-name]]
333+
[:symbol [last-name :last-name]]
334+
[:keys [:keys [foo bar]]]
335+
[:as [:as foobar]]]]
329336

330337
;; sequence - :elements-model
331338
(h/sequence-of (h/fn int?))

test/minimallist/generator_test.cljc

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -220,21 +220,27 @@
220220
::mg/min-cost 1}}]
221221
::mg/min-cost 2}
222222

223-
(h/map-of (h/fn keyword?) (h/fn int?))
223+
(h/map-of (h/vector (h/fn keyword?) (h/fn int?)))
224224
{:type :map-of
225-
:keys {:model {:type :fn
226-
::mg/min-cost 1}}
227-
:values {:model {:type :fn
228-
::mg/min-cost 1}}
225+
:entry-model {:type :sequence
226+
:coll-type :vector
227+
:entries [{:model {:type :fn
228+
::mg/min-cost 1}}
229+
{:model {:type :fn
230+
::mg/min-cost 1}}]
231+
::mg/min-cost 3}
229232
::mg/min-cost 1}
230233

231-
(-> (h/map-of (h/fn keyword?) (h/fn int?))
234+
(-> (h/map-of (h/vector (h/fn keyword?) (h/fn int?)))
232235
(h/with-count (h/enum #{3 4})))
233236
{:type :map-of
234-
:keys {:model {:type :fn
235-
::mg/min-cost 1}}
236-
:values {:model {:type :fn
237-
::mg/min-cost 1}}
237+
:entry-model {:type :sequence
238+
:coll-type :vector
239+
:entries [{:model {:type :fn
240+
::mg/min-cost 1}}
241+
{:model {:type :fn
242+
::mg/min-cost 1}}]
243+
::mg/min-cost 3}
238244
:count-model {:type :enum
239245
:values #{3 4}}
240246
::mg/min-cost 7}
@@ -292,7 +298,7 @@
292298
(h/with-count (h/enum #{1 2 3 10}))
293299
(h/with-condition (h/fn (comp #{1 2 3} count))))))
294300

295-
(tcg/sample (gen (h/map-of fn-int? fn-string?)))
301+
(tcg/sample (gen (h/map-of (h/vector fn-int? fn-simple-symbol?))))
296302

297303
(tcg/sample (gen (-> (h/map [:a fn-int?])
298304
(h/with-optional-entries [:b fn-string?]))))
@@ -324,10 +330,10 @@
324330
(tcg/sample (gen (h/let ['node (h/set-of (h/ref 'node))]
325331
(h/ref 'node))))
326332

327-
(tcg/sample (gen (h/let ['node (h/map-of fn-int? (h/ref 'node))]
333+
(tcg/sample (gen (h/let ['node (h/map-of (h/vector fn-int? (h/ref 'node)))]
328334
(h/ref 'node)) 50))
329335

330-
(tcg/sample (gen (h/let ['node (h/map-of fn-keyword? (h/ref 'node))]
336+
(tcg/sample (gen (h/let ['node (h/map-of (h/vector fn-keyword? (h/ref 'node)))]
331337
(h/ref 'node)) 100) 1)
332338

333339
(tcg/sample (gen (h/map [:a fn-int?])))
@@ -372,7 +378,7 @@
372378
(is (every? (partial valid? model)
373379
(tcg/sample (gen model)))))
374380

375-
(let [model (h/map-of fn-int? fn-string?)]
381+
(let [model (h/map-of (h/vector fn-int? fn-string?))]
376382
(is (every? (partial valid? model)
377383
(tcg/sample (gen model)))))
378384

@@ -455,7 +461,7 @@
455461
(tcg/sample (gen model)))))
456462

457463
;; Budget-based limit on variable map size.
458-
(let [model (h/let ['node (h/map-of fn-int? (h/ref 'node))]
464+
(let [model (h/let ['node (h/map-of (h/vector fn-int? (h/ref 'node)))]
459465
(h/ref 'node))]
460466
(is (every? (partial valid? model)
461467
(tcg/sample (gen model)))))

0 commit comments

Comments
 (0)