Merge branch 'def-sub' into develop
This commit is contained in:
commit
5f115c1d2c
|
@ -29,7 +29,7 @@
|
||||||
[karma-junit-reporter "0.3.8"]]}
|
[karma-junit-reporter "0.3.8"]]}
|
||||||
|
|
||||||
:cljsbuild {:builds [{:id "test"
|
:cljsbuild {:builds [{:id "test"
|
||||||
:source-paths ["test"]
|
:source-paths ["test" "src"]
|
||||||
:compiler {:output-to "run/compiled/test.js"
|
:compiler {:output-to "run/compiled/test.js"
|
||||||
:source-map "run/compiled/test.js.map"
|
:source-map "run/compiled/test.js.map"
|
||||||
:output-dir "run/compiled/test"
|
:output-dir "run/compiled/test"
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
(def dispatch-sync router/dispatch-sync)
|
(def dispatch-sync router/dispatch-sync)
|
||||||
|
|
||||||
(def register-sub subs/register)
|
(def register-sub subs/register)
|
||||||
|
(def register-pure-sub subs/register-pure)
|
||||||
(def clear-sub-handlers! subs/clear-handlers!)
|
(def clear-sub-handlers! subs/clear-handlers!)
|
||||||
(def subscribe subs/subscribe)
|
(def subscribe subs/subscribe)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
(ns re-frame.subs
|
(ns re-frame.subs
|
||||||
(:require
|
(:require
|
||||||
|
[cljs.spec :as s]
|
||||||
[reagent.ratom :as ratom :refer [make-reaction] :refer-macros [reaction]]
|
[reagent.ratom :as ratom :refer [make-reaction] :refer-macros [reaction]]
|
||||||
[re-frame.db :refer [app-db]]
|
[re-frame.db :refer [app-db]]
|
||||||
[re-frame.utils :refer [first-in-vector warn error]]))
|
[re-frame.utils :refer [first-in-vector warn error]]))
|
||||||
|
@ -10,11 +11,6 @@
|
||||||
;; Maps from a query-id to a handler function.
|
;; Maps from a query-id to a handler function.
|
||||||
(def ^:private qid->fn (atom {}))
|
(def ^:private qid->fn (atom {}))
|
||||||
|
|
||||||
(defn clear-handlers!
|
|
||||||
"Unregisters all existing subscription handlers"
|
|
||||||
[]
|
|
||||||
(reset! qid->fn {}))
|
|
||||||
|
|
||||||
(defn register
|
(defn register
|
||||||
"Registers a subscription handler function for an query id"
|
"Registers a subscription handler function for an query id"
|
||||||
[query-id handler-fn]
|
[query-id handler-fn]
|
||||||
|
@ -31,6 +27,12 @@
|
||||||
;; test "=".
|
;; test "=".
|
||||||
(def ^:private query->reaction (atom {}))
|
(def ^:private query->reaction (atom {}))
|
||||||
|
|
||||||
|
(defn clear-handlers!
|
||||||
|
"Unregisters all existing subscription handlers"
|
||||||
|
[]
|
||||||
|
(reset! qid->fn {})
|
||||||
|
(reset! query->reaction {}))
|
||||||
|
|
||||||
(defn cache-and-return
|
(defn cache-and-return
|
||||||
"cache the reaction r"
|
"cache the reaction r"
|
||||||
[v dynv r]
|
[v dynv r]
|
||||||
|
@ -61,7 +63,7 @@
|
||||||
cached)
|
cached)
|
||||||
(let [query-id (first-in-vector v)
|
(let [query-id (first-in-vector v)
|
||||||
handler-fn (get @qid->fn query-id)]
|
handler-fn (get @qid->fn query-id)]
|
||||||
(warn "Subscription crerated: " v)
|
(warn "Subscription created: " v)
|
||||||
(if-not handler-fn
|
(if-not handler-fn
|
||||||
(error "re-frame: no subscription handler registered for: \"" query-id "\". Returning a nil subscription."))
|
(error "re-frame: no subscription handler registered for: \"" query-id "\". Returning a nil subscription."))
|
||||||
(cache-and-return v [] (handler-fn app-db v)))))
|
(cache-and-return v [] (handler-fn app-db v)))))
|
||||||
|
@ -83,3 +85,93 @@
|
||||||
;; need to double deref it to get to the actual value.
|
;; need to double deref it to get to the actual value.
|
||||||
(warn "Subscription created: " v dynv)
|
(warn "Subscription created: " v dynv)
|
||||||
(cache-and-return v dynv (reaction @@sub))))))))
|
(cache-and-return v dynv (reaction @@sub))))))))
|
||||||
|
|
||||||
|
;; -- Helper code for register-pure -------------------
|
||||||
|
|
||||||
|
(s/def ::register-pure-args (s/cat
|
||||||
|
:sub-name keyword?
|
||||||
|
:sub-fn (s/? fn?)
|
||||||
|
:arrow-args (s/* (s/cat :key #{:<-} :val vector?))
|
||||||
|
:f fn?))
|
||||||
|
|
||||||
|
(defn- fmap
|
||||||
|
"Returns a new version of 'm' in which f has been applied to each value.
|
||||||
|
(fmap inc {:a 4, :b 2}) => {:a 5, :b 3}"
|
||||||
|
[f m]
|
||||||
|
(into {} (for [[k val] m] [k (f val)])))
|
||||||
|
|
||||||
|
(defn- multi-deref
|
||||||
|
"derefs a map sequence or a singleton"
|
||||||
|
[data]
|
||||||
|
(cond
|
||||||
|
(map? data) (fmap deref data)
|
||||||
|
(coll? data) (map deref data)
|
||||||
|
:else @data))
|
||||||
|
|
||||||
|
(defn register-pure
|
||||||
|
"This fn allows the user to write a 'pure' subscription
|
||||||
|
i.e. that is a subscription that operates on the values within app-db
|
||||||
|
rather than the atom itself
|
||||||
|
Note there are 3 ways this function can be called
|
||||||
|
|
||||||
|
```(register-pure
|
||||||
|
:test-sub
|
||||||
|
(fn [db [_]] db))```
|
||||||
|
In this example the entire app-db is derefed and passed to the subscription
|
||||||
|
function as a singleton
|
||||||
|
|
||||||
|
```(subs/register-pure
|
||||||
|
:a-b-sub
|
||||||
|
(fn [q-vec d-vec]
|
||||||
|
[(subs/subscribe [:a-sub])
|
||||||
|
(subs/subscribe [:b-sub])]
|
||||||
|
(fn [[a b] [_]] {:a a :b b}))```
|
||||||
|
In this example the the first function is called with the query vector
|
||||||
|
and the dynamic vector as arguements the return value of this function
|
||||||
|
can be singleton reaction or a list or map of reactions. Note that `q-vec`
|
||||||
|
and `d-vec` can be destructured and used in the subscriptions (this is the point
|
||||||
|
actually). Again the subscriptions are derefed and passed to the subscription
|
||||||
|
function
|
||||||
|
|
||||||
|
```(subs/register-pure
|
||||||
|
:a-b-sub
|
||||||
|
:<- [:a-sub]
|
||||||
|
:<- [:b-sub]
|
||||||
|
(fn [[a b] [_]] {:a a :b b}))```
|
||||||
|
In this example the convienent syntax of `:<-` is used to cover the majority
|
||||||
|
of cases where only a simple subscription is needed without any parameters
|
||||||
|
|
||||||
|
"
|
||||||
|
[& args]
|
||||||
|
(let [conform (s/conform ::register-pure-args args)
|
||||||
|
{:keys [sub-name
|
||||||
|
sub-fn
|
||||||
|
arrow-args
|
||||||
|
f]} conform
|
||||||
|
arrow-subs (->> arrow-args
|
||||||
|
(map :val))]
|
||||||
|
(cond
|
||||||
|
sub-fn ;; first case the user provides a custom sub-fn
|
||||||
|
(register
|
||||||
|
sub-name
|
||||||
|
(fn [db q-vec d-vec]
|
||||||
|
(let [subscriptions (sub-fn q-vec d-vec)] ;; this let needs to be outside the fn
|
||||||
|
(ratom/make-reaction
|
||||||
|
(fn [] (f (multi-deref subscriptions) q-vec d-vec))))))
|
||||||
|
arrow-args ;; the user uses the :<- sugar
|
||||||
|
(register
|
||||||
|
sub-name
|
||||||
|
(fn [db q-vec d-vec]
|
||||||
|
(let [subscriptions (map subscribe arrow-subs)] ;; this let needs to be outside the fn
|
||||||
|
(ratom/make-reaction
|
||||||
|
(fn [] (f (multi-deref subscriptions) q-vec d-vec))))))
|
||||||
|
:else
|
||||||
|
(register ;; the simple case with no subs
|
||||||
|
sub-name
|
||||||
|
(fn [db q-vec d-vec]
|
||||||
|
(ratom/make-reaction (fn [] (f @db q-vec d-vec))))))))
|
||||||
|
|
||||||
|
#_(s/fdef register-pure
|
||||||
|
:args ::register-pure-args)
|
||||||
|
|
||||||
|
#_(s/instrument #'register-pure)
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
(ns re-frame.test.subs
|
||||||
|
(:require [cljs.test :refer-macros [is deftest]]
|
||||||
|
[reagent.ratom :refer-macros [reaction]]
|
||||||
|
[re-frame.subs :as subs]
|
||||||
|
[re-frame.db :as db]
|
||||||
|
[re-frame.core :as re-frame]))
|
||||||
|
|
||||||
|
;=====test basic subscriptions ======
|
||||||
|
|
||||||
|
(deftest test-reg-sub
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:test-sub
|
||||||
|
(fn [db [_]] (reaction (deref db))))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:test-sub])]
|
||||||
|
(is (= @db/app-db @test-sub))
|
||||||
|
(reset! db/app-db 1)
|
||||||
|
(is (= 1 @test-sub))))
|
||||||
|
|
||||||
|
(deftest test-chained-subs
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:a-sub
|
||||||
|
(fn [db [_]] (reaction (:a @db))))
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:b-sub
|
||||||
|
(fn [db [_]] (reaction (:b @db))))
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:a-b-sub
|
||||||
|
(fn [db [_]]
|
||||||
|
(let [a (subs/subscribe [:a-sub])
|
||||||
|
b (subs/subscribe [:b-sub])]
|
||||||
|
(reaction {:a @a :b @b}))))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:a-b-sub])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= {:a 1 :b 2} @test-sub))
|
||||||
|
(swap! db/app-db assoc :b 3)
|
||||||
|
(is (= {:a 1 :b 3} @test-sub))))
|
||||||
|
|
||||||
|
(deftest test-sub-parameters
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:test-sub
|
||||||
|
(fn [db [_ b]] (reaction [(:a @db) b])))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:test-sub :c])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= [1 :c] @test-sub))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest test-sub-chained-parameters
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:a-sub
|
||||||
|
(fn [db [_ a]] (reaction [(:a @db) a])))
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:b-sub
|
||||||
|
(fn [db [_ b]] (reaction [(:b @db) b])))
|
||||||
|
|
||||||
|
(subs/register
|
||||||
|
:a-b-sub
|
||||||
|
(fn [db [_ c]]
|
||||||
|
(let [a (subs/subscribe [:a-sub c])
|
||||||
|
b (subs/subscribe [:b-sub c])]
|
||||||
|
(reaction {:a @a :b @b}))))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:a-b-sub :c])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= {:a [1 :c], :b [2 :c]} @test-sub))))
|
||||||
|
|
||||||
|
;============== test register-pure macros ================
|
||||||
|
|
||||||
|
(deftest test-reg-sub-macro
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:test-sub
|
||||||
|
(fn [db [_]] db))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:test-sub])]
|
||||||
|
(is (= @db/app-db @test-sub))
|
||||||
|
(reset! db/app-db 1)
|
||||||
|
(is (= 1 @test-sub))))
|
||||||
|
|
||||||
|
(deftest test-reg-sub-macro-singleton
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-sub
|
||||||
|
(fn [db [_]] (:a db)))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-b-sub
|
||||||
|
(fn [_ _ _]
|
||||||
|
(subs/subscribe [:a-sub]))
|
||||||
|
(fn [a [_]]
|
||||||
|
{:a a}))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:a-b-sub])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= {:a 1} @test-sub))
|
||||||
|
(swap! db/app-db assoc :b 3)
|
||||||
|
(is (= {:a 1} @test-sub))))
|
||||||
|
|
||||||
|
(deftest test-reg-sub-macro-vector
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-sub
|
||||||
|
(fn [db [_]] (:a db)))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:b-sub
|
||||||
|
(fn [db [_]] (:b db)))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-b-sub
|
||||||
|
(fn [_ _ _]
|
||||||
|
[(subs/subscribe [:a-sub])
|
||||||
|
(subs/subscribe [:b-sub])])
|
||||||
|
(fn [[a b] [_]]
|
||||||
|
{:a a :b b}))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:a-b-sub])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= {:a 1 :b 2} @test-sub))
|
||||||
|
(swap! db/app-db assoc :b 3)
|
||||||
|
(is (= {:a 1 :b 3} @test-sub))))
|
||||||
|
|
||||||
|
(deftest test-reg-sub-macro-map
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-sub
|
||||||
|
(fn [db [_]] (:a db)))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:b-sub
|
||||||
|
(fn [db [_]] (:b db)))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-b-sub
|
||||||
|
(fn [_ _ _]
|
||||||
|
{:a (subs/subscribe [:a-sub])
|
||||||
|
:b (subs/subscribe [:b-sub])})
|
||||||
|
(fn [{:keys [a b]} [_]]
|
||||||
|
{:a a :b b}))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:a-b-sub])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= {:a 1 :b 2} @test-sub))
|
||||||
|
(swap! db/app-db assoc :b 3)
|
||||||
|
(is (= {:a 1 :b 3} @test-sub))))
|
||||||
|
|
||||||
|
(deftest test-sub-macro-parameters
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:test-sub
|
||||||
|
(fn [db [_ b]] [(:a db) b]))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:test-sub :c])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= [1 :c] @test-sub))))
|
||||||
|
|
||||||
|
(deftest test-sub-macros-chained-parameters
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-sub
|
||||||
|
(fn [db [_ a]] [(:a db) a]))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:b-sub
|
||||||
|
(fn [db [_ b]] [(:b db) b]))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-b-sub
|
||||||
|
(fn [[_ c] _]
|
||||||
|
[(subs/subscribe [:a-sub c])
|
||||||
|
(subs/subscribe [:b-sub c])])
|
||||||
|
(fn [[a b] [_ c]] {:a a :b b}))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:a-b-sub :c])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= {:a [1 :c] :b [2 :c]} @test-sub))))
|
||||||
|
|
||||||
|
|
||||||
|
(deftest test-sub-macros-chained-parameters-<-
|
||||||
|
"test the syntactial sugar"
|
||||||
|
(subs/clear-handlers!)
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-sub
|
||||||
|
(fn [db [_]] (:a db)))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:b-sub
|
||||||
|
(fn [db [_]] (:b db)))
|
||||||
|
|
||||||
|
(subs/register-pure
|
||||||
|
:a-b-sub
|
||||||
|
:<- [:a-sub]
|
||||||
|
:<- [:b-sub]
|
||||||
|
(fn [[a b] [_ c]] {:a a :b b}))
|
||||||
|
|
||||||
|
(let [test-sub (subs/subscribe [:a-b-sub :c])]
|
||||||
|
(reset! db/app-db {:a 1 :b 2})
|
||||||
|
(is (= {:a 1 :b 2} @test-sub) ))
|
||||||
|
)
|
|
@ -1,11 +1,13 @@
|
||||||
(ns re-frame.test.runner
|
(ns re-frame.test.runner
|
||||||
(:require [jx.reporter.karma :as karma :include-macros true]
|
(:require [jx.reporter.karma :as karma :include-macros true]
|
||||||
[re-frame.test.middleware]
|
[re-frame.test.middleware]
|
||||||
[re-frame.test.undo]))
|
[re-frame.test.undo]
|
||||||
|
[re-frame.test.subs]))
|
||||||
|
|
||||||
|
|
||||||
(defn ^:export run [karma]
|
(defn ^:export run [karma]
|
||||||
(karma/run-tests
|
(karma/run-tests
|
||||||
karma
|
karma
|
||||||
're-frame.test.middleware
|
're-frame.test.middleware
|
||||||
're-frame.test.undo))
|
're-frame.test.undo
|
||||||
|
're-frame.test.subs))
|
||||||
|
|
Loading…
Reference in New Issue