Browse files

CLJS-647: Evaluate expressions for js-obj keys

JS objects are constructed in three phases. First, an object is
constructed using all key-value pairs with string literals as
their keys. Second, object keys are set for the key-value pairs
with symbols as their keys. Lastly, remaining key-value pairs
are let-bound, evaluated, and their keys are set via the
let-bound gensyms.
  • Loading branch information...
1 parent 0e427a0 commit 7a912f32c7d26eb171862db03acd7184074c620b @thieman thieman committed with swannodette Nov 10, 2013
Showing with 30 additions and 3 deletions.
  1. +22 −3 src/clj/cljs/core.clj
  2. +8 −0 test/cljs/cljs/core_test.cljs
View
25 src/clj/cljs/core.clj
@@ -33,6 +33,7 @@
cond-> cond->> as-> some-> some->>])
(:require clojure.walk
+ clojure.set
cljs.compiler
[cljs.env :as env]))
@@ -1318,12 +1319,30 @@
([& xs]
`(set (array ~@xs))))
-(defmacro js-obj [& rest]
+(defn js-obj* [kvs]
(let [kvs-str (->> (repeat "~{}:~{}")
- (take (quot (count rest) 2))
+ (take (count kvs))
(interpose ",")
(apply core/str))]
- (list* 'js* (core/str "{" kvs-str "}") rest)))
+ (list* 'js* (core/str "{" kvs-str "}") (apply concat kvs))))
+
+(defmacro js-obj [& rest]
+ (let [sym-or-str? (fn [x] (core/or (core/symbol? x) (core/string? x)))
+ filter-on-keys (fn [f coll]
+ (->> coll
+ (filter (fn [[k _]] (f k)))
+ (into {})))
+ kvs (into {} (map vec (partition 2 rest)))
+ sym-pairs (filter-on-keys core/symbol? kvs)
+ expr->local (zipmap
+ (filter (complement sym-or-str?) (keys kvs))
+ (repeatedly gensym))
+ obj (gensym "obj")]
+ `(let [~@(apply concat (clojure.set/map-invert expr->local))
+ ~obj ~(js-obj* (filter-on-keys core/string? kvs))]
+ ~@(map (fn [[k v]] `(aset ~obj ~k ~v)) sym-pairs)
+ ~@(map (fn [[k v]] `(aset ~obj ~v ~(core/get kvs k))) expr->local)
+ ~obj)))
(defmacro alength [a]
(core/list 'js* "~{}.length" a))
View
8 test/cljs/cljs/core_test.cljs
@@ -1994,5 +1994,13 @@
(assert (= (keyword 123) nil))
(assert (= (keyword (js/Date.)) nil))
+ ;; CLJS-647
+ (let [keys #(vec (js-keys %))
+ z "x"]
+ (assert (= ["x"]
+ (keys (js-obj "x" "y"))
+ (keys (js-obj (identity "x") "y"))
+ (keys (js-obj z "y")))))
+
:ok
)

0 comments on commit 7a912f3

Please sign in to comment.