From 779743e2d0275d6473bfdc848617f2d640da540d Mon Sep 17 00:00:00 2001 From: Julien Eluard Date: Thu, 31 Jan 2019 14:22:54 +0100 Subject: [PATCH] [Fixes #109] Allow to use queries from within local events Signed-off-by: Julien Eluard --- .../assets/extensions/demo/extension.edn | 9 ++-- examples/src/pluto/examples.cljs | 7 ++- src/pluto/reader/blocks.cljc | 15 +++--- src/pluto/reader/events.cljc | 49 ++++++++++++++----- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/examples/resources/public/assets/extensions/demo/extension.edn b/examples/resources/public/assets/extensions/demo/extension.edn index c55000e..7bdb096 100644 --- a/examples/resources/public/assets/extensions/demo/extension.edn +++ b/examples/resources/public/assets/extensions/demo/extension.edn @@ -11,8 +11,9 @@ [alert {:value "Eh! ${you} ${value}"}]) events/cb - (let [{value :arg cond? :cond? v :value} properties] - [alert {:value "Eh bis! ${you} ${value}"}] + (let [{value :arg v :value} properties + {cond2? :cond?} [random-boolean]] + [alert {:value "Eh bis! ${cond2?}"}] [identity {:cb [my-alert {:arg value :value ["%% ${v}"]}]}]) views/local-view @@ -22,7 +23,7 @@ (case level :polite [text {:style {:color color}} "Hello!! ${name}"] :neutral [text {:style {:color color}} "Hey!! ${name}"] - "?? ${name}"))} + [text "?? ${name}"]))} views/local-view2 (let [{name :name color :color level :level} properties] @@ -35,7 +36,7 @@ {cond? :cond?} [random-boolean]] [view [local-view {:name "Hey!! ${name}" :color :red :level :polite}] - [button {:on-click [cb {:arg name :cond? cond? :value "AA"}]} + [button {:on-click [cb {:arg name :value "AA"}]} "Click!"] ;[button {:on-click [alert {}]} ; "Click2 !"] diff --git a/examples/src/pluto/examples.cljs b/examples/src/pluto/examples.cljs index d8fb51b..07213ec 100644 --- a/examples/src/pluto/examples.cljs +++ b/examples/src/pluto/examples.cljs @@ -9,6 +9,7 @@ [reagent.core :as reagent] [reagent.dom :as dom] [re-frame.core :as re-frame] + [re-frame.registrar :as registrar] [re-frame.loggers :as re-frame.loggers])) (def warn (js/console.warn.bind js/console)) @@ -36,11 +37,15 @@ (doseq [event events] (re-frame/dispatch event))) +(defn resolve-query [[id :as data]] + (when (registrar/get-handler :sub id) + (re-frame/subscribe data))) + (defn parse [m] (pluto/parse {:env {:id "Extension ID" :logger nil :event-fn dispatch-events - :query-fn nil} + :query-fn resolve-query} :capacities {:components components/all :queries {'random-boolean {:data :random-boolean} diff --git a/src/pluto/reader/blocks.cljc b/src/pluto/reader/blocks.cljc index 799900f..b5912ea 100644 --- a/src/pluto/reader/blocks.cljc +++ b/src/pluto/reader/blocks.cljc @@ -1,11 +1,12 @@ (ns pluto.reader.blocks - (:require [clojure.walk :as walk] - [re-frame.core :as re-frame] - [reagent.core :as reagent] + (:require [clojure.walk :as walk] + [re-frame.core :as re-frame] + [reagent.core :as reagent] [pluto.reader.destructuring :as destructuring] - [pluto.reader.errors :as errors] - [pluto.reader.types :as types] - [pluto.utils :as utils])) + [pluto.reader.errors :as errors] + [pluto.reader.types :as types] + [pluto.utils :as utils] + [pluto.reader.reference :as reference])) (defmulti parse "Parse a block element. Return hiccup data." @@ -82,7 +83,7 @@ (or (utils/primitive? v) (map? v))) (defn valid-bindings? [k v] - (and (or (symbol? k) (map? k)) + (and (or (symbol? k) (map? k) (vector? k)) (or (symbol? v) (static-value? v) (query? v)))) (defn- valid-bindings-form? [bindings] diff --git a/src/pluto/reader/events.cljc b/src/pluto/reader/events.cljc index 54f5585..ff2d0a6 100644 --- a/src/pluto/reader/events.cljc +++ b/src/pluto/reader/events.cljc @@ -31,7 +31,7 @@ (defn- dispatch-events "Dispatches an event using ctx" [ctx events] - (let [f (get-in ctx [:env :event-fn])] + (when-let [f (get-in ctx [:env :event-fn])] (if (seq events) (f events) (println "Empty event dispatched")))) @@ -46,28 +46,41 @@ :inline inline :errors (concat errors errors1)})) -(defn- event-dispatcher [ctx ext refs arguments bindings] +(defn- resolve-query + "Resolve a query using ctx" + [ctx ext query] + (let [{data :data} (types/resolve ctx ext :query query)] + (when-let [f (get-in ctx [:env :query-fn])] + (when-let [signal (f data)] + @signal)))) + +(defn merge-resolved-query [ctx ext m {:keys [value bindings]}] + (cond + (map? bindings) + (merge m (:data (destructuring/destructure bindings (merge m (resolve-query ctx ext value))))) + (symbol? bindings) + (assoc m bindings (resolve-query ctx ext value)))) + +(defn- event-dispatcher + "Returns a function of 2 arguments " + [ctx ext refs arguments {:keys [queries properties]}] (let [ref (map #(create-ref ctx ext %) refs)] (errors/merge-errors {:data (with-meta (fn [dynamic env] + ;; TODO env contains data that shouldn't be there ;; env is the dispatched argument. Used as default but is overridden by the local arguments ;; Perform destructuring based on dynamic and static arguments ;; Then resolve recursive properties in the aggregated env ;; Final map contains inline arguments resolved - (let [{:keys [data errors]} (destructuring/destructure bindings (merge dynamic arguments))] + (let [{:keys [data errors]} (destructuring/destructure properties (merge dynamic arguments))] ;; TODO handle errors - (let [env' (resolve-env env (merge env data))] + (let [env' (resolve-env env (merge env (reduce #(merge-resolved-query ctx ext %1 %2) data queries)))] (dispatch-events ctx (map #(create-event ctx env' %) ref))))) {:event true})} nil))) -(defn- bindings - "Returns the left-hand part of a properties bindings" - [data] - (first (second data))) - (defn- references "Returns a list of local event references" [data] @@ -80,20 +93,30 @@ (let [[form bindings] data] (and (< 2 (count data)) (= 'let form) - (= 2 (count bindings)) + (even? (count bindings)) (map? (first bindings)) (= 'properties (second bindings)) (every? reference/reference? (references data)))))) +(defn- merge-pair [m [k v]] + (cond + (= v 'properties) (assoc m :properties k) + :else (update m :queries concat [{:value v :bindings k}]))) + +(defn- parse-let-bindings [bindings] + (let [pairs (partition 2 bindings)] + (reduce merge-pair + {} + pairs))) + (defn parse "Parses local references defining let blocks" - [ctx ext local arguments] + [ctx ext [_ let-bindings :as local] arguments] (if (local-event? local) - (event-dispatcher ctx ext (references local) arguments (bindings local)) + (event-dispatcher ctx ext (references local) arguments (parse-let-bindings let-bindings)) {:errors [(errors/error ::errors/invalid-local-event local)]})) (defmethod types/resolve :event [ctx ext _ [_ arguments :as value]] - ;; TODO if kw, comes from reference, then resolve as a fn (let [{:keys [data errors] :as m} (reference/resolve ctx ext :event value)] ;; resolve returns either data or errors (if data