diff --git a/src/clj/com/rpl/specter/impl.cljx b/src/clj/com/rpl/specter/impl.cljx index e30c5af..617a01b 100644 --- a/src/clj/com/rpl/specter/impl.cljx +++ b/src/clj/com/rpl/specter/impl.cljx @@ -857,21 +857,23 @@ ))) #+clj -(defn mk-params-maker [params-code possible-params-code used-locals] - (let [array-sym (gensym "array")] - (eval - `(fn [~@used-locals] - (let [~array-sym (fast-object-array ~(count params-code))] - ~@(map-indexed - (fn [i c] - `(aset ~array-sym ~i ~c)) - params-code - ) - ~array-sym - ))))) +(defn mk-params-maker [ns-str params-code possible-params-code used-locals] + (let [ns (find-ns (symbol ns-str)) + array-sym (gensym "array")] + (binding [*ns* ns] + (eval + `(fn [~@used-locals] + (let [~array-sym (fast-object-array ~(count params-code))] + ~@(map-indexed + (fn [i c] + `(aset ~array-sym ~i ~c)) + params-code + ) + ~array-sym + )))))) #+cljs -(defn mk-params-maker [params-code possible-params-code used-locals] +(defn mk-params-maker [ns-str params-code possible-params-code used-locals] (let [indexed (->> possible-params-code (map-indexed (comp vec reverse vector)) (into {}))] @@ -879,7 +881,7 @@ (mapv (fn [c] (get indexed c)) params-code))) ;; possible-params-code is for cljs impl that can't use eval -(defn magic-precompilation [prepared-path used-locals possible-params-code] +(defn magic-precompilation [prepared-path ns-str used-locals possible-params-code] (let [params-atom (atom []) failed-atom (atom false) path (magic-precompilation* prepared-path params-atom failed-atom) @@ -891,7 +893,7 @@ (let [precompiled (comp-paths* path) params-code (mapv extract-original-code @params-atom) params-maker (if-not (empty? params-code) - (mk-params-maker params-code possible-params-code used-locals)) + (mk-params-maker ns-str params-code possible-params-code used-locals)) ] ;; TODO: error if precompiled is compiledpath and there are params or ;; precompiled is paramsneededpath and there are no params... diff --git a/src/clj/com/rpl/specter/macros.clj b/src/clj/com/rpl/specter/macros.clj index 652ad88..d9f236b 100644 --- a/src/clj/com/rpl/specter/macros.clj +++ b/src/clj/com/rpl/specter/macros.clj @@ -319,7 +319,7 @@ `(def ~name (vary-meta (fn ~@args) assoc :pathedfn true)))) (defmacro defnavconstructor [name & args] - (let [[name [anav & body-or-bodies]] (m/name-with-attributes name args) + (let [[name [[csym anav] & body-or-bodies]] (m/name-with-attributes name args) bodies (if (-> body-or-bodies first vector?) [body-or-bodies] body-or-bodies) checked-code @@ -330,11 +330,13 @@ (if (i/layered-nav? ret#) (i/layered-nav-underlying ret#) (i/throw-illegal "Expected result navigator '" (quote ~anav) - "' from nav constructor '" (quote ~name) "'")) + "' from nav constructor '" (quote ~name) "'" + " constructed with the provided constructor '" (quote ~csym) + "'")) ))))] `(def ~name (vary-meta - (let [~anav (i/layered-wrapper ~anav)] + (let [~csym (i/layered-wrapper ~anav)] (fn ~@checked-code)) assoc :layerednav true)) )) @@ -428,6 +430,7 @@ (if (nil? info#) (let [info# (i/magic-precompilation ~prepared-path + ~(str *ns*) (quote ~used-locals) ;;possible-params is wrong atm ;;as is used-locals in cljs... diff --git a/test/com/rpl/specter/core_test.cljx b/test/com/rpl/specter/core_test.cljx index 9f42edc..e207419 100644 --- a/test/com/rpl/specter/core_test.cljx +++ b/test/com/rpl/specter/core_test.cljx @@ -7,7 +7,7 @@ [com.rpl.specter.macros :refer [paramsfn defprotocolpath defnav extend-protocolpath nav declarepath providepath select select-one select-one! - select-first transform setval replace-in]]) + select-first transform setval replace-in defnavconstructor]]) (:use #+clj [clojure.test :only [deftest is]] #+clj [clojure.test.check.clojure-test :only [defspec]] @@ -15,7 +15,7 @@ #+clj [com.rpl.specter.macros :only [paramsfn defprotocolpath defnav extend-protocolpath nav declarepath providepath select select-one select-one! - select-first transform setval replace-in]] + select-first transform setval replace-in defnavconstructor]] ) @@ -859,6 +859,27 @@ (= q1 q2) (= (type q1) (type q2)))))) +(defnavconstructor double-str-keypath + [p s/keypath] + [s1 s2] + (p (str s1 s2))) + +(defnavconstructor some-keypath + [p s/keypath] + ([] (p "a")) + ([k1] (p (str k1 "!"))) + ([k & args] (p "bbb"))) + +(deftest nav-constructor-test + ;; this also tests that the eval done by clj platform during inline + ;; caching rebinds to the correct namespace since this is run + ;; by clojure.test in a different namespace + (is (= 1 (select-one! (double-str-keypath "a" "b") {"ab" 1 "c" 2}))) + (is (= 1 (select-one! (some-keypath) {"a" 1 "a!" 2 "bbb" 3 "d" 4}))) + (is (= 2 (select-one! (some-keypath "a") {"a" 1 "a!" 2 "bbb" 3 "d" 4}))) + (is (= 3 (select-one! (some-keypath 1 2 3 4 5) {"a" 1 "a!" 2 "bbb" 3 "d" 4}))) + ) + (def ^:dynamic *APATH* s/keypath) (deftest inline-caching-test @@ -883,6 +904,13 @@ inc {:a 1 :b 2} [[true] [false]]) + (ic-test + true + [v] + [s/ALL (double-str-keypath v (inc v))] + str + [{"12" :a "1011" :b} {"1011" :c}] + [[1] [10]]) (ic-test false [k]