eufon

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 712a6578462d8e36260f2370a6b9f4a19b011c4f
parent 8b564f09a76b12bac23d1c9bc170431531634cc1
Author: Daniel Barlow <dan@telent.net>
Date:   Sun, 27 Feb 2022 16:57:08 +0000

allow observers on app-state leaf nodes

Diffstat:
Mjust/observable-test.fnl | 13+++++++++++--
Mjust/observable.fnl | 52++++++++++++++++++++++++++++++----------------------
2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/just/observable-test.fnl b/just/observable-test.fnl @@ -45,11 +45,20 @@ (let [s (observable.new {:foo {:bar 43}})] (var win false) - ;; observers live on subtrees, not individual nodes - (s:observe [:foo] #(set win true)) + ;; observer on leaf + (s:observe [:foo :bar] #(set win true)) (s:update [:foo :bar] 42) (expect (and win))) +(let [s (observable.new {:foo {:bar 43}})] + (var win false) + ;; observer on subtree + (s:observe [:foo] #(set win true)) + (s:update [:foo :bar] 42) + (expect (and true win))) + + + (let [s (observable.new {:foo {:bar {:baz 43}}})] (var win 0) ;; observers on ancestor trees are called after child trees diff --git a/just/observable.fnl b/just/observable.fnl @@ -3,32 +3,40 @@ (fn concat [dest src] (table.move dest 1 (# dest) (# src) src)) -(fn update [data self path value] +(fn update [data path value vivify?] (let [[first & rest] path] (if (next rest) - (update (. data first) self rest value) - (tset data first value)) - (if data._subscribers - (each [_ f (pairs data._subscribers)] (f))))) + (do + (if (and vivify? (not (. data first))) + (tset data first {})) + (update (. data first) rest value)) + (tset data first value)))) -(fn get [data self path] - (let [[first & rest] path] - (if (not first) data - (next rest) (get (. data first) self rest) - (. data first)))) +(fn new [data] + (let [observers {} + key [:obs]] + (fn get [data path] + (let [[first & rest] path] + (if (not first) data + (next rest) (get (. data first) rest) + (. (or data {}) first)))) -(fn observe [data self path fun] - (let [el (get data self path)] - (when el - (if el._subscribers - (table.insert el._subscribers fun) - (tset el :_subscribers [fun]))))) + (fn publish [observers path] + (let [[first & rest] path + os (. (or observers {}) first)] + (if (and (next rest) (next os)) (publish os rest)) + (match os + {key list} (each [_ f (pairs list)] (f))))) -(fn new [data] - { - :observe (partial observe data) - :update (partial update data) - :get (partial get data) - }) + (fn observe [observers path fun] + (let [el (get observers path)] + (if el + (table.insert (. el key) fun) + (update observers path {key [fun]} true)))) + { + :observe #(observe observers $2 $3) + :update #(do (update data $2 $3) (publish observers $2)) + :get #(get data $2) + })) {: new }