mirror of https://github.com/status-im/reagent.git
Merge branch 'with-let'
This commit is contained in:
commit
be1dfaeba7
|
@ -29,10 +29,23 @@
|
||||||
[:input {:value @val
|
[:input {:value @val
|
||||||
:on-change #(reset! val (.-target.value %))}]])
|
:on-change #(reset! val (.-target.value %))}]])
|
||||||
|
|
||||||
|
(defn name-part [key]
|
||||||
|
(get-in @person [:name key]))
|
||||||
|
|
||||||
|
(def track reagent.ratom/track)
|
||||||
|
|
||||||
|
(defn foo [])
|
||||||
|
|
||||||
(defn name-edit [n]
|
(defn name-edit [n]
|
||||||
(let [{:keys [first-name last-name]} @n]
|
(let [{:keys [first-name last-name]} @n]
|
||||||
[:div
|
[:div
|
||||||
[:p "I'm editing " first-name " " last-name "."]
|
[:p "I'm editing " first-name " " last-name "."]
|
||||||
|
[:p "I'm editing " @(track name-part :first-name) " "
|
||||||
|
@(track name-part :last-name) "."]
|
||||||
|
[:p "I'm editing " @(track name-part :first-name) " "
|
||||||
|
@(track name-part :last-name) "."]
|
||||||
|
[:p "I'm editing " @(track name-part :first-name) " "
|
||||||
|
@(track name-part :last-name) "."]
|
||||||
|
|
||||||
[input "First name: " (r/wrap first-name
|
[input "First name: " (r/wrap first-name
|
||||||
swap! n assoc :first-name)]
|
swap! n assoc :first-name)]
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
{:compiler {:optimizations :advanced
|
{:compiler {:optimizations :advanced
|
||||||
:elide-asserts true
|
:elide-asserts true
|
||||||
:pretty-print false
|
:pretty-print false
|
||||||
|
;; :pseudo-names true
|
||||||
:output-dir "target/client"}}}}}]
|
:output-dir "target/client"}}}}}]
|
||||||
|
|
||||||
:prod-test [:test :prod]
|
:prod-test [:test :prod]
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
(ns reagent.core
|
||||||
|
(:require [reagent.ratom :as ra]))
|
||||||
|
|
||||||
|
(defmacro with-let [bindings & body]
|
||||||
|
`(ra/with-let ~bindings ~@body))
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
(ns reagent.core
|
(ns reagent.core
|
||||||
|
(:require-macros [reagent.core])
|
||||||
(:refer-clojure :exclude [partial atom flush])
|
(:refer-clojure :exclude [partial atom flush])
|
||||||
(:require [cljsjs.react]
|
(:require [cljsjs.react]
|
||||||
[reagent.impl.template :as tmpl]
|
[reagent.impl.template :as tmpl]
|
||||||
|
@ -221,6 +221,19 @@ re-rendered."
|
||||||
([x] (ratom/atom x))
|
([x] (ratom/atom x))
|
||||||
([x & rest] (apply ratom/atom x rest)))
|
([x & rest] (apply ratom/atom x rest)))
|
||||||
|
|
||||||
|
(defn track
|
||||||
|
[f & args]
|
||||||
|
{:pre [(ifn? f)]}
|
||||||
|
(ratom/make-track f args))
|
||||||
|
|
||||||
|
(defn track!
|
||||||
|
[f & args]
|
||||||
|
{:pre [(ifn? f)]}
|
||||||
|
(ratom/make-track! f args))
|
||||||
|
|
||||||
|
(defn dispose!
|
||||||
|
[x]
|
||||||
|
(ratom/dispose! x))
|
||||||
|
|
||||||
(defn wrap
|
(defn wrap
|
||||||
"Provide a combination of value and callback, that looks like an atom.
|
"Provide a combination of value and callback, that looks like an atom.
|
||||||
|
@ -277,6 +290,27 @@ another cursor) these cursors are equivalent:
|
||||||
|
|
||||||
;; Utilities
|
;; Utilities
|
||||||
|
|
||||||
|
(defn rswap!
|
||||||
|
"Swaps the value of a to be (apply f current-value-of-atom args).
|
||||||
|
|
||||||
|
rswap! works like swap!, except that recursive calls to rswap! on
|
||||||
|
the same atom are allowed – and it always returns nil."
|
||||||
|
[a f & args]
|
||||||
|
{:pre [(satisfies? IAtom a)
|
||||||
|
(ifn? f)]}
|
||||||
|
(if a.rswapping
|
||||||
|
(-> (or a.rswapfs (set! a.rswapfs (array)))
|
||||||
|
(.push #(apply f % args)))
|
||||||
|
(do (set! a.rswapping true)
|
||||||
|
(try (swap! a (fn [state]
|
||||||
|
(loop [s (apply f state args)]
|
||||||
|
(if-some [sf (some-> a.rswapfs .shift)]
|
||||||
|
(recur (sf s))
|
||||||
|
s))))
|
||||||
|
(finally
|
||||||
|
(set! a.rswapping false)))))
|
||||||
|
nil)
|
||||||
|
|
||||||
(defn next-tick
|
(defn next-tick
|
||||||
"Run f using requestAnimationFrame or equivalent."
|
"Run f using requestAnimationFrame or equivalent."
|
||||||
[f]
|
[f]
|
||||||
|
|
|
@ -37,7 +37,10 @@
|
||||||
(dotimes [i (alength a)]
|
(dotimes [i (alength a)]
|
||||||
(let [c (aget a i)]
|
(let [c (aget a i)]
|
||||||
(when (.' c :cljsIsDirty)
|
(when (.' c :cljsIsDirty)
|
||||||
(.' c forceUpdate)))))
|
(let [a (.' c :cljsRatom)]
|
||||||
|
(if (ratom/-check-clean a)
|
||||||
|
(.! c :cljsIsDirty false)
|
||||||
|
(.' c forceUpdate)))))))
|
||||||
|
|
||||||
(defn run-funs [a]
|
(defn run-funs [a]
|
||||||
(dotimes [i (alength a)]
|
(dotimes [i (alength a)]
|
||||||
|
@ -56,14 +59,17 @@
|
||||||
(set! scheduled? true)
|
(set! scheduled? true)
|
||||||
(next-tick #(.run-queue this))))
|
(next-tick #(.run-queue this))))
|
||||||
(run-queue [_]
|
(run-queue [_]
|
||||||
(let [q queue aq after-render]
|
(ratom/flush!)
|
||||||
|
(let [q queue
|
||||||
|
aq after-render]
|
||||||
(set! queue (array))
|
(set! queue (array))
|
||||||
(set! after-render (array))
|
(set! after-render (array))
|
||||||
(set! scheduled? false)
|
(set! scheduled? false)
|
||||||
(run-queue q)
|
(run-queue q)
|
||||||
(run-funs aq))))
|
(run-funs aq))))
|
||||||
|
|
||||||
(def render-queue (RenderQueue. (array) false (array)))
|
(defonce render-queue (RenderQueue. (array) false (array)))
|
||||||
|
(set! ratom/render-queue render-queue)
|
||||||
|
|
||||||
(defn flush []
|
(defn flush []
|
||||||
(.run-queue render-queue))
|
(.run-queue render-queue))
|
||||||
|
@ -98,7 +104,8 @@
|
||||||
(.! c :cljsRatom
|
(.! c :cljsRatom
|
||||||
(ratom/make-reaction run
|
(ratom/make-reaction run
|
||||||
:auto-run #(queue-render c)
|
:auto-run #(queue-render c)
|
||||||
:derefed derefed)))
|
:capture derefed
|
||||||
|
:no-cache true)))
|
||||||
res)
|
res)
|
||||||
(ratom/run rat))))
|
(ratom/run rat))))
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,42 @@
|
||||||
:auto-run true)]
|
:auto-run true)]
|
||||||
(deref co#)
|
(deref co#)
|
||||||
co#))
|
co#))
|
||||||
|
|
||||||
|
(defmacro with-let [bindings & body]
|
||||||
|
(assert (vector? bindings))
|
||||||
|
(let [v (gensym "bind-v")
|
||||||
|
bs (->> bindings
|
||||||
|
(map-indexed (fn [i x]
|
||||||
|
(if (even? i)
|
||||||
|
x
|
||||||
|
(let [pos (quot i 2)]
|
||||||
|
`(if (> (alength ~v) ~pos)
|
||||||
|
(aget ~v ~pos)
|
||||||
|
(aset ~v ~pos ~x))))))
|
||||||
|
vec)
|
||||||
|
[forms destroy] (let [fin (last body)]
|
||||||
|
(if (and (list? fin)
|
||||||
|
(= 'finally (first fin)))
|
||||||
|
[(butlast body) `(fn [] ~@(rest fin))]
|
||||||
|
[body nil]))
|
||||||
|
destroy-obj (when destroy
|
||||||
|
`(cljs.core/js-obj))
|
||||||
|
asserting (if *assert* true false)]
|
||||||
|
`(let [destroy-obj# ~destroy-obj
|
||||||
|
~v (reagent.ratom/get-cached-values (quote ~v) destroy-obj#)]
|
||||||
|
(when ~asserting
|
||||||
|
(when-some [c# reagent.ratom/*ratom-context*]
|
||||||
|
(when (== (.-ratomGeneration c#)
|
||||||
|
(.-generation ~v))
|
||||||
|
(js/console.error
|
||||||
|
"The same with-let is being used more than once in the
|
||||||
|
same reactive context."))
|
||||||
|
(set! (.-generation ~v) (.-ratomGeneration c#))))
|
||||||
|
(let ~bs
|
||||||
|
(let [destroy# ~destroy
|
||||||
|
res# (do ~@forms)]
|
||||||
|
(when-not (nil? destroy#)
|
||||||
|
(if (reagent.ratom/reactive?)
|
||||||
|
(set! (.-destroy destroy-obj#) destroy#)
|
||||||
|
(destroy#)))
|
||||||
|
res#)))))
|
||||||
|
|
|
@ -5,19 +5,34 @@
|
||||||
[reagent.debug :refer-macros [dbg log warn dev?]]))
|
[reagent.debug :refer-macros [dbg log warn dev?]]))
|
||||||
|
|
||||||
(declare ^:dynamic *ratom-context*)
|
(declare ^:dynamic *ratom-context*)
|
||||||
|
(defonce cached-reactions {})
|
||||||
|
|
||||||
(defonce debug false)
|
(defn ^boolean reactive? []
|
||||||
|
(some? *ratom-context*))
|
||||||
|
|
||||||
|
(defonce ^boolean debug false)
|
||||||
|
(defonce ^boolean silent false)
|
||||||
|
(defonce generation 0)
|
||||||
|
|
||||||
(defonce -running (clojure.core/atom 0))
|
(defonce -running (clojure.core/atom 0))
|
||||||
|
|
||||||
(defn running [] @-running)
|
(defn running []
|
||||||
|
(+ @-running
|
||||||
|
(count cached-reactions)))
|
||||||
|
|
||||||
(defn capture-derefed [f obj]
|
(defn capture-derefed [f obj]
|
||||||
(set! (.-cljsCaptured obj) nil)
|
(set! (.-cljsCaptured obj) nil)
|
||||||
|
(when (dev?)
|
||||||
|
(set! (.-ratomGeneration obj)
|
||||||
|
(set! generation (inc generation))))
|
||||||
(binding [*ratom-context* obj]
|
(binding [*ratom-context* obj]
|
||||||
(f)))
|
(f)))
|
||||||
|
|
||||||
(defn captured [obj]
|
(defn captured [obj]
|
||||||
|
(when (some? (.-cljsCaptured obj))
|
||||||
|
obj))
|
||||||
|
|
||||||
|
(defn- -captured [obj]
|
||||||
(let [c (.-cljsCaptured obj)]
|
(let [c (.-cljsCaptured obj)]
|
||||||
(set! (.-cljsCaptured obj) nil)
|
(set! (.-cljsCaptured obj) nil)
|
||||||
c))
|
c))
|
||||||
|
@ -30,6 +45,11 @@
|
||||||
(conj (if (nil? captured) #{} captured)
|
(conj (if (nil? captured) #{} captured)
|
||||||
derefable))))))
|
derefable))))))
|
||||||
|
|
||||||
|
(defn- check-watches [old new]
|
||||||
|
(when debug
|
||||||
|
(swap! -running + (- (count new) (count old))))
|
||||||
|
new)
|
||||||
|
|
||||||
|
|
||||||
;;; Atom
|
;;; Atom
|
||||||
|
|
||||||
|
@ -83,9 +103,9 @@
|
||||||
nil)
|
nil)
|
||||||
nil watches))
|
nil watches))
|
||||||
(-add-watch [this key f]
|
(-add-watch [this key f]
|
||||||
(set! watches (assoc watches key f)))
|
(set! watches (check-watches watches (assoc watches key f))))
|
||||||
(-remove-watch [this key]
|
(-remove-watch [this key]
|
||||||
(set! watches (dissoc watches key)))
|
(set! watches (check-watches watches (dissoc watches key))))
|
||||||
|
|
||||||
IHash
|
IHash
|
||||||
(-hash [this] (goog/getUid this)))
|
(-hash [this] (goog/getUid this)))
|
||||||
|
@ -97,11 +117,74 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; cursor
|
;;; track
|
||||||
|
|
||||||
(declare make-reaction)
|
(declare make-reaction)
|
||||||
|
|
||||||
(deftype RCursor [ratom path ^:mutable reaction]
|
(defn- cached-reaction [f key obj destroy]
|
||||||
|
(if-some [r (get cached-reactions key)]
|
||||||
|
(-deref r)
|
||||||
|
(if (some? *ratom-context*)
|
||||||
|
(let [r (make-reaction
|
||||||
|
f :on-dispose (fn []
|
||||||
|
(set! cached-reactions
|
||||||
|
(dissoc cached-reactions key))
|
||||||
|
(when (some? obj)
|
||||||
|
(set! (.-reaction obj) nil))
|
||||||
|
(when (some-> destroy .-destroy some?)
|
||||||
|
(.destroy destroy))))
|
||||||
|
v (-deref r)]
|
||||||
|
(set! cached-reactions (assoc cached-reactions key r))
|
||||||
|
(when (some? obj)
|
||||||
|
(set! (.-reaction obj) r))
|
||||||
|
v)
|
||||||
|
(f))))
|
||||||
|
|
||||||
|
(deftype Track [f key ^:mutable reaction]
|
||||||
|
IReactiveAtom
|
||||||
|
|
||||||
|
IDeref
|
||||||
|
(-deref [this]
|
||||||
|
(if-some [r reaction]
|
||||||
|
(-deref r)
|
||||||
|
(cached-reaction f key this nil)))
|
||||||
|
|
||||||
|
IEquiv
|
||||||
|
(-equiv [o other]
|
||||||
|
(and (instance? Track other)
|
||||||
|
(= key (.-key other))))
|
||||||
|
|
||||||
|
IHash
|
||||||
|
(-hash [this] (hash key))
|
||||||
|
|
||||||
|
IPrintWithWriter
|
||||||
|
(-pr-writer [a writer opts]
|
||||||
|
(-write writer (str "#<Track: " key " "))
|
||||||
|
(binding [*ratom-context* nil]
|
||||||
|
(pr-writer (-deref a) writer opts))
|
||||||
|
(-write writer ">")))
|
||||||
|
|
||||||
|
(defn make-track [f args]
|
||||||
|
(Track. #(apply f args) [f args] nil))
|
||||||
|
|
||||||
|
(defn make-track! [f args]
|
||||||
|
(let [r (make-reaction #(-deref (make-track f args))
|
||||||
|
:auto-run :async)]
|
||||||
|
@r
|
||||||
|
r))
|
||||||
|
|
||||||
|
(defn track [f & args]
|
||||||
|
{:pre [(ifn? f)]}
|
||||||
|
(make-track f args))
|
||||||
|
|
||||||
|
(defn track! [f & args]
|
||||||
|
{:pre [(ifn? f)]}
|
||||||
|
(make-track! f args))
|
||||||
|
|
||||||
|
;;; cursor
|
||||||
|
|
||||||
|
(deftype RCursor [ratom path ^:mutable reaction
|
||||||
|
^:mutable state ^:mutable watches]
|
||||||
IAtom
|
IAtom
|
||||||
IReactiveAtom
|
IReactiveAtom
|
||||||
|
|
||||||
|
@ -112,39 +195,48 @@
|
||||||
(= ratom (.-ratom other))))
|
(= ratom (.-ratom other))))
|
||||||
|
|
||||||
Object
|
Object
|
||||||
(_reaction [this]
|
|
||||||
(if (nil? reaction)
|
|
||||||
(set! reaction
|
|
||||||
(if (satisfies? IDeref ratom)
|
|
||||||
(make-reaction #(get-in @ratom path)
|
|
||||||
:on-set (if (= path [])
|
|
||||||
#(reset! ratom %2)
|
|
||||||
#(swap! ratom assoc-in path %2)))
|
|
||||||
(make-reaction #(ratom path)
|
|
||||||
:on-set #(ratom path %2))))
|
|
||||||
reaction))
|
|
||||||
|
|
||||||
(_peek [this]
|
(_peek [this]
|
||||||
(binding [*ratom-context* nil]
|
(binding [*ratom-context* nil]
|
||||||
(-deref (._reaction this))))
|
(-deref this)))
|
||||||
|
|
||||||
|
(_set-state [this oldstate newstate]
|
||||||
|
(when-not (identical? oldstate newstate)
|
||||||
|
(set! state newstate)
|
||||||
|
(when (some? watches)
|
||||||
|
(-notify-watches this oldstate newstate))))
|
||||||
|
|
||||||
IDeref
|
IDeref
|
||||||
(-deref [this]
|
(-deref [this]
|
||||||
(-deref (._reaction this)))
|
(let [oldstate state
|
||||||
|
newstate (if-some [r reaction]
|
||||||
|
(-deref r)
|
||||||
|
(let [f (if (satisfies? IDeref ratom)
|
||||||
|
#(get-in @ratom path)
|
||||||
|
#(ratom path))]
|
||||||
|
(cached-reaction f [::cursor ratom path] this nil)))]
|
||||||
|
(._set-state this oldstate newstate)
|
||||||
|
newstate))
|
||||||
|
|
||||||
IReset
|
IReset
|
||||||
(-reset! [this new-value]
|
(-reset! [this new-value]
|
||||||
(-reset! (._reaction this) new-value))
|
(let [oldstate state]
|
||||||
|
(._set-state this oldstate new-value)
|
||||||
|
(if (satisfies? IDeref ratom)
|
||||||
|
(if (= path [])
|
||||||
|
(reset! ratom new-value)
|
||||||
|
(swap! ratom assoc-in path new-value))
|
||||||
|
(ratom path new-value))
|
||||||
|
new-value))
|
||||||
|
|
||||||
ISwap
|
ISwap
|
||||||
(-swap! [a f]
|
(-swap! [a f]
|
||||||
(-swap! (._reaction a) f))
|
(-reset! a (f (._peek a))))
|
||||||
(-swap! [a f x]
|
(-swap! [a f x]
|
||||||
(-swap! (._reaction a) f x))
|
(-reset! a (f (._peek a) x)))
|
||||||
(-swap! [a f x y]
|
(-swap! [a f x y]
|
||||||
(-swap! (._reaction a) f x y))
|
(-reset! a (f (._peek a) x y)))
|
||||||
(-swap! [a f x y more]
|
(-swap! [a f x y more]
|
||||||
(-swap! (._reaction a) f x y more))
|
(-reset! a (apply f (._peek a) x y more)))
|
||||||
|
|
||||||
IPrintWithWriter
|
IPrintWithWriter
|
||||||
(-pr-writer [a writer opts]
|
(-pr-writer [a writer opts]
|
||||||
|
@ -154,36 +246,46 @@
|
||||||
|
|
||||||
IWatchable
|
IWatchable
|
||||||
(-notify-watches [this oldval newval]
|
(-notify-watches [this oldval newval]
|
||||||
(-notify-watches (._reaction this) oldval newval))
|
(doseq [[key f] watches]
|
||||||
|
(f key this oldval newval)))
|
||||||
(-add-watch [this key f]
|
(-add-watch [this key f]
|
||||||
(-add-watch (._reaction this) key f))
|
(set! watches (assoc watches key f)))
|
||||||
(-remove-watch [this key]
|
(-remove-watch [this key]
|
||||||
(-remove-watch (._reaction this) key))
|
(set! watches (dissoc watches key)))
|
||||||
|
|
||||||
IHash
|
IHash
|
||||||
(-hash [this] (hash [ratom path])))
|
(-hash [this] (hash [ratom path])))
|
||||||
|
|
||||||
(defn cursor
|
(defn cursor
|
||||||
[src path]
|
[src path]
|
||||||
(if (satisfies? IDeref path)
|
|
||||||
(do
|
|
||||||
(warn "Calling cursor with an atom as the second arg is "
|
|
||||||
"deprecated, in (cursor "
|
|
||||||
src " " (pr-str path) ")")
|
|
||||||
(assert (satisfies? IReactiveAtom path)
|
|
||||||
(str "src must be a reactive atom, not "
|
|
||||||
(pr-str path)))
|
|
||||||
(RCursor. path src nil))
|
|
||||||
(do
|
|
||||||
(assert (or (satisfies? IReactiveAtom src)
|
(assert (or (satisfies? IReactiveAtom src)
|
||||||
(and (ifn? src)
|
(and (ifn? src)
|
||||||
(not (vector? src))))
|
(not (vector? src))))
|
||||||
(str "src must be a reactive atom or a function, not "
|
(str "src must be a reactive atom or a function, not "
|
||||||
(pr-str src)))
|
(pr-str src)))
|
||||||
(RCursor. src path nil))))
|
(RCursor. src path nil nil nil))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;;; with-let support
|
||||||
|
|
||||||
|
(def reaction-counter 0)
|
||||||
|
|
||||||
|
(defn reaction-key []
|
||||||
|
(when-some [c *ratom-context*]
|
||||||
|
(if-some [k (.-reaction-id c)]
|
||||||
|
k
|
||||||
|
(->> reaction-counter inc
|
||||||
|
(set! reaction-counter)
|
||||||
|
(set! (.-reaction-id c))))))
|
||||||
|
|
||||||
|
(defn get-cached-values [key destroy]
|
||||||
|
(if-some [k (reaction-key)]
|
||||||
|
(cached-reaction #(array)
|
||||||
|
[k key] nil destroy)
|
||||||
|
(array)))
|
||||||
|
|
||||||
|
|
||||||
;;;; reaction
|
;;;; reaction
|
||||||
|
|
||||||
(defprotocol IDisposable
|
(defprotocol IDisposable
|
||||||
|
@ -193,13 +295,18 @@
|
||||||
(run [this]))
|
(run [this]))
|
||||||
|
|
||||||
(defprotocol IComputedImpl
|
(defprotocol IComputedImpl
|
||||||
(-update-watching [this derefed])
|
(-peek-at [this])
|
||||||
(-handle-change [k sender oldval newval])
|
(^boolean -check-clean [this])
|
||||||
(-peek-at [this]))
|
(-handle-change [this sender oldval newval])
|
||||||
|
(-update-watching [this derefed]))
|
||||||
|
|
||||||
(deftype Reaction [f ^:mutable state ^:mutable dirty? ^:mutable active?
|
(def ^:const clean 0)
|
||||||
|
(def ^:const maybe-dirty 1)
|
||||||
|
(def ^:const dirty 2)
|
||||||
|
|
||||||
|
(deftype Reaction [f ^:mutable state ^:mutable ^number dirtyness
|
||||||
^:mutable watching ^:mutable watches
|
^:mutable watching ^:mutable watches
|
||||||
auto-run on-set on-dispose]
|
^:mutable auto-run on-set on-dispose ^boolean nocache?]
|
||||||
IAtom
|
IAtom
|
||||||
IReactiveAtom
|
IReactiveAtom
|
||||||
|
|
||||||
|
@ -208,24 +315,24 @@
|
||||||
(reduce-kv (fn [_ key f]
|
(reduce-kv (fn [_ key f]
|
||||||
(f key this oldval newval)
|
(f key this oldval newval)
|
||||||
nil)
|
nil)
|
||||||
nil watches))
|
nil watches)
|
||||||
|
nil)
|
||||||
|
|
||||||
(-add-watch [this k wf]
|
(-add-watch [_ key f]
|
||||||
(set! watches (assoc watches k wf)))
|
(set! watches (check-watches watches (assoc watches key f))))
|
||||||
|
|
||||||
(-remove-watch [this k]
|
(-remove-watch [this key]
|
||||||
(set! watches (dissoc watches k))
|
(set! watches (check-watches watches (dissoc watches key)))
|
||||||
(when (and (empty? watches)
|
(when (and (empty? watches)
|
||||||
(not auto-run))
|
(nil? auto-run))
|
||||||
(dispose! this)))
|
(dispose! this)))
|
||||||
|
|
||||||
IReset
|
IReset
|
||||||
(-reset! [a newval]
|
(-reset! [a newval]
|
||||||
|
(assert (ifn? on-set) "Reaction is read only.")
|
||||||
(let [oldval state]
|
(let [oldval state]
|
||||||
(set! state newval)
|
(set! state newval)
|
||||||
(when on-set
|
(on-set oldval newval)
|
||||||
(set! dirty? true)
|
|
||||||
(on-set oldval newval))
|
|
||||||
(-notify-watches a oldval newval)
|
(-notify-watches a oldval newval)
|
||||||
newval))
|
newval))
|
||||||
|
|
||||||
|
@ -240,56 +347,102 @@
|
||||||
(-reset! a (apply f (-peek-at a) x y more)))
|
(-reset! a (apply f (-peek-at a) x y more)))
|
||||||
|
|
||||||
IComputedImpl
|
IComputedImpl
|
||||||
|
(-peek-at [this]
|
||||||
|
(if (== dirtyness clean)
|
||||||
|
state
|
||||||
|
(binding [*ratom-context* nil]
|
||||||
|
(-deref this))))
|
||||||
|
|
||||||
|
(-check-clean [this]
|
||||||
|
(when (== dirtyness maybe-dirty)
|
||||||
|
(let [ar auto-run]
|
||||||
|
(set! auto-run nil)
|
||||||
|
(doseq [w watching]
|
||||||
|
(when (and (instance? Reaction w)
|
||||||
|
(not (-check-clean w)))
|
||||||
|
(._try-run this w)))
|
||||||
|
(set! auto-run ar))
|
||||||
|
(when (== dirtyness maybe-dirty)
|
||||||
|
(set! dirtyness clean)))
|
||||||
|
(== dirtyness clean))
|
||||||
|
|
||||||
(-handle-change [this sender oldval newval]
|
(-handle-change [this sender oldval newval]
|
||||||
(when (and active? (not (identical? oldval newval)))
|
(let [old-dirty dirtyness
|
||||||
(set! dirty? true)
|
new-dirty (if (identical? oldval newval)
|
||||||
((or auto-run run) this)))
|
(if (instance? Reaction sender)
|
||||||
|
maybe-dirty clean)
|
||||||
|
dirty)]
|
||||||
|
(when (> new-dirty old-dirty)
|
||||||
|
(set! dirtyness new-dirty)
|
||||||
|
(when (== old-dirty clean)
|
||||||
|
(if-some [ar auto-run]
|
||||||
|
(when-not (and (identical? ar run)
|
||||||
|
(-check-clean this))
|
||||||
|
(ar this))
|
||||||
|
(-notify-watches this state state)))))
|
||||||
|
nil)
|
||||||
|
|
||||||
(-update-watching [this derefed]
|
(-update-watching [this derefed]
|
||||||
(doseq [w derefed]
|
(doseq [w derefed]
|
||||||
(when-not (contains? watching w)
|
(when-not (contains? watching w)
|
||||||
(add-watch w this -handle-change)))
|
(-add-watch w this -handle-change)))
|
||||||
(doseq [w watching]
|
(doseq [w watching]
|
||||||
(when-not (contains? derefed w)
|
(when-not (contains? derefed w)
|
||||||
(remove-watch w this)))
|
(-remove-watch w this)))
|
||||||
(set! watching derefed))
|
(set! watching derefed)
|
||||||
|
nil)
|
||||||
|
|
||||||
(-peek-at [this]
|
Object
|
||||||
(if-not dirty?
|
(_try-run [_ parent]
|
||||||
state
|
(try
|
||||||
(binding [*ratom-context* nil]
|
(if-some [ar (.-auto-run parent)]
|
||||||
(-deref this))))
|
(ar parent)
|
||||||
|
(run parent))
|
||||||
|
(catch :default e
|
||||||
|
;; Just log error: it will most likely pop up again at deref time.
|
||||||
|
(when-not silent
|
||||||
|
(js/console.error "Error in reaction:" e))
|
||||||
|
(set! (.-dirtyness parent) dirty)
|
||||||
|
(set! dirtyness dirty))))
|
||||||
|
|
||||||
IRunnable
|
IRunnable
|
||||||
(run [this]
|
(run [this]
|
||||||
(let [oldstate state
|
(let [oldstate state
|
||||||
res (capture-derefed f this)
|
res (capture-derefed f this)
|
||||||
derefed (captured this)]
|
derefed (-captured this)]
|
||||||
(when (not= derefed watching)
|
(when (not= derefed watching)
|
||||||
(-update-watching this derefed))
|
(-update-watching this derefed))
|
||||||
(when-not active?
|
(set! dirtyness clean)
|
||||||
(when debug (swap! -running inc))
|
(when-not nocache?
|
||||||
(set! active? true))
|
|
||||||
(set! dirty? false)
|
|
||||||
(set! state res)
|
(set! state res)
|
||||||
(-notify-watches this oldstate state)
|
;; Use = to determine equality from reactions, since
|
||||||
|
;; they are likely to produce new data structures.
|
||||||
|
(when (and (some? watches)
|
||||||
|
(not= oldstate res))
|
||||||
|
(-notify-watches this oldstate res)))
|
||||||
res))
|
res))
|
||||||
|
|
||||||
IDeref
|
IDeref
|
||||||
(-deref [this]
|
(-deref [this]
|
||||||
(if (or auto-run (some? *ratom-context*))
|
(-check-clean this)
|
||||||
|
(if (and (nil? *ratom-context*)
|
||||||
|
(nil? auto-run))
|
||||||
|
(do
|
||||||
|
(when-not (== dirtyness clean)
|
||||||
|
(let [oldstate state
|
||||||
|
newstate (f)]
|
||||||
|
(set! state newstate)
|
||||||
|
(when (and (some? watches)
|
||||||
|
(not= oldstate newstate))
|
||||||
|
(-notify-watches this oldstate newstate))))
|
||||||
|
(when (and (some? on-dispose)
|
||||||
|
(nil? watches))
|
||||||
|
(on-dispose)))
|
||||||
(do
|
(do
|
||||||
(notify-deref-watcher! this)
|
(notify-deref-watcher! this)
|
||||||
(if dirty?
|
(when-not (== dirtyness clean)
|
||||||
(run this)
|
(run this))))
|
||||||
state))
|
state)
|
||||||
(do
|
|
||||||
(when dirty?
|
|
||||||
(let [oldstate state]
|
|
||||||
(set! state (f))
|
|
||||||
(when-not (identical? oldstate state)
|
|
||||||
(-notify-watches this oldstate state))))
|
|
||||||
state)))
|
|
||||||
|
|
||||||
IDisposable
|
IDisposable
|
||||||
(dispose! [this]
|
(dispose! [this]
|
||||||
|
@ -297,12 +450,11 @@
|
||||||
(remove-watch w this))
|
(remove-watch w this))
|
||||||
(set! watching nil)
|
(set! watching nil)
|
||||||
(set! state nil)
|
(set! state nil)
|
||||||
(set! dirty? true)
|
(set! auto-run nil)
|
||||||
(when active?
|
(set! dirtyness dirty)
|
||||||
(when debug (swap! -running dec))
|
(when (some? on-dispose)
|
||||||
(set! active? false))
|
(on-dispose))
|
||||||
(when on-dispose
|
nil)
|
||||||
(on-dispose)))
|
|
||||||
|
|
||||||
IEquiv
|
IEquiv
|
||||||
(-equiv [o other] (identical? o other))
|
(-equiv [o other] (identical? o other))
|
||||||
|
@ -316,16 +468,54 @@
|
||||||
IHash
|
IHash
|
||||||
(-hash [this] (goog/getUid this)))
|
(-hash [this] (goog/getUid this)))
|
||||||
|
|
||||||
(defn make-reaction [f & {:keys [auto-run on-set on-dispose derefed]}]
|
|
||||||
(let [runner (if (= auto-run true) run auto-run)
|
;;; Queueing
|
||||||
active (not (nil? derefed))
|
|
||||||
dirty (not active)
|
;; Gets set up from batching
|
||||||
reaction (Reaction. f nil dirty active
|
;; TODO: Refactor so that isn't needed
|
||||||
nil nil
|
(defonce render-queue nil)
|
||||||
runner on-set on-dispose)]
|
|
||||||
|
(def dirty-queue nil)
|
||||||
|
|
||||||
|
(defn enqueue [r]
|
||||||
|
(when (nil? dirty-queue)
|
||||||
|
(set! dirty-queue (array))
|
||||||
|
(.schedule render-queue))
|
||||||
|
(.push dirty-queue r))
|
||||||
|
|
||||||
|
(defn flush! []
|
||||||
|
(let [q dirty-queue]
|
||||||
|
(when (some? q)
|
||||||
|
(set! dirty-queue nil)
|
||||||
|
(dotimes [i (alength q)]
|
||||||
|
(let [r (aget q i)]
|
||||||
|
(when-not (or (nil? (.-auto-run r))
|
||||||
|
(-check-clean r))
|
||||||
|
(run r)))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn make-reaction [f & {:keys [auto-run on-set on-dispose derefed no-cache
|
||||||
|
capture]}]
|
||||||
|
(let [runner (case auto-run
|
||||||
|
true run
|
||||||
|
:async enqueue
|
||||||
|
auto-run)
|
||||||
|
derefs (if-some [c capture]
|
||||||
|
(-captured c)
|
||||||
|
derefed)
|
||||||
|
dirty (if (nil? derefs) dirty clean)
|
||||||
|
nocache (if (nil? no-cache) false no-cache)
|
||||||
|
reaction (Reaction. f nil dirty nil nil
|
||||||
|
runner on-set on-dispose nocache)]
|
||||||
|
(when-some [rid (some-> capture .-reaction-id)]
|
||||||
|
(set! (.-reaction-id reaction) rid))
|
||||||
(when-not (nil? derefed)
|
(when-not (nil? derefed)
|
||||||
(when debug (swap! -running inc))
|
(warn "using derefed is deprecated"))
|
||||||
(-update-watching reaction derefed))
|
(when-not (nil? derefs)
|
||||||
|
(when (dev?)
|
||||||
|
(set! (.-ratomGeneration reaction)
|
||||||
|
(.-ratomGeneration derefs)))
|
||||||
|
(-update-watching reaction derefs))
|
||||||
reaction))
|
reaction))
|
||||||
|
|
||||||
|
|
||||||
|
@ -397,3 +587,24 @@
|
||||||
(util/partial-ifn. callback-fn args nil)
|
(util/partial-ifn. callback-fn args nil)
|
||||||
false nil))
|
false nil))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(def perf-check 0)
|
||||||
|
(defn ratom-perf []
|
||||||
|
(dbg "ratom-perf")
|
||||||
|
(set! debug false)
|
||||||
|
(dotimes [_ 10]
|
||||||
|
(set! perf-check 0)
|
||||||
|
(let [nite 100000
|
||||||
|
a (atom 0)
|
||||||
|
mid (make-reaction (fn [] (inc @a)))
|
||||||
|
res (make-reaction (fn []
|
||||||
|
(set! perf-check (inc perf-check))
|
||||||
|
(inc @mid))
|
||||||
|
:auto-run true)]
|
||||||
|
@res
|
||||||
|
(time (dotimes [x nite]
|
||||||
|
(swap! a inc)))
|
||||||
|
(dispose! res)
|
||||||
|
(assert (= perf-check (inc nite))))))
|
||||||
|
(enable-console-print!)
|
||||||
|
(ratom-perf))
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
(ns reagenttest.runtests
|
(ns ^:figwheel-always
|
||||||
|
reagenttest.runtests
|
||||||
(:require [reagenttest.testreagent]
|
(:require [reagenttest.testreagent]
|
||||||
[reagenttest.testcursor]
|
[reagenttest.testcursor]
|
||||||
[reagenttest.testinterop]
|
[reagenttest.testinterop]
|
||||||
[reagenttest.testratom]
|
[reagenttest.testratom]
|
||||||
|
[reagenttest.testratomasync]
|
||||||
|
[reagenttest.testtrack]
|
||||||
|
[reagenttest.testwithlet]
|
||||||
[reagenttest.testwrap]
|
[reagenttest.testwrap]
|
||||||
[cljs.test :as test :include-macros true]
|
[cljs.test :as test :include-macros true]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
|
@ -51,7 +55,6 @@
|
||||||
(run-tests)))
|
(run-tests)))
|
||||||
|
|
||||||
(defn reload []
|
(defn reload []
|
||||||
(demo/init!)
|
(demo/init!))
|
||||||
(init!))
|
|
||||||
|
|
||||||
(init!)
|
(init!)
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
(rv/running))
|
(rv/running))
|
||||||
(defn dispose [v] (rv/dispose! v))
|
(defn dispose [v] (rv/dispose! v))
|
||||||
|
|
||||||
|
(def testite 10)
|
||||||
|
|
||||||
(deftest basic-cursor
|
(deftest basic-cursor
|
||||||
(let [runs (running)
|
(let [runs (running)
|
||||||
start-base (rv/atom {:a {:b {:c 0}}})
|
start-base (rv/atom {:a {:b {:c 0}}})
|
||||||
|
@ -29,7 +31,7 @@
|
||||||
(is (= @out 2))
|
(is (= @out 2))
|
||||||
(reset! start 1)
|
(reset! start 1)
|
||||||
(is (= @out 3))
|
(is (= @out 3))
|
||||||
(is (= @count 4))
|
(is (= @count 2))
|
||||||
(dispose const)
|
(dispose const)
|
||||||
(is (= @start-base {:a {:b {:c 1}}}))
|
(is (= @start-base {:a {:b {:c 1}}}))
|
||||||
(is (= (running) runs))))
|
(is (= (running) runs))))
|
||||||
|
@ -85,7 +87,7 @@
|
||||||
|
|
||||||
|
|
||||||
(deftest test-unsubscribe
|
(deftest test-unsubscribe
|
||||||
(dotimes [x 10]
|
(dotimes [x testite]
|
||||||
(let [runs (running)
|
(let [runs (running)
|
||||||
a-base (rv/atom {:test {:unsubscribe 0 :value 42}})
|
a-base (rv/atom {:test {:unsubscribe 0 :value 42}})
|
||||||
a (r/cursor a-base [:test :unsubscribe])
|
a (r/cursor a-base [:test :unsubscribe])
|
||||||
|
@ -171,7 +173,7 @@
|
||||||
(is (= runs (running)))))
|
(is (= runs (running)))))
|
||||||
|
|
||||||
(deftest test-dispose
|
(deftest test-dispose
|
||||||
(dotimes [x 10]
|
(dotimes [x testite]
|
||||||
(let [runs (running)
|
(let [runs (running)
|
||||||
a-base (rv/atom {:a 0 :b 0})
|
a-base (rv/atom {:a 0 :b 0})
|
||||||
a (r/cursor a-base [:a])
|
a (r/cursor a-base [:a])
|
||||||
|
@ -191,19 +193,19 @@
|
||||||
:on-dispose #(reset! disposed-cns true))]
|
:on-dispose #(reset! disposed-cns true))]
|
||||||
@cns
|
@cns
|
||||||
(is (= @res 2))
|
(is (= @res 2))
|
||||||
(is (= (+ 4 runs) (running)))
|
(is (= (+ 6 runs) (running)))
|
||||||
(is (= @count-b 1))
|
(is (= @count-b 1))
|
||||||
(is (= {:a 0 :b 0} @a-base))
|
(is (= {:a 0 :b 0} @a-base))
|
||||||
(reset! a -1)
|
(reset! a -1)
|
||||||
(is (= @res 1))
|
(is (= @res 1))
|
||||||
(is (= @disposed nil))
|
(is (= @disposed nil))
|
||||||
(is (= @count-b 2))
|
(is (= @count-b 2))
|
||||||
(is (= (+ 4 runs) (running)) "still running")
|
(is (= (+ 6 runs) (running)) "still running")
|
||||||
(is (= {:a -1 :b 0} @a-base))
|
(is (= {:a -1 :b 0} @a-base))
|
||||||
(reset! a 2)
|
(reset! a 2)
|
||||||
(is (= @res 1))
|
(is (= @res 1))
|
||||||
(is (= @disposed true))
|
(is (= @disposed true))
|
||||||
(is (= (+ 3 runs) (running)) "less running count")
|
(is (= (+ 4 runs) (running)) "less running count")
|
||||||
(is (= {:a 2 :b 0} @a-base))
|
(is (= {:a 2 :b 0} @a-base))
|
||||||
|
|
||||||
(reset! disposed nil)
|
(reset! disposed nil)
|
||||||
|
|
|
@ -8,19 +8,28 @@
|
||||||
(set! rv/debug true)
|
(set! rv/debug true)
|
||||||
(rv/running))
|
(rv/running))
|
||||||
|
|
||||||
|
(def testite 10)
|
||||||
|
|
||||||
(defn dispose [v]
|
(defn dispose [v]
|
||||||
(rv/dispose! v))
|
(rv/dispose! v))
|
||||||
|
|
||||||
|
(def perf-check 0)
|
||||||
(defn ratom-perf []
|
(defn ratom-perf []
|
||||||
(dbg "ratom-perf")
|
(dbg "ratom-perf")
|
||||||
(let [a (rv/atom 0)
|
(set! rv/debug false)
|
||||||
|
(set! perf-check 0)
|
||||||
|
(let [nite 100000
|
||||||
|
a (rv/atom 0)
|
||||||
mid (reaction (inc @a))
|
mid (reaction (inc @a))
|
||||||
res (run!
|
res (run!
|
||||||
|
(set! perf-check (inc perf-check))
|
||||||
(inc @mid))]
|
(inc @mid))]
|
||||||
(time (dotimes [x 100000]
|
(time (dotimes [x nite]
|
||||||
(swap! a inc)))
|
(swap! a inc)))
|
||||||
(dispose res)))
|
(dispose res)
|
||||||
|
(assert (= perf-check (inc nite)))))
|
||||||
|
|
||||||
|
(enable-console-print!)
|
||||||
;; (ratom-perf)
|
;; (ratom-perf)
|
||||||
|
|
||||||
(deftest basic-ratom
|
(deftest basic-ratom
|
||||||
|
@ -40,7 +49,7 @@
|
||||||
(is (= @out 2))
|
(is (= @out 2))
|
||||||
(reset! start 1)
|
(reset! start 1)
|
||||||
(is (= @out 3))
|
(is (= @out 3))
|
||||||
(is (= @count 4))
|
(is (= @count 2))
|
||||||
(dispose const)
|
(dispose const)
|
||||||
(is (= (running) runs))))
|
(is (= (running) runs))))
|
||||||
|
|
||||||
|
@ -89,7 +98,7 @@
|
||||||
|
|
||||||
|
|
||||||
(deftest test-unsubscribe
|
(deftest test-unsubscribe
|
||||||
(dotimes [x 10]
|
(dotimes [x testite]
|
||||||
(let [runs (running)
|
(let [runs (running)
|
||||||
a (rv/atom 0)
|
a (rv/atom 0)
|
||||||
a1 (reaction (inc @a))
|
a1 (reaction (inc @a))
|
||||||
|
@ -166,7 +175,7 @@
|
||||||
(is (= runs (running)))))
|
(is (= runs (running)))))
|
||||||
|
|
||||||
(deftest test-dispose
|
(deftest test-dispose
|
||||||
(dotimes [x 10]
|
(dotimes [x testite]
|
||||||
(let [runs (running)
|
(let [runs (running)
|
||||||
a (rv/atom 0)
|
a (rv/atom 0)
|
||||||
disposed (rv/atom nil)
|
disposed (rv/atom nil)
|
||||||
|
@ -185,13 +194,13 @@
|
||||||
:on-dispose #(reset! disposed-cns true))]
|
:on-dispose #(reset! disposed-cns true))]
|
||||||
@cns
|
@cns
|
||||||
(is (= @res 2))
|
(is (= @res 2))
|
||||||
(is (= (+ 3 runs) (running)))
|
(is (= (+ 4 runs) (running)))
|
||||||
(is (= @count-b 1))
|
(is (= @count-b 1))
|
||||||
(reset! a -1)
|
(reset! a -1)
|
||||||
(is (= @res 1))
|
(is (= @res 1))
|
||||||
(is (= @disposed nil))
|
(is (= @disposed nil))
|
||||||
(is (= @count-b 2))
|
(is (= @count-b 2))
|
||||||
(is (= (+ 3 runs) (running)) "still running")
|
(is (= (+ 4 runs) (running)) "still running")
|
||||||
(reset! a 2)
|
(reset! a 2)
|
||||||
(is (= @res 1))
|
(is (= @res 1))
|
||||||
(is (= @disposed true))
|
(is (= @disposed true))
|
||||||
|
@ -238,15 +247,52 @@
|
||||||
(is (= @b 6))
|
(is (= @b 6))
|
||||||
(is (= runs (running)))))
|
(is (= runs (running)))))
|
||||||
|
|
||||||
;; (deftest catching
|
(deftest catching
|
||||||
;; (let [runs (running)
|
(let [runs (running)
|
||||||
;; a (rv/atom false)
|
a (rv/atom false)
|
||||||
;; catch-count (atom 0)
|
catch-count (atom 0)
|
||||||
;; b (reaction (if @a (throw {})))
|
b (reaction (if @a (throw (js/Error. "fail"))))
|
||||||
;; c (run! (try @b (catch js/Object e
|
c (run! (try @b (catch :default e
|
||||||
;; (swap! catch-count inc))))]
|
(swap! catch-count inc))))]
|
||||||
;; (is (= @catch-count 0))
|
(set! rv/silent true)
|
||||||
;; (reset! a false)
|
(is (= @catch-count 0))
|
||||||
;; (is (= @catch-count 0))
|
(reset! a false)
|
||||||
;; (reset! a true)
|
(is (= @catch-count 0))
|
||||||
;; (is (= @catch-count 1))))
|
(reset! a true)
|
||||||
|
(is (= @catch-count 1))
|
||||||
|
(reset! a false)
|
||||||
|
(is (= @catch-count 1))
|
||||||
|
(set! rv/silent false)
|
||||||
|
(dispose c)
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
(deftest test-rswap
|
||||||
|
(let [a (atom {:foo 1})]
|
||||||
|
(is (nil? (r/rswap! a update-in [:foo] inc)))
|
||||||
|
(is (= (:foo @a) 2))
|
||||||
|
(is (nil? (r/rswap! a identity)))
|
||||||
|
(is (= (:foo @a) 2))
|
||||||
|
(is (nil? (r/rswap! a #(assoc %1 :foo %2) 3)))
|
||||||
|
(is (= (:foo @a) 3))
|
||||||
|
(is (nil? (r/rswap! a #(assoc %1 :foo %3) 0 4)))
|
||||||
|
(is (= (:foo @a) 4))
|
||||||
|
(is (nil? (r/rswap! a #(assoc %1 :foo %4) 0 0 5)))
|
||||||
|
(is (= (:foo @a) 5))
|
||||||
|
(is (nil? (r/rswap! a #(assoc %1 :foo %5) 0 0 0 6)))
|
||||||
|
(is (= (:foo @a) 6))
|
||||||
|
(let [disp (atom nil)
|
||||||
|
f (fn [o v]
|
||||||
|
(assert (= v :add))
|
||||||
|
(if (< (:foo o) 10)
|
||||||
|
(do
|
||||||
|
(is (nil? (@disp v)))
|
||||||
|
(update-in o [:foo] inc))
|
||||||
|
o))
|
||||||
|
_ (reset! disp #(r/rswap! a f %))]
|
||||||
|
(@disp :add)
|
||||||
|
(is (= (:foo @a) 10)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,292 @@
|
||||||
|
(ns reagenttest.testratomasync
|
||||||
|
(:require [cljs.test :as t :refer-macros [is deftest testing]]
|
||||||
|
[reagent.ratom :as rv :refer-macros [run! reaction]]
|
||||||
|
[reagent.debug :refer-macros [dbg]]
|
||||||
|
[reagent.core :as r]))
|
||||||
|
|
||||||
|
(defn running []
|
||||||
|
(set! rv/debug true)
|
||||||
|
(rv/running))
|
||||||
|
|
||||||
|
(def testite 1)
|
||||||
|
|
||||||
|
(defn dispose [v]
|
||||||
|
(rv/dispose! v))
|
||||||
|
|
||||||
|
(defn sync [] (r/flush))
|
||||||
|
|
||||||
|
(defn ar [f] (rv/make-reaction f :auto-run :async))
|
||||||
|
|
||||||
|
(deftest basic-ratom
|
||||||
|
(sync)
|
||||||
|
(let [runs (running)
|
||||||
|
start (rv/atom 0)
|
||||||
|
sv (reaction @start)
|
||||||
|
comp (reaction @sv (+ 2 @sv))
|
||||||
|
c2 (reaction (inc @comp))
|
||||||
|
count (rv/atom 0)
|
||||||
|
out (rv/atom 0)
|
||||||
|
res (reaction
|
||||||
|
(swap! count inc)
|
||||||
|
@sv @c2 @comp)
|
||||||
|
const (ar (fn []
|
||||||
|
(reset! out @res)))]
|
||||||
|
(is (= @count 0))
|
||||||
|
@const
|
||||||
|
(is (= @count 1) "constrain ran")
|
||||||
|
(is (= @out 2))
|
||||||
|
(reset! start 1)
|
||||||
|
(is (= @count 1))
|
||||||
|
(sync)
|
||||||
|
(is (= @out 3))
|
||||||
|
(is (= @count 2))
|
||||||
|
(reset! start 2)
|
||||||
|
(dispose const)
|
||||||
|
(is (= (running) runs) "did dispose")
|
||||||
|
(sync)
|
||||||
|
(is (= (running) runs) "should not awaken")))
|
||||||
|
|
||||||
|
(deftest double-dependency
|
||||||
|
(sync)
|
||||||
|
(let [runs (running)
|
||||||
|
start (rv/atom 0)
|
||||||
|
c3-count (rv/atom 0)
|
||||||
|
c1 (reaction @start 1)
|
||||||
|
c2 (reaction @start)
|
||||||
|
c3 (rv/make-reaction
|
||||||
|
(fn []
|
||||||
|
(swap! c3-count inc)
|
||||||
|
(+ @c1 @c2))
|
||||||
|
:auto-run :async)]
|
||||||
|
(is (= @c3-count 0) "t0")
|
||||||
|
(sync)
|
||||||
|
(is (= @c3 1))
|
||||||
|
(is (= @c3-count 1) "t1")
|
||||||
|
(swap! start inc)
|
||||||
|
(is (= @c3-count 1))
|
||||||
|
(sync)
|
||||||
|
(is (= @c3-count 2) "t2")
|
||||||
|
(is (= @c3 2))
|
||||||
|
(is (= @c3-count 2) "t3")
|
||||||
|
(dispose c3)
|
||||||
|
(is (= (running) runs))
|
||||||
|
(sync)
|
||||||
|
(is (= @c3 2))
|
||||||
|
(is (= (running) runs))))
|
||||||
|
|
||||||
|
(deftest test-from-reflex
|
||||||
|
(sync)
|
||||||
|
(let [runs (running)]
|
||||||
|
(let [!counter (rv/atom 0)
|
||||||
|
!signal (rv/atom "All I do is change")
|
||||||
|
co (ar (fn []
|
||||||
|
;;when I change...
|
||||||
|
@!signal
|
||||||
|
;;update the counter
|
||||||
|
(swap! !counter inc)))]
|
||||||
|
(is (= 0 @!counter))
|
||||||
|
@co
|
||||||
|
(is (= 1 @!counter) "Constraint run on init")
|
||||||
|
(reset! !signal "foo")
|
||||||
|
(sync)
|
||||||
|
(is (= 2 @!counter)
|
||||||
|
"Counter auto updated")
|
||||||
|
(dispose co))
|
||||||
|
(let [!x (rv/atom 0)
|
||||||
|
!co (rv/make-reaction #(inc @!x) :auto-run :async)]
|
||||||
|
@!co
|
||||||
|
(is (= 1 @!co) "CO has correct value on first deref")
|
||||||
|
(swap! !x inc)
|
||||||
|
(sync)
|
||||||
|
(is (= 2 @!co) "CO auto-updates")
|
||||||
|
(dispose !co))
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest test-unsubscribe
|
||||||
|
(sync)
|
||||||
|
(dotimes [x testite]
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
a1 (reaction (inc @a))
|
||||||
|
a2 (reaction @a)
|
||||||
|
b-changed (rv/atom 0)
|
||||||
|
c-changed (rv/atom 0)
|
||||||
|
b (reaction
|
||||||
|
(swap! b-changed inc)
|
||||||
|
(inc @a1))
|
||||||
|
c (reaction
|
||||||
|
(swap! c-changed inc)
|
||||||
|
(+ 10 @a2))
|
||||||
|
res (ar (fn []
|
||||||
|
(if (< @a2 1) @b @c)))]
|
||||||
|
(is (= @res (+ 2 @a)))
|
||||||
|
(is (= @b-changed 1))
|
||||||
|
(is (= @c-changed 0))
|
||||||
|
|
||||||
|
(reset! a -1)
|
||||||
|
(is (= @b-changed 1))
|
||||||
|
@res
|
||||||
|
|
||||||
|
(is (= @b-changed 2))
|
||||||
|
(is (= @c-changed 0))
|
||||||
|
(is (= @res (+ 2 @a)))
|
||||||
|
|
||||||
|
(reset! a 2)
|
||||||
|
(sync)
|
||||||
|
(is (= @b-changed 3))
|
||||||
|
(is (= @c-changed 1))
|
||||||
|
(is (= @res (+ 10 @a)))
|
||||||
|
|
||||||
|
(reset! a 3)
|
||||||
|
(sync)
|
||||||
|
(is (= @b-changed 3))
|
||||||
|
(is (= @c-changed 2))
|
||||||
|
(is (= @res (+ 10 @a)))
|
||||||
|
|
||||||
|
(reset! a 3)
|
||||||
|
(sync)
|
||||||
|
(is (= @b-changed 3))
|
||||||
|
(is (= @c-changed 2))
|
||||||
|
(is (= @res (+ 10 @a)))
|
||||||
|
|
||||||
|
(reset! a -1)
|
||||||
|
(is (= @res (+ 2 @a)))
|
||||||
|
(dispose res)
|
||||||
|
(is (= runs (running))))))
|
||||||
|
|
||||||
|
(deftest maybe-broken
|
||||||
|
(sync)
|
||||||
|
(let [runs (running)]
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
b (reaction (inc @a))
|
||||||
|
c (reaction (dec @a))
|
||||||
|
d (reaction (str @b))
|
||||||
|
res (rv/atom 0)
|
||||||
|
cs (ar
|
||||||
|
#(reset! res @d))]
|
||||||
|
@cs
|
||||||
|
(is (= @res "1"))
|
||||||
|
(dispose cs))
|
||||||
|
;; should be broken according to https://github.com/lynaghk/reflex/issues/1
|
||||||
|
;; but isnt
|
||||||
|
(let [a (rv/atom 0)
|
||||||
|
b (reaction (inc @a))
|
||||||
|
c (reaction (dec @a))
|
||||||
|
d (ar (fn [] [@b @c]))]
|
||||||
|
(is (= @d [1 -1]))
|
||||||
|
(dispose d))
|
||||||
|
(let [a (rv/atom 0)
|
||||||
|
b (reaction (inc @a))
|
||||||
|
c (reaction (dec @a))
|
||||||
|
d (ar (fn [] [@b @c]))
|
||||||
|
res (rv/atom 0)]
|
||||||
|
(is (= @d [1 -1]))
|
||||||
|
(let [e (ar #(reset! res @d))]
|
||||||
|
@e
|
||||||
|
(is (= @res [1 -1]))
|
||||||
|
(dispose e))
|
||||||
|
(dispose d))
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
(deftest test-dispose
|
||||||
|
(dotimes [x testite]
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
disposed (rv/atom nil)
|
||||||
|
disposed-c (rv/atom nil)
|
||||||
|
disposed-cns (rv/atom nil)
|
||||||
|
count-b (rv/atom 0)
|
||||||
|
b (rv/make-reaction (fn []
|
||||||
|
(swap! count-b inc)
|
||||||
|
(inc @a))
|
||||||
|
:on-dispose #(reset! disposed true))
|
||||||
|
c (rv/make-reaction #(if (< @a 1) (inc @b) (dec @a))
|
||||||
|
:on-dispose #(reset! disposed-c true))
|
||||||
|
res (rv/atom nil)
|
||||||
|
cns (rv/make-reaction #(reset! res @c)
|
||||||
|
:auto-run :async
|
||||||
|
:on-dispose #(reset! disposed-cns true))]
|
||||||
|
@cns
|
||||||
|
(is (= @res 2))
|
||||||
|
(is (= (+ 4 runs) (running)))
|
||||||
|
(is (= @count-b 1))
|
||||||
|
(reset! a -1)
|
||||||
|
(is (= @res 2))
|
||||||
|
(sync)
|
||||||
|
(is (= @res 1))
|
||||||
|
(is (= @disposed nil))
|
||||||
|
(is (= @count-b 2))
|
||||||
|
(is (= (+ 4 runs) (running)) "still running")
|
||||||
|
(reset! a 2)
|
||||||
|
(sync)
|
||||||
|
(is (= @res 1))
|
||||||
|
(is (= @disposed true))
|
||||||
|
(is (= (+ 2 runs) (running)) "less running count")
|
||||||
|
|
||||||
|
(reset! disposed nil)
|
||||||
|
(reset! a -1)
|
||||||
|
(sync)
|
||||||
|
;; This fails sometimes on node. I have no idea why.
|
||||||
|
(is (= 1 @res) "should be one again")
|
||||||
|
(is (= @disposed nil))
|
||||||
|
(reset! a 2)
|
||||||
|
(sync)
|
||||||
|
(is (= @res 1))
|
||||||
|
(is (= @disposed true))
|
||||||
|
(dispose cns)
|
||||||
|
(is (= @disposed-c true))
|
||||||
|
(is (= @disposed-cns true))
|
||||||
|
(is (= runs (running))))))
|
||||||
|
|
||||||
|
(deftest test-on-set
|
||||||
|
(sync)
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
b (rv/make-reaction #(+ 5 @a)
|
||||||
|
:auto-run :async
|
||||||
|
:on-set (fn [oldv newv]
|
||||||
|
(reset! a (+ 10 newv))))]
|
||||||
|
(sync)
|
||||||
|
(is (= 5 @b))
|
||||||
|
(reset! a 1)
|
||||||
|
(sync)
|
||||||
|
(is (= 6 @b))
|
||||||
|
(reset! b 1)
|
||||||
|
(sync)
|
||||||
|
(is (= 11 @a))
|
||||||
|
(is (= 16 @b))
|
||||||
|
(dispose b)
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
(deftest non-reactive-deref
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
b (rv/make-reaction #(+ 5 @a))]
|
||||||
|
(is (= @b 5))
|
||||||
|
(is (= runs (running)))
|
||||||
|
|
||||||
|
(reset! a 1)
|
||||||
|
(is (= @b 6))
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
(deftest catching
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom false)
|
||||||
|
catch-count (atom 0)
|
||||||
|
b (reaction (if @a (throw (js/Error. "reaction fail"))))
|
||||||
|
c (ar (fn [] (try @b (catch js/Object e
|
||||||
|
(swap! catch-count inc)))))]
|
||||||
|
(set! rv/silent true)
|
||||||
|
(is (= @catch-count 0))
|
||||||
|
(reset! a false)
|
||||||
|
@c
|
||||||
|
(is (= @catch-count 0))
|
||||||
|
(reset! a true)
|
||||||
|
(is (= @catch-count 0))
|
||||||
|
(sync)
|
||||||
|
(is (= @catch-count 1))
|
||||||
|
(set! rv/silent false)
|
||||||
|
(dispose c)
|
||||||
|
(is (= runs (running)))))
|
|
@ -103,7 +103,8 @@
|
||||||
runs (running)
|
runs (running)
|
||||||
val (r/atom 0)
|
val (r/atom 0)
|
||||||
secval (r/atom 0)
|
secval (r/atom 0)
|
||||||
v1 (reaction @val)
|
v1-ran (atom 0)
|
||||||
|
v1 (reaction (swap! v1-ran inc) @val)
|
||||||
comp (fn []
|
comp (fn []
|
||||||
(swap! ran inc)
|
(swap! ran inc)
|
||||||
[:div (str "val " @v1 @val @secval)])]
|
[:div (str "val " @v1 @val @secval)])]
|
||||||
|
@ -119,15 +120,20 @@
|
||||||
(reset! val 1)
|
(reset! val 1)
|
||||||
(reset! val 2)
|
(reset! val 2)
|
||||||
(reset! val 1)
|
(reset! val 1)
|
||||||
|
(is (= 1 @ran))
|
||||||
|
(is (= 1 @v1-ran))
|
||||||
(r/flush)
|
(r/flush)
|
||||||
(is (found-in #"val 1" div))
|
(is (found-in #"val 1" div))
|
||||||
(is (= 2 @ran))
|
(is (= 2 @ran) "ran once more")
|
||||||
|
(is (= 2 @v1-ran))
|
||||||
|
|
||||||
;; should not be rendered
|
;; should not be rendered
|
||||||
(reset! val 1)
|
(reset! val 1)
|
||||||
|
(is (= 2 @v1-ran))
|
||||||
(r/flush)
|
(r/flush)
|
||||||
|
(is (= 2 @v1-ran))
|
||||||
(is (found-in #"val 1" div))
|
(is (found-in #"val 1" div))
|
||||||
(is (= 2 @ran))))
|
(is (= 2 @ran) "did not run")))
|
||||||
(is (= runs (running)))
|
(is (= runs (running)))
|
||||||
(is (= 2 @ran)))))
|
(is (= 2 @ran)))))
|
||||||
|
|
||||||
|
@ -559,3 +565,50 @@
|
||||||
c2 (fn []
|
c2 (fn []
|
||||||
[c1 (sorted-map 1 "foo" 2 "bar")])]
|
[c1 (sorted-map 1 "foo" 2 "bar")])]
|
||||||
(is (= (rstr [c2]) "<div>foo</div>"))))
|
(is (= (rstr [c2]) "<div>foo</div>"))))
|
||||||
|
|
||||||
|
(deftest basic-with-let
|
||||||
|
(let [n1 (atom 0)
|
||||||
|
n2 (atom 0)
|
||||||
|
n3 (atom 0)
|
||||||
|
val (r/atom 0)
|
||||||
|
c (fn []
|
||||||
|
(r/with-let [v (swap! n1 inc)]
|
||||||
|
(swap! n2 inc)
|
||||||
|
[:div @val]
|
||||||
|
(finally
|
||||||
|
(swap! n3 inc))))]
|
||||||
|
(with-mounted-component [c]
|
||||||
|
(fn [_ div]
|
||||||
|
(is (= [1 1 0] [@n1 @n2 @n3]))
|
||||||
|
(swap! val inc)
|
||||||
|
(is (= [1 1 0] [@n1 @n2 @n3]))
|
||||||
|
(r/flush)
|
||||||
|
(is (= [1 2 0] [@n1 @n2 @n3]))))
|
||||||
|
(is (= [1 2 1] [@n1 @n2 @n3]))))
|
||||||
|
|
||||||
|
(deftest with-let-destroy-only
|
||||||
|
(let [n1 (atom 0)
|
||||||
|
n2 (atom 0)
|
||||||
|
c (fn []
|
||||||
|
(r/with-let []
|
||||||
|
(swap! n1 inc)
|
||||||
|
[:div]
|
||||||
|
(finally
|
||||||
|
(swap! n2 inc))))]
|
||||||
|
(with-mounted-component [c]
|
||||||
|
(fn [_ div]
|
||||||
|
(is (= [1 0] [@n1 @n2]))))
|
||||||
|
(is (= [1 1] [@n1 @n2]))))
|
||||||
|
|
||||||
|
(deftest with-let-non-reactive
|
||||||
|
(let [n1 (atom 0)
|
||||||
|
n2 (atom 0)
|
||||||
|
n3 (atom 0)
|
||||||
|
c (fn []
|
||||||
|
(r/with-let [a (swap! n1 inc)]
|
||||||
|
(swap! n2 inc)
|
||||||
|
[:div a]
|
||||||
|
(finally
|
||||||
|
(swap! n3 inc))))]
|
||||||
|
(is (= (rstr [c]) (rstr [:div 1])))
|
||||||
|
(is (= [1 1 1] [@n1 @n2 @n3]))))
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
(ns reagenttest.testtrack
|
||||||
|
(:require [cljs.test :as t :refer-macros [is deftest testing]]
|
||||||
|
[reagent.ratom :as rv :refer [track] :refer-macros [run! reaction]]
|
||||||
|
[reagent.debug :refer-macros [dbg]]
|
||||||
|
[reagent.core :as r]))
|
||||||
|
|
||||||
|
(defn running []
|
||||||
|
(set! rv/debug true)
|
||||||
|
(rv/running))
|
||||||
|
|
||||||
|
(def testite 10)
|
||||||
|
|
||||||
|
(defn dispose [v]
|
||||||
|
(rv/dispose! v))
|
||||||
|
|
||||||
|
(defn sync [] (r/flush))
|
||||||
|
|
||||||
|
(enable-console-print!)
|
||||||
|
|
||||||
|
|
||||||
|
(deftest basic-ratom
|
||||||
|
(let [runs (running)
|
||||||
|
start (rv/atom 0)
|
||||||
|
svf (fn [] @start)
|
||||||
|
sv (track svf)
|
||||||
|
compf (fn [x] @sv (+ x @sv))
|
||||||
|
comp (track compf 2)
|
||||||
|
c2f (fn [] (inc @comp))
|
||||||
|
count (rv/atom 0)
|
||||||
|
out (rv/atom 0)
|
||||||
|
resf (fn []
|
||||||
|
(swap! count inc)
|
||||||
|
(+ @sv @(track c2f) @comp))
|
||||||
|
res (track resf)
|
||||||
|
const (run!
|
||||||
|
(reset! out @res))]
|
||||||
|
(is (= @count 1) "constrain ran")
|
||||||
|
(is (= @out 5))
|
||||||
|
(reset! start 1)
|
||||||
|
(is (= @out 8))
|
||||||
|
(is (= @count 2))
|
||||||
|
(dispose const)
|
||||||
|
(is (= (running) runs))))
|
||||||
|
|
||||||
|
(deftest test-track!
|
||||||
|
(sync)
|
||||||
|
(let [runs (running)
|
||||||
|
start (rv/atom 0)
|
||||||
|
svf (fn [] @start)
|
||||||
|
sv (track svf)
|
||||||
|
compf (fn [x] @sv (+ x @sv))
|
||||||
|
comp (track compf 2)
|
||||||
|
c2f (fn [] (inc @comp))
|
||||||
|
count (rv/atom 0)
|
||||||
|
out (rv/atom 0)
|
||||||
|
resf (fn []
|
||||||
|
(swap! count inc)
|
||||||
|
(+ @sv @(track c2f) @comp))
|
||||||
|
res (track resf)
|
||||||
|
const (rv/track!
|
||||||
|
#(reset! out @res))]
|
||||||
|
(is (= @count 1) "constrain ran")
|
||||||
|
(is (= @out 5))
|
||||||
|
(reset! start 1)
|
||||||
|
(is (= @count 1))
|
||||||
|
(sync)
|
||||||
|
(is (= @out 8))
|
||||||
|
(is (= @count 2))
|
||||||
|
(dispose const)
|
||||||
|
(swap! start inc)
|
||||||
|
(sync)
|
||||||
|
(is (= @count 2))
|
||||||
|
(is (= @const 11))
|
||||||
|
(is (= @count 3))
|
||||||
|
(is (= (running) runs))))
|
||||||
|
|
||||||
|
(deftest double-dependency
|
||||||
|
(let [runs (running)
|
||||||
|
start (rv/atom 0)
|
||||||
|
c3-count (rv/atom 0)
|
||||||
|
c1f (fn [] @start 1)
|
||||||
|
c2f (fn [] @start)
|
||||||
|
c3 (rv/make-reaction
|
||||||
|
(fn []
|
||||||
|
(swap! c3-count inc)
|
||||||
|
(+ @(track c1f) @(track c2f)))
|
||||||
|
:auto-run true)]
|
||||||
|
(is (= @c3-count 0))
|
||||||
|
(is (= @c3 1))
|
||||||
|
(is (= @c3-count 1) "t1")
|
||||||
|
(swap! start inc)
|
||||||
|
(is (= @c3-count 2) "t2")
|
||||||
|
(is (= @c3 2))
|
||||||
|
(is (= @c3-count 2) "t3")
|
||||||
|
(dispose c3)
|
||||||
|
(is (= (running) runs))))
|
||||||
|
|
||||||
|
(deftest test-from-reflex
|
||||||
|
(let [runs (running)]
|
||||||
|
(let [!x (rv/atom 0)
|
||||||
|
f #(inc @!x)
|
||||||
|
!co (run! @(track f))]
|
||||||
|
(is (= 1 @!co) "CO has correct value on first deref")
|
||||||
|
(swap! !x inc)
|
||||||
|
(is (= 2 @!co) "CO auto-updates")
|
||||||
|
(dispose !co))
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest test-unsubscribe
|
||||||
|
(dotimes [x testite]
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
af (fn [x] (+ @a x))
|
||||||
|
a1 (track af 1)
|
||||||
|
a2 (track af 0)
|
||||||
|
b-changed (rv/atom 0)
|
||||||
|
c-changed (rv/atom 0)
|
||||||
|
mf (fn [v x spy]
|
||||||
|
(swap! spy inc)
|
||||||
|
(+ @v x))
|
||||||
|
res (run!
|
||||||
|
(if (< @a2 1)
|
||||||
|
@(track mf a1 1 b-changed)
|
||||||
|
@(track mf a2 10 c-changed)))]
|
||||||
|
(is (= @res (+ 2 @a)))
|
||||||
|
(is (= @b-changed 1))
|
||||||
|
(is (= @c-changed 0))
|
||||||
|
|
||||||
|
(reset! a -1)
|
||||||
|
(is (= @res (+ 2 @a)))
|
||||||
|
(is (= @b-changed 2))
|
||||||
|
(is (= @c-changed 0))
|
||||||
|
|
||||||
|
(reset! a 2)
|
||||||
|
(is (= @res (+ 10 @a)))
|
||||||
|
(is (<= 2 @b-changed 3))
|
||||||
|
(is (= @c-changed 1))
|
||||||
|
|
||||||
|
(reset! a 3)
|
||||||
|
(is (= @res (+ 10 @a)))
|
||||||
|
(is (<= 2 @b-changed 3))
|
||||||
|
(is (= @c-changed 2))
|
||||||
|
|
||||||
|
(reset! a 3)
|
||||||
|
(is (= @res (+ 10 @a)))
|
||||||
|
(is (<= 2 @b-changed 3))
|
||||||
|
(is (= @c-changed 2))
|
||||||
|
|
||||||
|
(reset! a -1)
|
||||||
|
(is (= @res (+ 2 @a)))
|
||||||
|
(dispose res)
|
||||||
|
(is (= runs (running))))))
|
||||||
|
|
||||||
|
(deftest maybe-broken
|
||||||
|
(let [runs (running)]
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
f (fn [x] (+ x @a))
|
||||||
|
b (track f 1)
|
||||||
|
c (track f -1)
|
||||||
|
d (track #(str @b))
|
||||||
|
res (rv/atom 0)
|
||||||
|
cs (run!
|
||||||
|
(reset! res @d))]
|
||||||
|
(is (= @res "1"))
|
||||||
|
(dispose cs))
|
||||||
|
;; should be broken according to https://github.com/lynaghk/reflex/issues/1
|
||||||
|
;; but isnt
|
||||||
|
(let [a (rv/atom 0)
|
||||||
|
f (fn [x] (+ x @a))
|
||||||
|
b (track f 1)
|
||||||
|
d (run! [@b @(track f -1)])]
|
||||||
|
(is (= @d [1 -1]))
|
||||||
|
(dispose d))
|
||||||
|
(let [a (rv/atom 0)
|
||||||
|
f (fn [x] (+ x @a))
|
||||||
|
c (track f -1)
|
||||||
|
d (run! [@(track f 1) @c])
|
||||||
|
res (rv/atom 0)]
|
||||||
|
(is (= @d [1 -1]))
|
||||||
|
(let [e (run! (reset! res @d))]
|
||||||
|
(is (= @res [1 -1]))
|
||||||
|
(dispose e))
|
||||||
|
(dispose d))
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
(deftest non-reactive-deref
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom 0)
|
||||||
|
b (track #(+ 5 @a))]
|
||||||
|
(is (= @b 5))
|
||||||
|
(is (= runs (running)))
|
||||||
|
|
||||||
|
(reset! a 1)
|
||||||
|
(is (= @b 6))
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
(deftest catching
|
||||||
|
(let [runs (running)
|
||||||
|
a (rv/atom false)
|
||||||
|
catch-count (atom 0)
|
||||||
|
b (track #(if @a (throw (js/Error. "fail"))))
|
||||||
|
c (run! (try @b (catch :default e
|
||||||
|
(swap! catch-count inc))))]
|
||||||
|
(set! rv/silent true)
|
||||||
|
|
||||||
|
(is (= @catch-count 0))
|
||||||
|
(reset! a false)
|
||||||
|
(is (= @catch-count 0))
|
||||||
|
(reset! a true)
|
||||||
|
(is (= @catch-count 1))
|
||||||
|
(reset! a false)
|
||||||
|
(is (= @catch-count 1))
|
||||||
|
|
||||||
|
(set! rv/silent false)
|
||||||
|
(dispose c)
|
||||||
|
(is (= runs (running)))))
|
|
@ -0,0 +1,218 @@
|
||||||
|
(ns reagenttest.testwithlet
|
||||||
|
(:require [cljs.test :as t :refer-macros [is deftest testing]]
|
||||||
|
[reagent.ratom :as rv]
|
||||||
|
[reagent.debug :refer-macros [dbg]]
|
||||||
|
[reagent.core :as r
|
||||||
|
:refer [flush track track! dispose!] :refer-macros [with-let]]
|
||||||
|
[clojure.walk :as w]))
|
||||||
|
|
||||||
|
(defn running []
|
||||||
|
(r/flush)
|
||||||
|
(set! rv/debug true)
|
||||||
|
(rv/running))
|
||||||
|
|
||||||
|
(deftest basic-with-let
|
||||||
|
(let [runs (running)
|
||||||
|
n1 (atom 0)
|
||||||
|
n2 (atom 0)
|
||||||
|
n3 (atom 0)
|
||||||
|
a (r/atom 10)
|
||||||
|
f1 (fn []
|
||||||
|
(with-let [v (swap! n1 inc)]
|
||||||
|
(swap! n2 inc)
|
||||||
|
[@a v]
|
||||||
|
(finally
|
||||||
|
(swap! n3 inc))))
|
||||||
|
r (atom nil)
|
||||||
|
t (track! (fn []
|
||||||
|
(reset! r @(track f1))))]
|
||||||
|
(is (= [[10 1] 1 1 0] [@r @n1 @n2 @n3]))
|
||||||
|
(swap! a inc)
|
||||||
|
(is (= [[10 1] 1 1 0] [@r @n1 @n2 @n3]))
|
||||||
|
(flush)
|
||||||
|
(is (= [[11 1] 1 2 0] [@r @n1 @n2 @n3]))
|
||||||
|
(is (= [11 1] @t))
|
||||||
|
|
||||||
|
(dispose! t)
|
||||||
|
(is (= [[11 1] 1 2 1] [@r @n1 @n2 @n3]))
|
||||||
|
(is (= runs (running)))
|
||||||
|
|
||||||
|
(swap! a inc)
|
||||||
|
(flush)
|
||||||
|
(is (= [[11 1] 1 2 1] [@r @n1 @n2 @n3]))
|
||||||
|
|
||||||
|
(is (= [12 2] @t))
|
||||||
|
(is (= [[12 2] 2 3 2] [@r @n1 @n2 @n3]))
|
||||||
|
|
||||||
|
(is (= [12 3] (f1)))
|
||||||
|
(is (= [[12 2] 3 4 3] [@r @n1 @n2 @n3]))
|
||||||
|
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest test-with-let-args
|
||||||
|
(let [runs (running)
|
||||||
|
n1 (atom 0)
|
||||||
|
n2 (atom 0)
|
||||||
|
a (r/atom 0)
|
||||||
|
ran (fn []
|
||||||
|
(swap! n2 inc)
|
||||||
|
@a)
|
||||||
|
f1 #(with-let []
|
||||||
|
(ran)
|
||||||
|
[])
|
||||||
|
f2 #(with-let [x1 (swap! n1 inc)]
|
||||||
|
(ran)
|
||||||
|
[x1])
|
||||||
|
f3 #(with-let [x1 (swap! n1 inc)
|
||||||
|
x2 (swap! n1 inc)]
|
||||||
|
(ran)
|
||||||
|
[x1 x2])
|
||||||
|
f4 #(with-let [x1 (swap! n1 inc)
|
||||||
|
x2 (swap! n1 inc)
|
||||||
|
x3 (swap! n1 inc)]
|
||||||
|
(ran)
|
||||||
|
[x1 x2 x3])
|
||||||
|
f5 #(with-let [x1 (swap! n1 inc)
|
||||||
|
x2 (swap! n1 inc)
|
||||||
|
x3 (swap! n1 inc)
|
||||||
|
x4 (swap! n1 inc)]
|
||||||
|
(ran)
|
||||||
|
[x1 x2 x3 x4])
|
||||||
|
f6 #(with-let [x1 (swap! n1 inc)
|
||||||
|
x2 (swap! n1 inc)
|
||||||
|
x3 (swap! n1 inc)
|
||||||
|
x4 (swap! n1 inc)
|
||||||
|
x5 (swap! n1 inc)]
|
||||||
|
(ran)
|
||||||
|
[x1 x2 x3 x4 x5])
|
||||||
|
f7 #(with-let [x1 (swap! n1 inc)
|
||||||
|
x2 (swap! n1 inc)
|
||||||
|
x3 (swap! n1 inc)
|
||||||
|
x4 (swap! n1 inc)
|
||||||
|
x5 (swap! n1 inc)
|
||||||
|
x6 (swap! n1 inc)]
|
||||||
|
(ran)
|
||||||
|
[x1 x2 x3 x4 x5 x6])
|
||||||
|
r (atom nil)
|
||||||
|
all (fn [] {:f1 @(track f1)
|
||||||
|
:f2 @(track f2)
|
||||||
|
:f3 @(track f3)
|
||||||
|
:f4 @(track f4)
|
||||||
|
:f5 @(track f5)
|
||||||
|
:f6 @(track f6)
|
||||||
|
:f7 @(track f7)})
|
||||||
|
t (track! (fn [] (reset! r (all))))
|
||||||
|
expected {:f1 []
|
||||||
|
:f2 [1]
|
||||||
|
:f3 [2 3]
|
||||||
|
:f4 [4 5 6]
|
||||||
|
:f5 [7 8 9 10]
|
||||||
|
:f6 [11 12 13 14 15]
|
||||||
|
:f7 [16 17 18 19 20 21]}]
|
||||||
|
(is (< runs (running)))
|
||||||
|
(is (= @n2 7))
|
||||||
|
(is (= @r expected))
|
||||||
|
(is (= (all) expected))
|
||||||
|
(is (= @t expected))
|
||||||
|
(swap! a inc)
|
||||||
|
(is (= @n2 7))
|
||||||
|
(flush)
|
||||||
|
(is (= @n2 14))
|
||||||
|
(is (= @r expected))
|
||||||
|
(is (= (all) expected))
|
||||||
|
(is (= @t expected))
|
||||||
|
(is (= @n2 14))
|
||||||
|
(dispose! t)
|
||||||
|
(is (= runs (running)))
|
||||||
|
(is (= @r expected))
|
||||||
|
(is (= @n2 14))
|
||||||
|
(is (= (all) (w/postwalk #(if (number? %) (+ 21 %) %)
|
||||||
|
expected)))
|
||||||
|
(is (= @n2 21))
|
||||||
|
(is (= @t (w/postwalk #(if (number? %) (+ 42 %) %)
|
||||||
|
expected)))
|
||||||
|
(is (= @n2 28))
|
||||||
|
(is (= runs (running)))))
|
||||||
|
|
||||||
|
(deftest non-reactive-with-let
|
||||||
|
(let [n1 (atom 0)
|
||||||
|
n2 (atom 0)
|
||||||
|
n3 (atom 0)
|
||||||
|
n4 (atom 0)
|
||||||
|
f1 (fn []
|
||||||
|
(with-let []
|
||||||
|
(swap! n2 inc)))
|
||||||
|
f2 (fn []
|
||||||
|
(with-let [v (swap! n1 inc)]
|
||||||
|
v))
|
||||||
|
f3 (fn []
|
||||||
|
(with-let [v (swap! n1 inc)]
|
||||||
|
(swap! n2 inc)
|
||||||
|
(finally (swap! n3 inc))))
|
||||||
|
f4 (fn []
|
||||||
|
(with-let []
|
||||||
|
(finally (swap! n3 inc)
|
||||||
|
(swap! n4 inc))))
|
||||||
|
f5 (fn []
|
||||||
|
[(f1) (f2) (f4)])
|
||||||
|
tst (fn [f]
|
||||||
|
[(f) @n1 @n2 @n3])]
|
||||||
|
(is (= [1 0 1 0] (tst f1)))
|
||||||
|
(is (= [1 1 1 0] (tst f2)))
|
||||||
|
(is (= [2 2 2 1] (tst f3)))
|
||||||
|
(is (= 0 @n4))
|
||||||
|
(is (= [nil 2 2 2] (tst f4)))
|
||||||
|
(is (= 1 @n4))
|
||||||
|
(is (= [[3 3 nil] 3 3 3] (tst f5)))))
|
||||||
|
|
||||||
|
(deftest with-let-args
|
||||||
|
(let [runs (running)
|
||||||
|
active (atom 0)
|
||||||
|
n1 (atom 0)
|
||||||
|
f1 (fn [x y]
|
||||||
|
(with-let [_ (swap! active inc)
|
||||||
|
v (r/atom @x)]
|
||||||
|
(swap! n1 inc)
|
||||||
|
(+ y @v)
|
||||||
|
(finally
|
||||||
|
(reset! v nil)
|
||||||
|
(swap! active dec))))
|
||||||
|
f2 (fn [x y]
|
||||||
|
(with-let [t1 (track f1 x y)
|
||||||
|
t2 (track f1 x y)]
|
||||||
|
(let [v @(track f1 x y)]
|
||||||
|
(is (= v @t1 @t2))
|
||||||
|
v)))
|
||||||
|
f2t (partial track f2)
|
||||||
|
res (atom nil)
|
||||||
|
val (r/atom 1)
|
||||||
|
valtrack (track deref val)
|
||||||
|
t (track! #(reset! res (let [v valtrack]
|
||||||
|
(if (> @v 2)
|
||||||
|
[@(f2t v 10)]
|
||||||
|
[@(f2t val 0)
|
||||||
|
@(f2t val 0)
|
||||||
|
@(f2t v 10)
|
||||||
|
(f1 v 10)]))))]
|
||||||
|
(is (= [1 1 11 11] @res))
|
||||||
|
(is (= [3 3] [@n1 @active]))
|
||||||
|
(reset! val 1)
|
||||||
|
(flush)
|
||||||
|
(is (= [1 1 11 11] @res))
|
||||||
|
(is (= [3 3] [@n1 @active]))
|
||||||
|
|
||||||
|
(swap! val inc)
|
||||||
|
(is (= [3 3] [@n1 @active]))
|
||||||
|
(flush)
|
||||||
|
(is (= [6 3] [@n1 @active]))
|
||||||
|
(is (= [1 1 11 11] @res))
|
||||||
|
|
||||||
|
(swap! val inc)
|
||||||
|
(flush)
|
||||||
|
(is (= [6 1] [@n1 @active]))
|
||||||
|
(is (= [11] @res))
|
||||||
|
|
||||||
|
(dispose! t)
|
||||||
|
(is (= [6 0] [@n1 @active]))
|
||||||
|
(is (= runs (running)))))
|
|
@ -175,8 +175,8 @@
|
||||||
(is (= @ran 7)))))))
|
(is (= @ran 7)))))))
|
||||||
|
|
||||||
(deftest test-cursor
|
(deftest test-cursor
|
||||||
(let [state (r/atom {:a 0
|
(let [state (r/atom {:a {:v 1}
|
||||||
:b 0})
|
:b {:v 2}})
|
||||||
a-count (r/atom 0)
|
a-count (r/atom 0)
|
||||||
b-count (r/atom 0)
|
b-count (r/atom 0)
|
||||||
derefer (fn derefer [cur count]
|
derefer (fn derefer [cur count]
|
||||||
|
@ -191,7 +191,57 @@
|
||||||
(is (= @a-count 1))
|
(is (= @a-count 1))
|
||||||
(is (= @b-count 1))
|
(is (= @b-count 1))
|
||||||
|
|
||||||
(swap! state update-in [:a] inc)
|
(swap! state update-in [:a :v] inc)
|
||||||
|
(is (= @a-count 1))
|
||||||
|
|
||||||
(r/flush)
|
(r/flush)
|
||||||
(is (= @a-count 2))
|
(is (= @a-count 2))
|
||||||
|
(is (= @b-count 1))
|
||||||
|
|
||||||
|
(reset! state {:a {:v 2} :b {:v 2}})
|
||||||
|
(r/flush)
|
||||||
|
(is (= @a-count 2))
|
||||||
|
(is (= @b-count 1))
|
||||||
|
|
||||||
|
(reset! state {:a {:v 3} :b {:v 2}})
|
||||||
|
(r/flush)
|
||||||
|
(is (= @a-count 3))
|
||||||
(is (= @b-count 1))))))
|
(is (= @b-count 1))))))
|
||||||
|
|
||||||
|
(deftest test-fn-cursor
|
||||||
|
(let [state (r/atom {:a {:v 1}
|
||||||
|
:b {:v 2}})
|
||||||
|
statec (r/cursor state [])
|
||||||
|
a-count (r/atom 0)
|
||||||
|
b-count (r/atom 0)
|
||||||
|
derefer (fn derefer [cur count]
|
||||||
|
[:div @cur])
|
||||||
|
f (fn [[x y]] (swap! y inc) (get-in @statec x))
|
||||||
|
ac (r/cursor f [[:a] a-count])
|
||||||
|
bc (r/cursor f [[:b] b-count])
|
||||||
|
comp (fn test-cursor []
|
||||||
|
[:div
|
||||||
|
[derefer ac]
|
||||||
|
[derefer bc]])]
|
||||||
|
(with-mounted-component [comp]
|
||||||
|
(fn [c div]
|
||||||
|
(is (= @a-count 1))
|
||||||
|
(is (= @b-count 1))
|
||||||
|
|
||||||
|
(swap! state update-in [:a :v] inc)
|
||||||
|
(is (= @a-count 1))
|
||||||
|
(is (= @b-count 1))
|
||||||
|
|
||||||
|
(r/flush)
|
||||||
|
(is (= @a-count 2))
|
||||||
|
(is (= @b-count 2))
|
||||||
|
|
||||||
|
(reset! state {:a {:v 2} :b {:v 2}})
|
||||||
|
(r/flush)
|
||||||
|
(is (= @a-count 2))
|
||||||
|
(is (= @b-count 2))
|
||||||
|
|
||||||
|
(reset! state {:a {:v 3} :b {:v 2}})
|
||||||
|
(r/flush)
|
||||||
|
(is (= @a-count 3))
|
||||||
|
(is (= @b-count 3))))))
|
||||||
|
|
Loading…
Reference in New Issue