Skip to content

Commit

Permalink
[nop] Misc housekeeping
Browse files Browse the repository at this point in the history
  • Loading branch information
ptaoussanis committed Jul 31, 2023
1 parent 4db04bc commit bb9b02c
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 143 deletions.
201 changes: 102 additions & 99 deletions src/taoensso/tengen/common.cljc
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
(ns taoensso.tengen.common
"Private common implementation details."
(:require
#?(:clj [taoensso.encore :as enc :refer [have have?]])
#?(:cljs [taoensso.encore :as enc :refer-macros [have have?]])))
[taoensso.encore :as enc :refer [have have?]]))

(enc/assert-min-encore-version [2 85 0])

(defmacro binding-rvals
"Evaluates and returns vector of rhs values for given bindings while
preserving support for the usual let-binding facilities like destructuring,
referring to previous bindings, etc.
#?(:clj
(defmacro binding-rvals
"Evaluates and returns vector of rhs values for given bindings while
preserving support for the usual let-binding facilities like destructuring,
referring to previous bindings, etc.
[{:keys [x]} {:x 1}
<...>
] ->
(let [alias1 {:x 1}
{:keys [x]} alias1
<...>
]
[alias1 <...>])"
[bindings]
(let [pairs (partition 2 bindings)
lvals (mapv first pairs)
rvals (mapv second pairs)
aliases (mapv (fn [i] (symbol (str "__lv" i))) (range (count lvals)))
[{:keys [x]} {:x 1}
<...>
] ->
(let [alias1 {:x 1}
{:keys [x]} alias1
<...>
]
[alias1 <...>])"

alias-bindings (interleave aliases rvals)
lval-bindings (interleave lvals aliases)
[bindings]
(let [pairs (partition 2 bindings)
lvals (mapv first pairs)
rvals (mapv second pairs)
aliases (mapv (fn [i] (symbol (str "__lv" i))) (range (count lvals)))

alias-bpairs (partition 2 alias-bindings) ; [(<alias> <rval>) ...]
lval-bpairs (partition 2 lval-bindings) ; [(<lval> <alias>) ...]
alias-bindings (interleave aliases rvals)
lval-bindings (interleave lvals aliases)

bindings* (reduce into [] (interleave alias-bpairs lval-bpairs))]
alias-bpairs (partition 2 alias-bindings) ; [(<alias> <rval>) ...]
lval-bpairs (partition 2 lval-bindings) ; [(<lval> <alias>) ...]

`(let ~bindings* ~aliases)))
bindings* (reduce into [] (interleave alias-bpairs lval-bpairs))]

`(let ~bindings* ~aliases))))

(comment
(do (binding-rvals [x 1, {:keys [a b]} {:a x :b x}]))
Expand Down Expand Up @@ -63,77 +64,79 @@

(comment (hash-map-with-unique-ks [:a :A :b :B :a :A2]))

(defmacro cmptfn [impl-constructor-fn id params & args]
(let [implicit-render-body? (odd? (count args))
args-map
(if implicit-render-body?
(hash-map-with-unique-ks (butlast args))
(hash-map-with-unique-ks args))

_ (have? [:ks<= #{:let-mount :let-render :render
:post-render :unmount}]
args-map)

_ (when implicit-render-body?
(assert (not (contains? args-map :render))
"Ambiguous render body: provided as both a :render value and implicit final arg"))

have-arg? (set (keys args-map)) ; For existance check w/o val eval
render-body (if implicit-render-body? (last args) (:render args-map))
_ (assert render-body "No (nil) render body provided")

;; [x :x y x]
mount-bindings (:let-mount args-map)
render-bindings (:let-render args-map)

;; [[x y] [:x x]] ; We actually just want the lval forms here
[ mount-lvals _mount-rvals] (split-let-pairs mount-bindings)
[render-lvals _render-rvals] (split-let-pairs render-bindings)

;; Define our cfn lifecycle fns
;; NB We try minimize code expansion size here (esp. gensyms)

argv
(if (seq params)
(into ['__] params) ; [__ x y z ...]
'__)

?mount-rvals-fn
(when (seq mount-bindings)
`(fn [~'this-cmpt ~argv]
(binding-rvals ~mount-bindings)))

?render-rvals-fn
(when (seq render-bindings)
`(fn [~'this-cmpt ~argv ~'this-mounting? ~mount-lvals]
(binding-rvals ~render-bindings)))

render-fn
`(fn [~'this-cmpt ~argv ~'this-mounting? ~mount-lvals ~render-lvals]
~render-body)

?post-render-fn
(when (have-arg? :post-render)
`(fn [~'this-cmpt ~argv ~'this-mounting? ~mount-lvals ~render-lvals]
~(:post-render args-map)))

?unmount-fn
(when (have-arg? :unmount)
`(fn [~'this-cmpt ~argv ~mount-lvals ~render-lvals]
~(:unmount args-map)))]

`(~impl-constructor-fn
~id
~?mount-rvals-fn
~?render-rvals-fn
~render-fn
~?post-render-fn
~?unmount-fn)))

(defmacro def-cmptfn [impl-constructor-fn sym id & sigs]
(let [[sym args] (enc/name-with-attrs sym sigs)]
`(def ~sym
(cmptfn
~impl-constructor-fn
~id ; ~(str *ns* "/" sym ":" (:line (meta &form) "?"))
~@args))))
#?(:clj
(defmacro cmptfn [impl-constructor-fn id params & args]
(let [implicit-render-body? (odd? (count args))
args-map
(if implicit-render-body?
(hash-map-with-unique-ks (butlast args))
(hash-map-with-unique-ks args))

_ (have? [:ks<= #{:let-mount :let-render :render
:post-render :unmount}]
args-map)

_ (when implicit-render-body?
(assert (not (contains? args-map :render))
"Ambiguous render body: provided as both a :render value and implicit final arg"))

have-arg? (set (keys args-map)) ; For existance check w/o val eval
render-body (if implicit-render-body? (last args) (:render args-map))
_ (assert render-body "No (nil) render body provided")

;; [x :x y x]
mount-bindings (:let-mount args-map)
render-bindings (:let-render args-map)

;; [[x y] [:x x]] ; We actually just want the lval forms here
[ mount-lvals _mount-rvals] (split-let-pairs mount-bindings)
[render-lvals _render-rvals] (split-let-pairs render-bindings)

;; Define our cfn lifecycle fns
;; NB We try minimize code expansion size here (esp. gensyms)

argv
(if (seq params)
(into ['__] params) ; [__ x y z ...]
'__)

?mount-rvals-fn
(when (seq mount-bindings)
`(fn [~'this-cmpt ~argv]
(binding-rvals ~mount-bindings)))

?render-rvals-fn
(when (seq render-bindings)
`(fn [~'this-cmpt ~argv ~'this-mounting? ~mount-lvals]
(binding-rvals ~render-bindings)))

render-fn
`(fn [~'this-cmpt ~argv ~'this-mounting? ~mount-lvals ~render-lvals]
~render-body)

?post-render-fn
(when (have-arg? :post-render)
`(fn [~'this-cmpt ~argv ~'this-mounting? ~mount-lvals ~render-lvals]
~(:post-render args-map)))

?unmount-fn
(when (have-arg? :unmount)
`(fn [~'this-cmpt ~argv ~mount-lvals ~render-lvals]
~(:unmount args-map)))]

`(~impl-constructor-fn
~id
~?mount-rvals-fn
~?render-rvals-fn
~render-fn
~?post-render-fn
~?unmount-fn))))

#?(:clj
(defmacro def-cmptfn [impl-constructor-fn sym id & sigs]
(let [[sym args] (enc/name-with-attrs sym sigs)]
`(def ~sym
(cmptfn
~impl-constructor-fn
~id ; ~(str *ns* "/" sym ":" (:line (meta &form) "?"))
~@args)))))
84 changes: 40 additions & 44 deletions src/taoensso/tengen/reagent.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@
"Public API for use with Reagent,
Ref. https://github.com/reagent-project/reagent."
{:author "Peter Taoussanis (@ptaoussanis)"}
(:require
[taoensso.encore :as enc :refer [have have?]]
[taoensso.tengen.common :as common]

#?(:clj
(:require
[taoensso.encore :as enc :refer [have have?]]
[taoensso.tengen.common :as common]))

#?(:cljs
(:require
[taoensso.encore :as enc :refer-macros [have have?]]
[taoensso.tengen.common :as common :refer-macros []]
[reagent.core]
[reagent.dom])))
#?(:cljs [reagent.core])
#?(:cljs [reagent.dom])))

(comment
(enc/declare-remote
Expand Down Expand Up @@ -127,39 +121,41 @@
(catch js/Error e
(throw-cmptfn-error e :unmount id cmpt false))))))))))

(defmacro cmptfn
"Reagent component fn util. Provides a sensible let-flow API for writing
simple, flexible Clj/s Reagent components.
(cmptfn
id ; Component identifier for debugging, error reporting, etc.
[x y] ; Reagent args passed to component
:let-mount [] ; Est. with each instance mount, avail. downstream
:let-render [] ; Est. with each instance render, avail. downstream, pure!
:render <body> ; Or just provide render body as final arg, pure!
:post-render <body> ; For DOM node setup/mutation
:unmount <body> ; For DOM node teardown
)
- Magic bindings: `this-cmpt`, `this-mounting?`.
- Nodes: `[<cmpt> {:ref (fn [node] _)}]` or `(enc/oget ev \"currentTarget\")`.
- Call Reagent components as:
* (<cmpt> <...>) - to get inlining.
* [<cmpt> <...>] - to get an intermediary Reagent component:
* Rerender-iff-args-change semantics.
* Can take ^{:key _} [<cmpt> <...>]."
[id params & args]
`(common/cmptfn taoensso.tengen.reagent/-new-cmptfn
~id ~params ~@args))

(defmacro def-cmptfn
"Defines a top-level Reagent component fn using `cmptfn`.
See the `cmptfn` docstring for more details on args, etc."
[sym & sigs]
`(common/def-cmptfn taoensso.tengen.reagent/-new-cmptfn
~sym
~(str *ns* "/" sym ":" (:line (meta &form) "?"))
~@sigs))
#?(:clj
(defmacro cmptfn
"Reagent component fn util. Provides a sensible let-flow API for writing
simple, flexible Clj/s Reagent components.
(cmptfn
id ; Component identifier for debugging, error reporting, etc.
[x y] ; Reagent args passed to component
:let-mount [] ; Est. with each instance mount, avail. downstream
:let-render [] ; Est. with each instance render, avail. downstream, pure!
:render <body> ; Or just provide render body as final arg, pure!
:post-render <body> ; For DOM node setup/mutation
:unmount <body> ; For DOM node teardown
)
- Magic bindings: `this-cmpt`, `this-mounting?`.
- Nodes: `[<cmpt> {:ref (fn [node] _)}]` or `(enc/oget ev \"currentTarget\")`.
- Call Reagent components as:
* (<cmpt> <...>) - to get inlining.
* [<cmpt> <...>] - to get an intermediary Reagent component:
* Rerender-iff-args-change semantics.
* Can take ^{:key _} [<cmpt> <...>]."
[id params & args]
`(common/cmptfn taoensso.tengen.reagent/-new-cmptfn
~id ~params ~@args)))

#?(:clj
(defmacro def-cmptfn
"Defines a top-level Reagent component fn using `cmptfn`.
See the `cmptfn` docstring for more details on args, etc."
[sym & sigs]
`(common/def-cmptfn taoensso.tengen.reagent/-new-cmptfn
~sym
~(str *ns* "/" sym ":" (:line (meta &form) "?"))
~@sigs)))

(comment
(macroexpand '(cmptfn :id [x] [:div x]))
Expand Down

0 comments on commit bb9b02c

Please sign in to comment.