Make wrap watchable

This commit is contained in:
Dan Holmsand 2015-02-01 19:43:26 +01:00
parent 5798a3f056
commit 6e0e9ed564
2 changed files with 57 additions and 19 deletions

View File

@ -315,7 +315,8 @@
;;; wrap
(deftype Wrapper [^:mutable state callback ^:mutable changed]
(deftype Wrapper [^:mutable state callback ^:mutable changed
^:mutable watches]
IAtom
@ -324,10 +325,13 @@
IReset
(-reset! [this newval]
(set! changed true)
(set! state newval)
(callback newval)
state)
(let [oldval state]
(set! changed true)
(set! state newval)
(when-not (nil? watches)
(-notify-watches this oldval newval))
(callback newval)
newval))
ISwap
(-swap! [a f]
@ -349,6 +353,17 @@
(= state (.-state other))
(= callback (.-callback other))))
IWatchable
(-notify-watches [this oldval newval]
(reduce-kv (fn [_ key f]
(f key this oldval newval)
nil)
nil watches))
(-add-watch [this key f]
(set! watches (assoc watches key f)))
(-remove-watch [this key]
(set! watches (dissoc watches key)))
IPrintWithWriter
(-pr-writer [_ writer opts]
(-write writer "#<wrap: ")
@ -358,4 +373,5 @@
(defn make-wrapper [value callback-fn args]
(Wrapper. value
(util/partial-ifn. callback-fn args nil)
false))
false nil))

View File

@ -11,18 +11,6 @@
(defn running [] (rv/running))
(defn dispose [v] (rv/dispose! v))
(defn ratom-perf []
(dbg "ratom-perf")
(let [a (rv/atom {})
mid (reaction (inc @a))
res (run!
(inc @mid))]
(time (dotimes [x 100000]
(swap! a inc)))
(dispose res)))
;; (ratom-perf)
(deftest basic-cursor
(let [runs (running)
start-base (rv/atom {:a {:b {:c 0}}})
@ -351,7 +339,7 @@
(is (= runs (running)))))
(deftest atom-behaviors
(deftest cursor-atom-behaviors
(let [test-atom (atom {:a {:b {:c {:d 1}}}})
test-cursor (r/cursor test-atom [:a :b :c :d])
witness (atom nil)
@ -394,3 +382,37 @@
(is (= (:new @witness) "newer")) ;; shouldn't have changed
(is (= (running) runs))
))
(deftest wrap-atom-behaviors
(let [test-atom (atom "foo")
test-wrap (r/wrap @test-atom reset! test-atom)
witness (atom nil)]
;; per the description, reset! should return the new values
(is (= {}
(reset! test-wrap {})))
(is (= @test-wrap @test-atom))
;; per the description, swap! should return the new values
(is (= {:z [1 2 3]}
(swap! test-wrap assoc :z [1 2 3])))
(is (= @test-wrap @test-atom))
;; watches should behave like with a normal atom
(reset! test-wrap "old")
(add-watch test-wrap :w #(reset! witness
{:key %1 :ref %2 :old %3 :new %4}))
(reset! test-wrap "new") ;; this should trigger the watch function
(is (= (:key @witness) :w))
;; cursor reports that the reaction is the current atom,
;; but I guess that's ok
(is (= (:old @witness) "old"))
(is (= (:new @witness) "new"))
(is (= (:ref @witness) test-wrap))
(is (= (:new @witness) "new"))
;; can we remove the watch?
(remove-watch test-wrap :w)
(reset! test-wrap "removed")
(is (= (:new @witness) "new")) ;; shouldn't have changed
(is (= @test-wrap @test-atom))
))