Skip to content

Commit

Permalink
[Fix #43] Implement cljs version of ordered-map (#59)
Browse files Browse the repository at this point in the history
- Add deps.edn for use with `:git/url`
- Add cljs tests for map, make reader cross-platform

- Change the map-test namespace to `cljc`, several sections are still marked as
clj-only, because they rely on eval, hashCode, compact, or transient-map. I made
some adjustments to the cljs implementation in the process to make it better
match the clj version.
  • Loading branch information
plexus committed Sep 21, 2021
1 parent 1204452 commit caec8d9
Show file tree
Hide file tree
Showing 10 changed files with 351 additions and 105 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Expand Up @@ -5,3 +5,12 @@ pom.xml.asc
target
.lein*
docs
tests.edn
.cljs_node_repl
.cpcache
.dir-locals.el
.nrepl-port
node_modules
out
package-lock.json
package.json
5 changes: 5 additions & 0 deletions bin/kaocha
@@ -0,0 +1,5 @@
#!/usr/bin/env bash

[ -d node_modules/ws ] || npm install ws

clojure -A:test -M -m kaocha.runner "$@"
7 changes: 7 additions & 0 deletions deps.edn
@@ -0,0 +1,7 @@
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.10.3"}}
:aliases
{:test {:extra-paths ["test"]
:extra-deps {lambdaisland/kaocha {:mvn/version "RELEASE"}
lambdaisland/kaocha-cljs {:mvn/version "RELEASE"}
org.clojure/clojurescript {:mvn/version "RELEASE"}}}}}
2 changes: 0 additions & 2 deletions src/data_readers.clj

This file was deleted.

2 changes: 2 additions & 0 deletions src/data_readers.cljc
@@ -0,0 +1,2 @@
{ordered/set flatland.ordered.set/into-ordered-set
ordered/map flatland.ordered.map/ordered-map-reader}
5 changes: 5 additions & 0 deletions src/flatland/ordered/map.clj
Expand Up @@ -206,3 +206,8 @@ assoc'ed for the first time. Supports transient."
(defmethod print-method OrderedMap [o ^java.io.Writer w]
(.write w "#ordered/map ")
(print-method (seq o) w))

(defn ordered-map-reader [coll]
(if (some-> (resolve 'cljs.env/*compiler*) deref)
`(ordered-map ~(vec coll))
(ordered-map coll)))
202 changes: 202 additions & 0 deletions src/flatland/ordered/map.cljs
@@ -0,0 +1,202 @@
(ns flatland.ordered.map)

(declare equiv-impl)

(defn print-ordered-map [writer kvs ks opts]
(pr-sequential-writer
writer
(fn [k w opts]
(-write w \[)
(-write w (pr-str k))
(-write w \space)
(-write w (pr-str (get kvs k)))
(-write w \]))
"(" " " ")"
opts
ks))

(deftype OrderedMap [kvs ks]
Object
(toString [this] (pr-str* this))
(equiv [this that] (equiv-impl kvs that))

;; js/map interface
(keys [this] (es6-iterator ks))
(entries [this] (es6-entries-iterator (seq kvs)))
(values [this] (es6-iterator (vals kvs)))
(has [this k] (not (nil? (.get kvs k))))
(get [this k] (.get kvs k))
(forEach [this f]
(doseq [k ks]
(f k (get kvs k) this)))
(forEach [this f use-as-this]
(doseq [k ks]
(.call f use-as-this k (get kvs k) this)))

;; js fallbacks
(key_set [this] (to-array (keys kvs)))
(entry_set [this] (to-array (map to-array kvs)))
(value_set [this] (to-array (map val kvs)))

ICloneable
(-clone [_] (OrderedMap. kvs ks))

;; IIterable
;; (-iterator [_] )

IWithMeta
(-with-meta [this new-meta]
(if (identical? (meta kvs) new-meta)
this
(OrderedMap. (with-meta kvs new-meta) ks)))

IMeta
(-meta [this] (meta kvs))

ICollection
(-conj [coll entry]
(if (vector? entry)
(OrderedMap. (conj kvs entry) (if (contains? kvs (-nth entry 0))
ks
(conj ks (-nth entry 0))))
(OrderedMap. (conj kvs entry) (into ks
(comp (map #(-nth % 0))
(remove #(contains? kvs %)))
entry))))

IEmptyableCollection
(-empty [this]
(if (seq ks)
(OrderedMap. (-empty kvs) [])
this))

IEquiv
(-equiv [this that] (equiv-impl kvs that))

IHash
(-hash [_] (hash kvs))

ISeqable
(-seq [this]
(when (seq ks)
(map #(-find kvs %) ks)))

IReversible
(-rseq [this]
(when (seq ks)
(map #(-find kvs %) (rseq ks))))

ICounted
(-count [this] (count kvs))

ILookup
(-lookup [this attr] (-lookup kvs attr))
(-lookup [this attr not-found] (-lookup kvs attr not-found))

IAssociative
(-assoc [coll k v]
(OrderedMap. (assoc kvs k v) (if (contains? kvs k)
ks
(conj ks k))))
(-contains-key? [this k]
(contains? kvs k))

IFind
(-find [this k]
(-find kvs k))

IMap
(-dissoc [this k]
(if (contains? kvs k)
(OrderedMap. (dissoc kvs k) (into [] (remove #{k}) ks))
this))

IKVReduce
(-kv-reduce [coll f init]
(reduce
(fn [acc k]
(f acc k (get kvs k)))
init
ks))

IFn
(-invoke [this k] (kvs k))
(-invoke [this k not-found] (kvs k not-found))

IPrintWithWriter
(-pr-writer [_ writer opts]
(-write writer "#ordered/map ")
(print-ordered-map writer kvs ks opts)))

(defn equiv-impl [kvs that]
(= kvs (if (instance? OrderedMap that)
(.-kvs that)
that)))

(def ^:private empty-ordered-map (OrderedMap. {} []))

(defn ordered-map
([]
empty-ordered-map)
([coll]
(into empty-ordered-map coll))
([k v & kvs]
(apply assoc empty-ordered-map k v kvs)))

(comment
(ordered-map :foo 123 :bar 456)
;; => #ordered/map [:foo 123, :bar 456]

(conj (ordered-map :foo 123 :bar 456) [:baz 123])
;; => #ordered/map [:foo 123, :bar 456, :baz 123]

(assoc (ordered-map :foo 123 :bar 456)
:baz 123
:baq 999)
;; => #ordered/map [:foo 123, :bar 456, :baz 123, :baq 999]

(merge (ordered-map :foo 123 :bar 456)
{:baz 123
:baq 999})
;; => #ordered/map [:foo 123, :bar 456, :baz 123, :baq 999]

(= (ordered-map :foo 123 :bar 456 :baz 123)
{:foo 123 :bar 456 :baz 123})
;; => true

(= {:foo 123 :bar 456 :baz 123}
(ordered-map :foo 123 :bar 456 :baz 123))
;; => true

(map? (ordered-map :foo 123 :bar 456 :baz 123))
;; => true

(empty (ordered-map :foo 123 :bar 456 :baz 123))
;; => #ordered/map []

(ordered-map)
;; => #ordered/map []

(seq (ordered-map))
;; => nil

(reduce conj [] (ordered-map :foo 123 :bar 456 :baz 123))
;; => [[:foo 123] [:bar 456] [:baz 123]]

(keys (ordered-map :foo 123 :bar 456 :baz 123))
;; => (:foo :bar :baz)

(vals (ordered-map :foo 123 :bar 456 :baz 789))
;; => (123 456 789)

(meta (with-meta (ordered-map) {:foo :bar}))
;; => {:foo :bar}

(-> (ordered-map)
(assoc-in [:foo :bar] 1)
(assoc-in [:foo :baz] 2))

(into (ordered-map) [[:foo 1] [:bar 2] [:foo 3]])
;; #ordered/map [:foo 3, :bar 2]

)

0 comments on commit caec8d9

Please sign in to comment.