Skip to content

Commit

Permalink
Improve dev UX with proper function arglists (#4)
Browse files Browse the repository at this point in the history
* Prefer to use original params vector

For the common case, this produces smaller, more efficient javascript,
and also automatically gives us a useful arglist in the function docs.
However, it won't work if there's any destructuring in the params
vector.

* Handle variadic and destructured arglists

This certainly adds some complexity, but since it's all handled
at compile time, so there's no overhead at runtime. It also means
that in the general cases you can get better experiences, but we
still support the fancy case if anybody wants to do that.

* Fix variadic support with correct cond cordering
  • Loading branch information
dhleong authored Aug 28, 2019
1 parent c24cbea commit 43da869
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 8 deletions.
45 changes: 38 additions & 7 deletions src/spade/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -95,34 +95,65 @@
(transform-named-style style style-name-var params-var))))

(defmulti ^:private declare-style
(fn [mode _class-name _factory-name-var _factory-fn-name]
(fn [mode _class-name params _factory-name-var _factory-fn-name]
(case mode
:global :static
:keyframes :no-args
:default)))
(cond
(some #{'&} params) :variadic
(every? symbol? params) :default
:else :destructured))))
(defmethod declare-style :static
[mode class-name factory-name-var factory-fn-name]
[mode class-name _ factory-name-var factory-fn-name]
`(def ~class-name (spade.runtime/ensure-style!
~mode
~factory-name-var
~factory-fn-name
nil)))
(defmethod declare-style :no-args
[mode class-name factory-name-var factory-fn-name]
[mode class-name _ factory-name-var factory-fn-name]
`(defn ~class-name []
(spade.runtime/ensure-style!
~mode
~factory-name-var
~factory-fn-name
nil)))
(defmethod declare-style :default
[mode class-name factory-name-var factory-fn-name]
(defmethod declare-style :destructured
[mode class-name params factory-name-var factory-fn-name]
; good case; since there's no variadic args, we can generate an :arglists
; meta and a simplified params list that we can forward simply
(let [raw-params (->> (range (count params))
(map (fn [idx]
(gensym (str "param-" idx "-"))))
vec)]
`(defn ~class-name
{:arglists (quote ~(list params))}
~raw-params
(spade.runtime/ensure-style!
~mode
~factory-name-var
~factory-fn-name
~raw-params))))
(defmethod declare-style :variadic
[mode class-name _params factory-name-var factory-fn-name]
; dumb case; with a variadic params vector, any :arglists we
; provide gets ignored, so we just simply collect them all
; and pass the list as-is
`(defn ~class-name [& params#]
(spade.runtime/ensure-style!
~mode
~factory-name-var
~factory-fn-name
params#)))
(defmethod declare-style :default
[mode class-name params factory-name-var factory-fn-name]
; best case; simple params means we can use them directly
`(defn ~class-name ~params
(spade.runtime/ensure-style!
~mode
~factory-name-var
~factory-fn-name
~params)))

(defn- declare-style-fns [mode class-name params style]
{:pre [(symbol? class-name)
Expand All @@ -138,7 +169,7 @@
~(transform-style mode style style-name-var params-var))

(let [~factory-name-var (factory->name ~factory-fn-name)]
~(declare-style mode class-name factory-name-var factory-fn-name)))))
~(declare-style mode class-name params factory-name-var factory-fn-name)))))

(defmacro defclass [class-name params & style]
(declare-style-fns :class class-name params style))
Expand Down
33 changes: 32 additions & 1 deletion test/spade/core_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,35 @@
(is (true? (str/includes? generated
"background:"))))))


(defclass destructured [{:keys [c b]}]
^{:key (str c "_" b)}
{:color c
:background b})

(defn foo {:arglists '([a b c])}
[& args]
(println args))

(deftest function-meta-test
(testing "Simple arglists"
(is (= '([color])
(:arglists (meta #'params))))
(is (= '([])
(:arglists (meta #'fixed-style-attrs)))))

(testing "Destructuring arglists"
(is (= '([{:keys [c b]}])
(:arglists (meta #'destructured))))))

(defclass variadic [& others]
^{:key (str/join others)}
{:content (str others)})

(deftest destructuring-factory-test
(testing "Destructure args"
(is (= "spade-core-test-destructured_blue_red"
(destructured {:c "blue" :b "red"}))))

(testing "Don't barf on Variadic args"
(is (= "spade-core-test-variadic_cyanmagentayellow"
(variadic "cyan" "magenta" "yellow")))))

0 comments on commit 43da869

Please sign in to comment.