diff --git a/project.clj b/project.clj index 4b124a2..fc09529 100644 --- a/project.clj +++ b/project.clj @@ -1,9 +1,9 @@ (def VERSION (.trim (slurp "VERSION"))) (defproject com.rpl/specter VERSION - :jvm-opts ["-XX:-OmitStackTraceInFastThrow" ; this prevents JVM from doing optimizations which can remove stack traces from NPE and other exceptions - ;"-agentpath:/Applications/YourKit_Java_Profiler_2015_build_15056.app/Contents/Resources/bin/mac/libyjpagent.jnilib" - ] + :jvm-opts ["-XX:-OmitStackTraceInFastThrow"] ; this prevents JVM from doing optimizations which can remove stack traces from NPE and other exceptions + ;"-agentpath:/Applications/YourKit_Java_Profiler_2015_build_15056.app/Contents/Resources/bin/mac/libyjpagent.jnilib"] + :source-paths ["src/clj"] :java-source-paths ["src/java"] :test-paths ["test", "target/test-classes"] @@ -18,15 +18,14 @@ com.rpl.specter.transients] :source-uri {#"target/classes" "https://github.com/nathanmarz/specter/tree/{version}/src/clj/{classpath}x#L{line}" - #".*" "https://github.com/nathanmarz/specter/tree/{version}/src/clj/{classpath}#L{line}" - } - } + #".*" "https://github.com/nathanmarz/specter/tree/{version}/src/clj/{classpath}#L{line}"}} + + :profiles {:dev {:dependencies [[org.clojure/test.check "0.7.0"] [org.clojure/clojure "1.7.0"] - [org.clojure/clojurescript "1.7.10"]] - } - :test {:dependencies [[org.clojure/clojure "1.7.0"]]} - } - :aliases {"deploy" ["do" "clean," "deploy" "clojars"]} - ) + [org.clojure/clojurescript "1.7.10"]]} + + :test {:dependencies [[org.clojure/clojure "1.7.0"]]}} + + :aliases {"deploy" ["do" "clean," "deploy" "clojars"]}) diff --git a/repl.clj b/repl.clj index c472bca..edf3e91 100644 --- a/repl.clj +++ b/repl.clj @@ -6,13 +6,13 @@ {:output-to "out/main.js" :verbose true :warning-handlers [(fn [warning-type env extra] - (when (warning-type cljs.analyzer/*cljs-warnings*) - (when-let [s (cljs.analyzer/error-message warning-type extra)] - (binding [*out* *err*] - (println "WARNING:" (cljs.analyzer/message env s)) - (println "Failed to build because of warning!") - ) - (System/exit 1))))]}) + (when (warning-type cljs.analyzer/*cljs-warnings*) + (when-let [s (cljs.analyzer/error-message warning-type extra)] + (binding [*out* *err*] + (println "WARNING:" (cljs.analyzer/message env s)) + (println "Failed to build because of warning!")) + + (System/exit 1))))]}) (cljs.repl/repl (cljs.repl.node/repl-env) :watch "target/classes/com/rpl" diff --git a/scripts/benchmarks.clj b/scripts/benchmarks.clj index e1cc633..ebc4ad7 100644 --- a/scripts/benchmarks.clj +++ b/scripts/benchmarks.clj @@ -3,8 +3,8 @@ [com.rpl.specter macros] [com.rpl.specter.transients] [com.rpl.specter.impl :only [benchmark]]) - (:require [clojure.walk :as walk]) - ) + (:require [clojure.walk :as walk])) + ;; run via `lein repl` with `(load-file "scripts/benchmarks.clj")` @@ -19,8 +19,8 @@ (let [start (System/nanoTime) _ (dotimes [_ amt] (afn)) end (System/nanoTime)] - (/ (- end start) 1000000.0) - )) + (/ (- end start) 1000000.0))) + (defn avg [numbers] (/ (reduce + numbers) @@ -41,20 +41,20 @@ (fn [afn] (average-time-ms 8 amt-per-iter afn)) afn-map) - [[_ best-time] & _ :as sorted] (sort-by last results) - ] + [[_ best-time] & _ :as sorted] (sort-by last results)] + (println "\nAvg(ms)\t\tvs best\t\tCode") (doseq [[k t] sorted] - (println (pretty-float5 t) "\t\t" (pretty-float3 (/ t best-time 1.0)) "\t\t" k) - ))) + (println (pretty-float5 t) "\t\t" (pretty-float3 (/ t best-time 1.0)) "\t\t" k)))) + (defmacro run-benchmark [name amt-per-iter & exprs] (let [afn-map (->> exprs shuffle (map (fn [e] [`(quote ~e) `(fn [] ~e)])) (into {}))] `(do (println "Benchmark:" ~name (str "(" ~amt-per-iter " iterations)")) (compare-benchmark ~amt-per-iter ~afn-map) - (println "\n********************************\n") - ))) + (println "\n********************************\n")))) + (let [data {:a {:b {:c 1}}} p (comp-paths :a :b :c)] @@ -66,8 +66,8 @@ (compiled-select-any p data) (get-in data [:a :b :c]) (-> data :a :b :c) - (select-any [(keypath :a) (keypath :b) (keypath :c)] data) - )) + (select-any [(keypath :a) (keypath :b) (keypath :c)] data))) + ;; because below 1.7 there is no update function @@ -85,8 +85,8 @@ (run-benchmark "update value in nested map" 500000 (update-in data [:a :b :c] inc) (transform [:a :b :c] inc data) - (manual-transform data inc) - )) + (manual-transform data inc))) + (defn map-vals-map-iterable [^clojure.lang.IMapIterable m afn] (let [k-it (.keyIterator m) @@ -95,10 +95,10 @@ (if (.hasNext k-it) (let [k (.next k-it) v (.next v-it)] - (recur (assoc ret k (afn v))) - ) - ret - )))) + (recur (assoc ret k (afn v)))) + + ret)))) + (defn map-vals-map-iterable-transient [^clojure.lang.IMapIterable m afn] (persistent! @@ -108,10 +108,10 @@ (if (.hasNext k-it) (let [k (.next k-it) v (.next v-it)] - (recur (assoc! ret k (afn v))) - ) - ret - ))))) + (recur (assoc! ret k (afn v)))) + + ret))))) + (let [data {:a 1 :b 2 :c 3 :d 4}] (run-benchmark "transform values of a small map" 500000 @@ -124,8 +124,8 @@ (zipmap (keys data) (map inc (vals data))) (into {} (map (fn [e] [(key e) (inc (val e))]) data)) (map-vals-map-iterable data inc) - (map-vals-map-iterable-transient data inc) - )) + (map-vals-map-iterable-transient data inc))) + (let [data (->> (for [i (range 1000)] [i i]) (into {}))] (run-benchmark "transform values of large map" 600 @@ -139,23 +139,23 @@ (zipmap (keys data) (map inc (vals data))) (into {} (map (fn [e] [(key e) (inc (val e))]) data)) (map-vals-map-iterable data inc) - (map-vals-map-iterable-transient data inc) - )) + (map-vals-map-iterable-transient data inc))) + (let [data [1 2 3 4 5]] (run-benchmark "map a function over a vector" 1000000 (vec (map inc data)) (mapv inc data) - (transform ALL inc data) - )) + (transform ALL inc data))) + (let [data [1 2 3 4 5 6 7 8 9 10]] (run-benchmark "filter a sequence" 500000 (doall (filter even? data)) (filterv even? data) (select [ALL even?] data) - (select-any (filterer even?) data) - )) + (select-any (filterer even?) data))) + (let [data [{:a 2 :b 2} {:a 1} {:a 4} {:a 6}] xf (comp (map :a) (filter even?))] @@ -163,8 +163,8 @@ (select [ALL :a even?] data) (->> data (mapv :a) (filter even?) doall) (into [] (comp (map :a) (filter even?)) data) - (into [] xf data) - )) + (into [] xf data))) + (let [v (vec (range 1000))] (run-benchmark "END on large vector" @@ -191,8 +191,8 @@ (defn tree-value-transform [afn atree] (if (vector? atree) (mapv #(tree-value-transform afn %) atree) - (afn atree) - )) + (afn atree))) + (let [data [1 2 [[3]] [4 6 [7 [8]] 10]]] (run-benchmark "update every value in a tree (represented with vectors)" @@ -201,8 +201,8 @@ (transform [(walker number?) even?] inc data) (transform [TreeValues even?] inc data) (transform [TreeValuesProt even?] inc data) - (tree-value-transform (fn [e] (if (even? e) (inc e) e)) data) - )) + (tree-value-transform (fn [e] (if (even? e) (inc e) e)) data))) + (let [toappend (range 1000)] (run-benchmark "transient comparison: building up vectors" @@ -218,8 +218,8 @@ (reduce (fn [v i] (conj v i)) [] toappend) (reduce (fn [v i] (conj! v i)) (transient []) toappend) (reduce (fn [v i] (setval END [i] v)) [] toappend) - (reduce (fn [v i] (setval END! [i] v)) (transient []) toappend) - )) + (reduce (fn [v i] (setval END! [i] v)) (transient []) toappend))) + (let [data (vec (range 1000)) tdata (transient data) @@ -280,19 +280,18 @@ (into #{} (traverse ALL data)) (persistent! (reduce conj! (transient #{}) (traverse ALL data))) - (reduce conj #{} (traverse ALL data)) - )) + (reduce conj #{} (traverse ALL data)))) + (defn mult-10 [v] (* 10 v)) (let [data [1 2 3 4 5 6 7 8 9]] (run-benchmark "multi-transform vs. consecutive transforms, one shared nav" 300000 (->> data (transform [ALL even?] mult-10) (transform [ALL odd?] dec)) - (multi-transform [ALL (multi-path [even? (terminal mult-10)] [odd? (terminal dec)])] data) - )) + (multi-transform [ALL (multi-path [even? (terminal mult-10)] [odd? (terminal dec)])] data))) + (let [data [[1 2 3 4 :a] [5] [6 7 :b 8 9] [10 11 12 13]]] (run-benchmark "multi-transform vs. consecutive transforms, three shared navs" 150000 (->> data (transform [ALL ALL number? even?] mult-10) (transform [ALL ALL number? odd?] dec)) - (multi-transform [ALL ALL number? (multi-path [even? (terminal mult-10)] [odd? (terminal dec)])] data) - )) + (multi-transform [ALL ALL number? (multi-path [even? (terminal mult-10)] [odd? (terminal dec)])] data))) diff --git a/src/clj/com/rpl/specter.cljc b/src/clj/com/rpl/specter.cljc index f68bcfd..d5458bf 100644 --- a/src/clj/com/rpl/specter.cljc +++ b/src/clj/com/rpl/specter.cljc @@ -8,11 +8,11 @@ defnav defpathedfn richnav - defnavconstructor - ]] + defnavconstructor]] + [com.rpl.specter.util-macros :refer - [doseqres]] - )) + [doseqres]])) + (:use [com.rpl.specter.protocols :only [ImplicitNav]] #?(:clj [com.rpl.specter.macros :only [fixed-pathed-collector @@ -22,12 +22,12 @@ defpathedfn richnav defnavconstructor]]) - #?(:clj [com.rpl.specter.util-macros :only [doseqres]]) - ) + #?(:clj [com.rpl.specter.util-macros :only [doseqres]])) + (:require [com.rpl.specter.impl :as i] [com.rpl.specter.navs :as n] - [clojure.set :as set]) - ) + [clojure.set :as set])) + (defn comp-paths "Returns a compiled version of the given path for use with @@ -177,8 +177,8 @@ (select* [this params params-idx vals structure next-fn] (i/exec-rich-select* nav params (- params-idx needed) vals structure next-fn)) (transform* [this params params-idx vals structure next-fn] - (i/exec-rich-transform* nav params (- params-idx needed) vals structure next-fn) - )))) + (i/exec-rich-transform* nav params (- params-idx needed) vals structure next-fn))))) + ;; Built-in pathing and context operations @@ -188,10 +188,10 @@ STOP [] (select* [this structure next-fn] - NONE ) + NONE) (transform* [this structure next-fn] - structure - )) + structure)) + (defnav @@ -213,8 +213,8 @@ (select* [this params params-idx vals structure next-fn] (i/throw-illegal "'terminal' should only be used in multi-transform")) (transform* [this params params-idx vals structure next-fn] - (n/terminal* params params-idx vals structure) - ))) + (n/terminal* params params-idx vals structure)))) + (defnavconstructor terminal-val "Like `terminal` but specifies a val to set at the location regardless of @@ -240,11 +240,11 @@ [] (select* [this structure next-fn] (doseqres NONE [v (vals structure)] - (next-fn v) - )) + (next-fn v))) + (transform* [this structure next-fn] - (n/map-vals-transform structure next-fn) - )) + (n/map-vals-transform structure next-fn))) + (defcollector VAL [] @@ -271,8 +271,8 @@ (select* [this structure next-fn] (n/srange-select structure (start-fn structure) (end-fn structure) next-fn)) (transform* [this structure next-fn] - (n/srange-transform structure (start-fn structure) (end-fn structure) next-fn) - )) + (n/srange-transform structure (start-fn structure) (end-fn structure) next-fn))) + (defnav ^{:doc "Navigates to the subsequence bound by the indexes start (inclusive) @@ -282,8 +282,8 @@ (select* [this structure next-fn] (n/srange-select structure start end next-fn)) (transform* [this structure next-fn] - (n/srange-transform structure start end next-fn) - )) + (n/srange-transform structure start end next-fn))) + (defnav ^{:doc "Navigates to every continuous subsequence of elements matching `pred`"} @@ -291,15 +291,15 @@ [pred] (select* [this structure next-fn] (doseqres NONE [[s e] (n/matching-ranges structure pred)] - (n/srange-select structure s e next-fn) - )) + (n/srange-select structure s e next-fn))) + (transform* [this structure next-fn] (reduce (fn [structure [s e]] (n/srange-transform structure s e next-fn)) structure - (reverse (n/matching-ranges structure pred)) - ))) + (reverse (n/matching-ranges structure pred))))) + (defnav ^{:doc "Navigate to the empty subsequence before the first element of the collection."} @@ -309,8 +309,8 @@ (next-fn [])) (transform* [this structure next-fn] (let [to-prepend (next-fn [])] - (n/prepend-all structure to-prepend) - ))) + (n/prepend-all structure to-prepend)))) + (defnav ^{:doc "Navigate to the empty subsequence after the last element of the collection."} @@ -320,8 +320,8 @@ (next-fn [])) (transform* [this structure next-fn] (let [to-append (next-fn [])] - (n/append-all structure to-append) - ))) + (n/append-all structure to-append)))) + (defnav ^{:doc "Navigates to the specified subset (by taking an intersection). @@ -336,8 +336,8 @@ newset (next-fn subset)] (-> structure (set/difference subset) - (set/union newset)) - ))) + (set/union newset))))) + (defnav ^{:doc "Navigates to the specified submap (using select-keys). @@ -401,8 +401,8 @@ (select* [this structure next-fn] (next-fn (get structure key))) (transform* [this structure next-fn] - (assoc structure key (next-fn (get structure key))) - )) + (assoc structure key (next-fn (get structure key))))) + (defnav ^{:doc "Navigates to the key only if it exists in the map."} @@ -415,8 +415,8 @@ (transform* [this structure next-fn] (if (contains? structure k) (assoc structure k (next-fn (get structure k))) - structure - ))) + structure))) + (defnav ^{:doc "Navigates to result of running `afn` on the currently navigated value."} @@ -425,8 +425,8 @@ (select* [this structure next-fn] (next-fn (afn structure))) (transform* [this structure next-fn] - (next-fn (afn structure)) - )) + (next-fn (afn structure)))) + (defnav ^{:doc "Navigate to the result of running `parse-fn` on the value. For @@ -437,8 +437,8 @@ (select* [this structure next-fn] (next-fn (parse-fn structure))) (transform* [this structure next-fn] - (unparse-fn (next-fn (parse-fn structure))) - )) + (unparse-fn (next-fn (parse-fn structure))))) + (defnav ^{:doc "Navigates to atom value."} @@ -522,8 +522,8 @@ (select* [this structure next-fn] (if (afn structure) (next-fn structure) NONE)) (transform* [this structure next-fn] - (if (afn structure) (next-fn structure) structure)) - ) + (if (afn structure) (next-fn structure) structure))) + (extend-type nil ImplicitNav @@ -531,8 +531,8 @@ (extend-type #?(:clj clojure.lang.Keyword :cljs cljs.core/Keyword) ImplicitNav - (implicit-nav [this] (keypath this)) - ) + (implicit-nav [this] (keypath this))) + (extend-type #?(:clj clojure.lang.AFn :cljs function) ImplicitNav @@ -586,8 +586,8 @@ [& path] (fixed-pathed-collector [late path] (collect-val [this structure] - (compiled-select late structure) - ))) + (compiled-select late structure)))) + (defpathedfn ^{:doc "Adds the result of running select-one with the given path on the @@ -596,8 +596,8 @@ [& path] (fixed-pathed-collector [late path] (collect-val [this structure] - (compiled-select-one late structure) - ))) + (compiled-select-one late structure)))) + (defcollector ^{:doc @@ -610,7 +610,7 @@ putval [val] (collect-val [this structure] - val )) + val)) (def ^{:doc "Drops all collected values for subsequent navigation."} @@ -620,69 +620,69 @@ (defpathedfn if-path "Like cond-path, but with if semantics." ([cond-p then-path] - (if-path cond-p then-path STOP)) + (if-path cond-p then-path STOP)) ([cond-p then-path else-path] - (let [then-comp (i/comp-paths-internalized then-path) - else-comp (i/comp-paths-internalized else-path) - then-needed (i/num-needed-params then-comp) - else-needed (i/num-needed-params else-comp) - then-nav (i/extract-rich-nav then-comp) - else-nav (i/extract-rich-nav else-comp)] - (if-let [afn (n/extract-basic-filter-fn cond-p)] - (richnav (+ then-needed else-needed) - (select* [this params params-idx vals structure next-fn] - (n/if-select - params - params-idx - vals - structure - next-fn - afn - then-nav - then-needed - else-nav - )) - (transform* [this params params-idx vals structure next-fn] - (n/if-transform - params - params-idx - vals - structure - next-fn - afn - then-nav - then-needed - else-nav - )))) - (let [cond-comp (i/comp-paths-internalized cond-p) - cond-needed (i/num-needed-params cond-comp)] - (richnav (+ then-needed else-needed cond-needed) - (select* [this params params-idx vals structure next-fn] - (let [late-cond (i/parameterize-path cond-comp params params-idx)] - (n/if-select - params - (+ params-idx cond-needed) - vals - structure - next-fn - #(n/selected?* late-cond %) - then-nav - then-needed - else-nav - ))) - (transform* [this params params-idx vals structure next-fn] - (let [late-cond (i/parameterize-path cond-comp params params-idx)] - (n/if-transform - params - (+ params-idx cond-needed) - vals - structure - next-fn - #(n/selected?* late-cond %) - then-nav - then-needed - else-nav - )))))))) + (let [then-comp (i/comp-paths-internalized then-path) + else-comp (i/comp-paths-internalized else-path) + then-needed (i/num-needed-params then-comp) + else-needed (i/num-needed-params else-comp) + then-nav (i/extract-rich-nav then-comp) + else-nav (i/extract-rich-nav else-comp)] + (if-let [afn (n/extract-basic-filter-fn cond-p)] + (richnav (+ then-needed else-needed) + (select* [this params params-idx vals structure next-fn] + (n/if-select + params + params-idx + vals + structure + next-fn + afn + then-nav + then-needed + else-nav)) + + (transform* [this params params-idx vals structure next-fn] + (n/if-transform + params + params-idx + vals + structure + next-fn + afn + then-nav + then-needed + else-nav)))) + + (let [cond-comp (i/comp-paths-internalized cond-p) + cond-needed (i/num-needed-params cond-comp)] + (richnav (+ then-needed else-needed cond-needed) + (select* [this params params-idx vals structure next-fn] + (let [late-cond (i/parameterize-path cond-comp params params-idx)] + (n/if-select + params + (+ params-idx cond-needed) + vals + structure + next-fn + #(n/selected?* late-cond %) + then-nav + then-needed + else-nav))) + + (transform* [this params params-idx vals structure next-fn] + (let [late-cond (i/parameterize-path cond-comp params params-idx)] + (n/if-transform + params + (+ params-idx cond-needed) + vals + structure + next-fn + #(n/selected?* late-cond %) + then-nav + then-needed + else-nav)))))))) + (defpathedfn cond-path "Takes in alternating cond-path path cond-path path... @@ -700,8 +700,8 @@ (fn [p [tester apath]] (if-path tester apath p)) STOP - pairs - ))) + pairs))) + (defpathedfn multi-path "A path that branches on multiple paths. For updates, @@ -709,27 +709,27 @@ ([] STAY) ([path] (i/comp-paths* path)) ([path1 path2] - (let [comp1 (i/comp-paths-internalized path1) - comp2 (i/comp-paths-internalized path2) - comp1-needed (i/num-needed-params comp1) - nav1 (i/extract-rich-nav comp1) - nav2 (i/extract-rich-nav comp2) - ] - (richnav (+ comp1-needed (i/num-needed-params comp2)) - (select* [this params params-idx vals structure next-fn] - (let [res1 (i/exec-rich-select* nav1 params params-idx vals structure next-fn) - res2 (i/exec-rich-select* nav2 params (+ params-idx comp1-needed) vals structure next-fn)] - (if (identical? NONE res2) - res1 - res2 - ))) - (transform* [this params params-idx vals structure next-fn] - (let [s1 (i/exec-rich-transform* nav1 params params-idx vals structure next-fn)] - (i/exec-rich-transform* nav2 params (+ params-idx comp1-needed) vals s1 next-fn) - ))))) + (let [comp1 (i/comp-paths-internalized path1) + comp2 (i/comp-paths-internalized path2) + comp1-needed (i/num-needed-params comp1) + nav1 (i/extract-rich-nav comp1) + nav2 (i/extract-rich-nav comp2)] + + (richnav (+ comp1-needed (i/num-needed-params comp2)) + (select* [this params params-idx vals structure next-fn] + (let [res1 (i/exec-rich-select* nav1 params params-idx vals structure next-fn) + res2 (i/exec-rich-select* nav2 params (+ params-idx comp1-needed) vals structure next-fn)] + (if (identical? NONE res2) + res1 + res2))) + + (transform* [this params params-idx vals structure next-fn] + (let [s1 (i/exec-rich-transform* nav1 params params-idx vals structure next-fn)] + (i/exec-rich-transform* nav2 params (+ params-idx comp1-needed) vals s1 next-fn)))))) + ([path1 path2 & paths] - (reduce multi-path (multi-path path1 path2) paths) - )) + (reduce multi-path (multi-path path1 path2) paths))) + (defpathedfn stay-then-continue "Navigates to the current element and then navigates via the provided path. diff --git a/src/clj/com/rpl/specter/defhelpers.clj b/src/clj/com/rpl/specter/defhelpers.clj index e45eed7..173692e 100644 --- a/src/clj/com/rpl/specter/defhelpers.clj +++ b/src/clj/com/rpl/specter/defhelpers.clj @@ -11,10 +11,9 @@ `(~invoke-name [this# ~@args] (let [~a (~(if clj? 'com.rpl.specter.impl/fast-object-array 'object-array) ~i)] ~@setters - (com.rpl.specter.impl/bind-params* this# ~a 0) - )))] + (com.rpl.specter.impl/bind-params* this# ~a 0))))] + `(defrecord ~'ParamsNeededPath [~'rich-nav ~'num-needed-params] ~fn-type ~@impls - ~var-arity-impl - ))) + ~var-arity-impl))) diff --git a/src/clj/com/rpl/specter/defnavhelpers.cljc b/src/clj/com/rpl/specter/defnavhelpers.cljc index ac14b22..5b16560 100644 --- a/src/clj/com/rpl/specter/defnavhelpers.cljc +++ b/src/clj/com/rpl/specter/defnavhelpers.cljc @@ -3,12 +3,11 @@ (defn param-delta [i] (fn [^objects params params-idx] - (aget params (+ params-idx i)) - )) + (aget params (+ params-idx i)))) + (defn bound-params [path start-delta] (fn [^objects params params-idx] (if (i/params-needed-path? path) (i/bind-params* path params (+ params-idx start-delta)) - path - ))) + path))) diff --git a/src/clj/com/rpl/specter/impl.cljc b/src/clj/com/rpl/specter/impl.cljc index 056500c..eb3ba5d 100644 --- a/src/clj/com/rpl/specter/impl.cljc +++ b/src/clj/com/rpl/specter/impl.cljc @@ -1,19 +1,19 @@ (ns com.rpl.specter.impl #?(:cljs (:require-macros [com.rpl.specter.defhelpers :refer [define-ParamsNeededPath]] - [com.rpl.specter.util-macros :refer [doseqres]] - )) + [com.rpl.specter.util-macros :refer [doseqres]])) + (:use [com.rpl.specter.protocols :only [select* transform* collect-val Navigator]] - #?(:clj [com.rpl.specter.util-macros :only [doseqres]]) -) + #?(:clj [com.rpl.specter.util-macros :only [doseqres]])) + (:require [com.rpl.specter.protocols :as p] [clojure.string :as s] #?(:clj [com.rpl.specter.defhelpers :as dh]) - #?(:clj [riddley.walk :as riddley]) - ) - #?(:clj (:import [com.rpl.specter Util MutableCell])) - ) + #?(:clj [riddley.walk :as riddley])) + + #?(:clj (:import [com.rpl.specter Util MutableCell]))) + (def NONE ::NONE) @@ -45,56 +45,56 @@ ([a1 a2 a3 a4 a5 a6 a7 a8] v) ([a1 a2 a3 a4 a5 a6 a7 a8 a9] v) ([a1 a2 a3 a4 a5 a6 a7 a8 a9 a10] v) - ([a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 & r] v) - )) + ([a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 & r] v))) + #?(:clj -(defmacro throw* [etype & args] - `(throw (new ~etype (smart-str ~@args))))) + (defmacro throw* [etype & args] + `(throw (new ~etype (smart-str ~@args))))) #?( -:clj -(defmacro throw-illegal [& args] - `(throw* IllegalArgumentException ~@args)) + :clj + (defmacro throw-illegal [& args] + `(throw* IllegalArgumentException ~@args)) -:cljs -(defn throw-illegal [& args] - (throw (js/Error. (apply str args)))) -) + :cljs + (defn throw-illegal [& args] + (throw (js/Error. (apply str args))))) + ;; need to get the expansion function like this so that ;; this code compiles in a clojure environment where cljs.analyzer ;; namespace does not exist #?( -:clj -(defn cljs-analyzer-macroexpand-1 [] - (eval 'cljs.analyzer/macroexpand-1)) + :clj + (defn cljs-analyzer-macroexpand-1 [] + (eval 'cljs.analyzer/macroexpand-1)) ;; this version is for bootstrap cljs -:cljs -(defn cljs-analyzer-macroexpand-1 [] - ^:cljs.analyzer/no-resolve cljs.analyzer/macroexpand-1) -) + :cljs + (defn cljs-analyzer-macroexpand-1 [] + ^:cljs.analyzer/no-resolve cljs.analyzer/macroexpand-1)) + #?( -:clj -(defn clj-macroexpand-all [form] - (riddley/macroexpand-all form)) + :clj + (defn clj-macroexpand-all [form] + (riddley/macroexpand-all form)) + + :cljs + (defn clj-macroexpand-all [form] + (throw-illegal "not implemented"))) -:cljs -(defn clj-macroexpand-all [form] - (throw-illegal "not implemented")) -) #?( -:clj -(defn intern* [ns name val] (intern ns name val)) + :clj + (defn intern* [ns name val] (intern ns name val)) + + :cljs + (defn intern* [ns name val] + (throw-illegal "intern not supported in ClojureScript"))) -:cljs -(defn intern* [ns name val] - (throw-illegal "intern not supported in ClojureScript")) -) (defn benchmark [iters afn] (time @@ -107,56 +107,56 @@ (defprotocol RichNavigator (rich-select* [this params params-idx vals structure next-fn]) - (rich-transform* [this params params-idx vals structure next-fn]) - ) + (rich-transform* [this params params-idx vals structure next-fn])) + #?( -:clj -(defmacro exec-rich-select* [this & args] - (let [hinted (with-meta this {:tag 'com.rpl.specter.impl.RichNavigator})] - `(.rich-select* ~hinted ~@args) - )) + :clj + (defmacro exec-rich-select* [this & args] + (let [hinted (with-meta this {:tag 'com.rpl.specter.impl.RichNavigator})] + `(.rich-select* ~hinted ~@args))) + + + :cljs + (defn exec-rich-select* [this params params-idx vals structure next-fn] + (rich-select* ^not-native this params params-idx vals structure next-fn))) -:cljs -(defn exec-rich-select* [this params params-idx vals structure next-fn] - (rich-select* ^not-native this params params-idx vals structure next-fn)) -) #?( -:clj -(defmacro exec-rich-transform* [this & args] - (let [hinted (with-meta this {:tag 'com.rpl.specter.impl.RichNavigator})] - `(.rich-transform* ~hinted ~@args) - )) + :clj + (defmacro exec-rich-transform* [this & args] + (let [hinted (with-meta this {:tag 'com.rpl.specter.impl.RichNavigator})] + `(.rich-transform* ~hinted ~@args))) + + + :cljs + (defn exec-rich-transform* [this params params-idx vals structure next-fn] + (rich-transform* ^not-native this params params-idx vals structure next-fn))) -:cljs -(defn exec-rich-transform* [this params params-idx vals structure next-fn] - (rich-transform* ^not-native this params params-idx vals structure next-fn)) -) #?( -:clj -(defmacro exec-select* [this & args] - (let [hinted (with-meta this {:tag 'com.rpl.specter.protocols.Navigator})] - `(.select* ~hinted ~@args) - )) + :clj + (defmacro exec-select* [this & args] + (let [hinted (with-meta this {:tag 'com.rpl.specter.protocols.Navigator})] + `(.select* ~hinted ~@args))) + + + :cljs + (defn exec-select* [this structure next-fn] + (p/select* ^not-native this structure next-fn))) -:cljs -(defn exec-select* [this structure next-fn] - (p/select* ^not-native this structure next-fn)) -) #?( -:clj -(defmacro exec-transform* [this & args] - (let [hinted (with-meta this {:tag 'com.rpl.specter.protocols.Navigator})] - `(.transform* ~hinted ~@args) - )) + :clj + (defmacro exec-transform* [this & args] + (let [hinted (with-meta this {:tag 'com.rpl.specter.protocols.Navigator})] + `(.transform* ~hinted ~@args))) + + + :cljs + (defn exec-transform* [this structure next-fn] + (p/transform* ^not-native this structure next-fn))) -:cljs -(defn exec-transform* [this structure next-fn] - (p/transform* ^not-native this structure next-fn)) -) (def RichPathExecutor (->ExecutorFunctions @@ -176,16 +176,16 @@ (fn [_ _ vals structure] (if (identical? [] vals) (transform-fn structure) - (apply transform-fn (conj vals structure)))))) - )) + (apply transform-fn (conj vals structure)))))))) + (def LeanPathExecutor (->ExecutorFunctions (fn [nav result-fn structure] (exec-select* nav structure result-fn)) (fn [nav transform-fn structure] - (exec-transform* nav structure transform-fn)) - )) + (exec-transform* nav structure transform-fn)))) + (defrecord CompiledPath [executors nav]) @@ -198,8 +198,8 @@ (->ParameterizedRichNav rich-nav nil - 0 - ))) + 0))) + (defn lean-compiled-path [nav] (->CompiledPath LeanPathExecutor nav)) @@ -208,41 +208,41 @@ (declare bind-params*) #?( -:clj -(defmacro fast-object-array [i] - `(com.rpl.specter.Util/makeObjectArray ~i)) + :clj + (defmacro fast-object-array [i] + `(com.rpl.specter.Util/makeObjectArray ~i)) + + :cljs + (defn fast-object-array [i] + (object-array i))) -:cljs -(defn fast-object-array [i] - (object-array i)) -) #?( -:clj -(dh/define-ParamsNeededPath - true - clojure.lang.IFn - invoke - (applyTo [this args] - (let [a (object-array args)] - (com.rpl.specter.impl/bind-params* this a 0)))) + :clj + (dh/define-ParamsNeededPath + true + clojure.lang.IFn + invoke + (applyTo [this args] + (let [a (object-array args)] + (com.rpl.specter.impl/bind-params* this a 0)))) + + :cljs + (define-ParamsNeededPath + false + cljs.core/IFn + -invoke + (-invoke [this p01 p02 p03 p04 p05 p06 p07 p08 p09 p10 + p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 + rest] + (let [a (object-array + (concat + [p01 p02 p03 p04 p05 p06 p07 p08 p09 p10 + p11 p12 p13 p14 p15 p16 p17 p18 p19 p20] + rest))] + (com.rpl.specter.impl/bind-params* this a 0))))) + -:cljs -(define-ParamsNeededPath - false - cljs.core/IFn - -invoke - (-invoke [this p01 p02 p03 p04 p05 p06 p07 p08 p09 p10 - p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 - rest] - (let [a (object-array - (concat - [p01 p02 p03 p04 p05 p06 p07 p08 p09 p10 - p11 p12 p13 p14 p15 p16 p17 p18 p19 p20] - rest))] - (com.rpl.specter.impl/bind-params* this a 0)) - )) -) (defn params-needed-path? [o] (instance? ParamsNeededPath o)) @@ -253,8 +253,8 @@ (let [n (.-nav ^CompiledPath p)] (if (instance? ParameterizedRichNav n) (.-rich-nav ^ParameterizedRichNav n) - n - )))) + n)))) + (defn bind-params* [^ParamsNeededPath params-needed-path params idx] @@ -263,15 +263,15 @@ (->ParameterizedRichNav (.-rich-nav params-needed-path) params - idx - ))) + idx))) + (defprotocol PathComposer (do-comp-paths [paths])) (defn comp-paths* [p] - (if (compiled-path? p) p (do-comp-paths p)) - ) + (if (compiled-path? p) p (do-comp-paths p))) + (defn- seq-contains? [aseq val] (->> aseq @@ -285,8 +285,8 @@ (defn- coerce-object [this] (cond (root-params-nav? this) (-> this meta :highernav :params-needed-path) (satisfies? p/ImplicitNav this) (p/implicit-nav this) - :else (throw-illegal "Not a navigator: " this) - )) + :else (throw-illegal "Not a navigator: " this))) + (defprotocol CoercePath (coerce-path [this])) @@ -335,14 +335,14 @@ (exec-rich-select* curr params params-idx vals structure (fn [params-next params-idx-next vals-next structure-next] (exec-rich-select* next params-next params-idx-next - vals-next structure-next next-fn) - ))) + vals-next structure-next next-fn)))) + (rich-transform* [this params params-idx vals structure next-fn] (exec-rich-transform* curr params params-idx vals structure (fn [params-next params-idx-next vals-next structure-next] (exec-rich-transform* next params-next params-idx-next - vals-next structure-next next-fn) - ))))) + vals-next structure-next next-fn)))))) + (fn [curr next] (reify Navigator (select* [this structure next-fn] @@ -360,11 +360,11 @@ nav (reify RichNavigator (rich-select* [this params params-idx vals structure next-fn] - (exec-select* nav structure (fn [structure] (next-fn params params-idx vals structure))) - ) + (exec-select* nav structure (fn [structure] (next-fn params params-idx vals structure)))) + (rich-transform* [this params params-idx vals structure next-fn] - (exec-transform* nav structure (fn [structure] (next-fn params params-idx vals structure))) - )))) + (exec-transform* nav structure (fn [structure] (next-fn params params-idx vals structure))))))) + (defn extract-rich-nav [p] (coerce-rich-navigator (extract-nav p))) @@ -389,13 +389,13 @@ (rich-select* [this params2 params-idx2 vals structure next-fn] (exec-rich-select* rich-nav params params-idx vals structure (fn [_ _ vals-next structure-next] - (next-fn params2 params-idx2 vals-next structure-next) - ))) + (next-fn params2 params-idx2 vals-next structure-next)))) + (rich-transform* [this params2 params-idx2 vals structure next-fn] (exec-rich-transform* rich-nav params params-idx vals structure (fn [_ _ vals-next structure-next] - (next-fn params2 params-idx2 vals-next structure-next) - ))))))))) + (next-fn params2 params-idx2 vals-next structure-next)))))))))) + (defn comp-paths-internalized [path] (capture-params-internally (comp-paths* path))) @@ -417,14 +417,14 @@ combined (->> coerced (map extract-nav) (partition-by type) - (map combine-same-types) - ) + (map combine-same-types)) + result-nav (if (= 1 (count combined)) (first combined) (->> combined (map coerce-rich-navigator) - combine-same-types) - ) + combine-same-types)) + needs-params-paths (filter #(instance? ParamsNeededPath %) coerced)] (if (empty? needs-params-paths) (if (satisfies? Navigator result-nav) @@ -434,9 +434,9 @@ (coerce-rich-navigator result-nav) (->> needs-params-paths (map :num-needed-params) - (reduce +)) - )) - )))) + (reduce +)))))))) + + (defn num-needed-params [path] @@ -447,48 +447,48 @@ ;; cell implementation idea taken from prismatic schema library #?(:cljs -(defprotocol PMutableCell - (set_cell [cell x])) -) + (defprotocol PMutableCell + (set_cell [cell x]))) + #?(:cljs -(deftype MutableCell [^:volatile-mutable q] - PMutableCell - (set_cell [this x] (set! q x))) -) + (deftype MutableCell [^:volatile-mutable q] + PMutableCell + (set_cell [this x] (set! q x)))) + #?( -:clj -(defn mutable-cell - ([] (mutable-cell nil)) - ([v] (MutableCell. v))) + :clj + (defn mutable-cell + ([] (mutable-cell nil)) + ([v] (MutableCell. v))) + + :cljs + (defn mutable-cell + ([] (mutable-cell nil)) + ([init] (MutableCell. init)))) -:cljs -(defn mutable-cell - ([] (mutable-cell nil)) - ([init] (MutableCell. init))) -) #?( -:clj -(defn set-cell! [^MutableCell c v] - (.set c v)) + :clj + (defn set-cell! [^MutableCell c v] + (.set c v)) + + :cljs + (defn set-cell! [cell val] + (set_cell cell val))) -:cljs -(defn set-cell! [cell val] - (set_cell cell val)) -) #?( -:clj -(defn get-cell [^MutableCell c] - (.get c)) + :clj + (defn get-cell [^MutableCell c] + (.get c)) -:cljs -(defn get-cell [cell] - (.-q cell)) -) + :cljs + (defn get-cell [cell] + (.-q cell))) + @@ -513,26 +513,26 @@ ;; amazingly doing this as a macro shows a big effect in the ;; benchmark for getting a value out of a nested map #?( -:clj -(defmacro compiled-traverse* [path result-fn structure] - `(let [nav# (compiled-nav-field ~path) - ex# (compiled-executors-field ~path)] - ((traverse-executor-field ex#) - nav# - ~result-fn - ~structure) - )) + :clj + (defmacro compiled-traverse* [path result-fn structure] + `(let [nav# (compiled-nav-field ~path) + ex# (compiled-executors-field ~path)] + ((traverse-executor-field ex#) + nav# + ~result-fn + ~structure))) + + + :cljs + (defn compiled-traverse* [path result-fn structure] + (let [nav (compiled-nav-field path) + ex (compiled-executors-field path)] + ((traverse-executor-field ex) + nav + result-fn + structure)))) + -:cljs -(defn compiled-traverse* [path result-fn structure] - (let [nav (compiled-nav-field path) - ex (compiled-executors-field path)] - ((traverse-executor-field ex) - nav - result-fn - structure) - )) -) (defn do-compiled-traverse [apath structure] (reify #?(:clj clojure.lang.IReduce :cljs cljs.core/IReduce) @@ -546,22 +546,22 @@ apath (fn [elem] (let [curr (get-cell cell)] - (set-cell! cell (afn curr elem)) - )) - structure - ) - (get-cell cell) - )))) + (set-cell! cell (afn curr elem)))) + + structure) + + (get-cell cell))))) + (defn compiled-select* [path structure] (let [res (mutable-cell (transient [])) result-fn (fn [structure] (let [curr (get-cell res)] - (set-cell! res (conj! curr structure)) - ))] + (set-cell! res (conj! curr structure))))] + (compiled-traverse* path result-fn structure) - (persistent! (get-cell res)) - )) + (persistent! (get-cell res)))) + (defn compiled-select-one* [path structure] (let [res (mutable-cell NONE) @@ -569,14 +569,14 @@ (let [curr (get-cell res)] (if (identical? curr NONE) (set-cell! res structure) - (throw-illegal "More than one element found in structure: " structure) - )))] + (throw-illegal "More than one element found in structure: " structure))))] + (compiled-traverse* path result-fn structure) (let [ret (get-cell res)] (if (identical? ret NONE) nil - ret - )))) + ret)))) + (defn compiled-select-one!* [path structure] (let [res (mutable-cell NONE) @@ -584,14 +584,14 @@ (let [curr (get-cell res)] (if (identical? curr NONE) (set-cell! res structure) - (throw-illegal "More than one element found in structure: " structure) - )))] + (throw-illegal "More than one element found in structure: " structure))))] + (compiled-traverse* path result-fn structure) (let [ret (get-cell res)] (if (identical? NONE ret) (throw-illegal "Found no elements for select-one! on " structure)) - ret - ))) + ret))) + (defn compiled-select-first* [path structure] (let [res (mutable-cell NONE) @@ -603,8 +603,8 @@ (let [ret (get-cell res)] (if (identical? ret NONE) nil - ret - )))) + ret)))) + (defn compiled-select-any* [path structure] (compiled-traverse* path identity structure)) @@ -616,8 +616,8 @@ [^com.rpl.specter.impl.CompiledPath path transform-fn structure] (let [nav (.-nav path) ^com.rpl.specter.impl.ExecutorFunctions ex (.-executors path)] - ((.-transform-executor ex) nav transform-fn structure) - )) + ((.-transform-executor ex) nav transform-fn structure))) + (defn params-needed-nav @@ -629,8 +629,8 @@ ^com.rpl.specter.impl.RichNavigator [^com.rpl.specter.impl.CompiledPath path] (let [^com.rpl.specter.impl.ParameterizedRichNav pr (.-nav path)] - (.-rich-nav pr) - )) + (.-rich-nav pr))) + (defn coerce-compiled->rich-nav [path] (if (instance? ParamsNeededPath path) @@ -638,8 +638,8 @@ (let [nav (.-nav ^CompiledPath path)] (if (satisfies? Navigator nav) (no-params-rich-compiled-path (coerce-rich-navigator nav)) - path - )))) + path)))) + (defn fn-invocation? [f] (or #?(:clj (instance? clojure.lang.Cons f)) @@ -660,8 +660,8 @@ (and (instance? ParamsNeededPath anav) (> (:num-needed-params anav) 0))) (throw-illegal "defnavconstructor must be used on a navigator defined with - defnav with at least one parameter") - )) + defnav with at least one parameter"))) + (defn layered-wrapper [anav] (verify-layerable! anav) @@ -676,8 +676,8 @@ ([a1 a2 a3 a4 a5 a6 a7 a8 a9] (->LayeredNav (anav a1 a2 a3 a4 a5 a6 a7 a8 a9))) ([a1 a2 a3 a4 a5 a6 a7 a8 a9 a10] (->LayeredNav (anav a1 a2 a3 a4 a5 a6 a7 a8 a9 a10))) ([a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 & args] - (->LayeredNav (apply anav a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 args))) - )) + (->LayeredNav (apply anav a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 args))))) + (defrecord LocalSym [val sym]) @@ -694,8 +694,8 @@ (defrecord CachedPathInfo [precompiled ; can be null - params-maker ; can be null - ]) + params-maker]) ; can be null + (def MUST-CACHE-PATHS (mutable-cell false)) @@ -712,8 +712,8 @@ (set? node) (every? constant-node? node) (map? node) (and (every? constant-node? (vals node)) (every? constant-node? (keys node))) - :else false - )) + :else false)) + (defn- extract-original-code [p] (cond @@ -721,20 +721,20 @@ (instance? VarUse p) (:sym p) (instance? SpecialFormUse p) (:code p) (instance? FnInvocation p) (:code p) - :else p - )) + :else p)) + (defn- valid-navigator? [v] (or (satisfies? p/ImplicitNav v) (instance? CompiledPath v))) #?(:cljs -(defn handle-params [precompiled params-maker possible-params] - (let [params (fast-object-array (count params-maker))] - (dotimes [i (count params-maker)] - (aset params i ((get possible-params (get params-maker i))))) - (bind-params* precompiled params 0) - ))) + (defn handle-params [precompiled params-maker possible-params] + (let [params (fast-object-array (count params-maker))] + (dotimes [i (count params-maker)] + (aset params i ((get possible-params (get params-maker i))))) + (bind-params* precompiled params 0)))) + (defn filter-select [afn structure next-fn] (if (afn structure) @@ -753,16 +753,16 @@ (let [afn (aget ^objects params params-idx)] (if (afn structure) (next-fn params (inc params-idx) vals structure) - NONE - ))) + NONE))) + (rich-transform* [this params params-idx vals structure next-fn] (let [afn (aget ^objects params params-idx)] (if (afn structure) (next-fn params (inc params-idx) vals structure) - structure - )))) - 1 - )) + structure)))) + + 1)) + (def collected?* (->ParamsNeededPath @@ -771,16 +771,16 @@ (let [afn (aget ^objects params params-idx)] (if (afn vals) (next-fn params (inc params-idx) vals structure) - NONE - ))) + NONE))) + (rich-transform* [this params params-idx vals structure next-fn] (let [afn (aget ^objects params params-idx)] (if (afn vals) (next-fn params (inc params-idx) vals structure) - structure - )))) - 1 - )) + structure)))) + + 1)) + (def rich-compiled-path-proxy (->ParamsNeededPath @@ -796,8 +796,8 @@ vals structure (fn [_ _ vals-next structure-next] - (next-fn params params-idx vals-next structure-next)) - ))) + (next-fn params params-idx vals-next structure-next))))) + (rich-transform* [this params params-idx vals structure next-fn] (let [apath ^CompiledPath (aget ^objects params params-idx) pnav ^ParameterizedRichNav (.-nav apath) @@ -809,10 +809,10 @@ vals structure (fn [_ _ vals-next structure-next] - (next-fn params params-idx vals-next structure-next)) - )))) - 1 - )) + (next-fn params params-idx vals-next structure-next)))))) + + 1)) + (def lean-compiled-path-proxy (->ParamsNeededPath @@ -824,8 +824,8 @@ nav structure (fn [structure-next] - (next-fn params params-idx vals structure-next)) - ))) + (next-fn params params-idx vals structure-next))))) + (rich-transform* [this params params-idx vals structure next-fn] (let [^CompiledPath apath (aget ^objects params params-idx) ^Navigator nav (.-nav apath)] @@ -833,10 +833,10 @@ nav structure (fn [structure-next] - (next-fn params params-idx vals structure-next)) - )))) - 1 - )) + (next-fn params params-idx vals structure-next)))))) + + 1)) + (defn srange-transform* [structure start end next-fn] (let [structurev (vec structure) @@ -846,8 +846,8 @@ (subvec structurev end (count structure)))] (if (vector? structure) (vec res) - res - ))) + res))) + (defn- variadic-arglist? [al] (contains? (set al) '&)) @@ -857,8 +857,8 @@ (filter (fn [al] (or (= (count al) c) - (variadic-arglist? al)) - )) + (variadic-arglist? al)))) + first) len (count ret)] (when-not ret @@ -866,8 +866,8 @@ (if (variadic-arglist? ret) (srange-transform* ret (- len 2) len (fn [_] (repeatedly (- c (- len 2)) gensym))) - ret - ))) + ret))) + (defn- magic-precompilation* [p params-atom failed-atom] (let [magic-fail! (fn [& reason] @@ -897,17 +897,17 @@ vv :else - (magic-fail! "Var " (:sym p) " is not a navigator") - )) + (magic-fail! "Var " (:sym p) " is not a navigator"))) + (instance? SpecialFormUse p) (if (->> p :code first (contains? #{'fn* 'fn})) (do (swap! params-atom conj (:code p)) - pred* - ) - (magic-fail! "Special form " (:code p) " where navigator expected") - ) + pred*) + + (magic-fail! "Special form " (:code p) " where navigator expected")) + (instance? FnInvocation p) (let [op (:op p) @@ -923,8 +923,8 @@ (apply vv ps) (do (swap! params-atom #(vec (concat % ps))) - (coerce-path vv) - )) + (coerce-path vv))) + (and (fn? vv) (-> v meta :pathedfn)) ;;TODO: update this to ignore args that aren't symbols or have :nopath @@ -953,14 +953,14 @@ (magic-fail! "Could not factor static param " "of pathedfn because it's not a static var " " or non-collection value: " - (extract-original-code p)) - ))) - al + (extract-original-code p))))) + + al ps))] (if @failed-atom nil - (apply vv subpath) - )) + (apply vv subpath))) + (and (fn? vv) (-> vv meta :layerednav)) (if (every? constant-node? ps) @@ -969,20 +969,20 @@ (swap! params-atom conj (:code p)) (if (= (-> vv meta :layerednav) :lean) lean-compiled-path-proxy - rich-compiled-path-proxy - ))) + rich-compiled-path-proxy))) + :else (magic-fail! "Var " (:sym op) " must be either a parameterized " "navigator, a higher order pathed constructor function, " - "or a nav constructor") - ))) + "or a nav constructor")))) + (magic-fail! "Code at " (extract-original-code p) " is in " "function invocation position and must be either a parameterized " "navigator, a higher order pathed constructor function, or a " - "nav constructor." - ) - )) + "nav constructor."))) + + :else (cond (set? p) @@ -999,49 +999,49 @@ p :else - (magic-fail! "Code " p " is not a valid navigator or can't be factored") - ) - ))) + (magic-fail! "Code " p " is not a valid navigator or can't be factored"))))) + + ;; This is needed when aset is used on primitive values in mk-params-maker ;; to avoid reflection #?(:clj -(defn aset-object [^objects a i ^Object v] - (aset a i v))) + (defn aset-object [^objects a i ^Object v] + (aset a i v))) #?( -:clj -(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-object ~array-sym ~i ~c)) - params-code - ) - ~array-sym - )))))) + :clj + (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-object ~array-sym ~i ~c)) + params-code) -:cljs -(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 {}))] + ~array-sym)))))) + + + :cljs + (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 {}))] ;;TODO: may be more efficient as an array - (mapv (fn [c] (get indexed c)) params-code))) -) + (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 ns-str used-locals possible-params-code] (let [params-atom (atom []) failed-atom (atom false) - path (magic-precompilation* prepared-path params-atom failed-atom) - ] + path (magic-precompilation* prepared-path params-atom failed-atom)] + (if @failed-atom (if (get-cell MUST-CACHE-PATHS) (throw-illegal "Failed to cache path") @@ -1049,13 +1049,13 @@ (let [precompiled (comp-paths* path) params-code (mapv extract-original-code @params-atom) params-maker (if-not (empty? params-code) - (mk-params-maker ns-str 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... - (->CachedPathInfo precompiled params-maker) - )) - )) + (->CachedPathInfo precompiled params-maker))))) + + @@ -1074,11 +1074,11 @@ (merge-fn (get-cell state)) (set-cell! state)) ret) - (last args) - ))) + (last args)))) + structure) - (get-cell state)] - )) + (get-cell state)])) + (defn- multi-transform-error-fn [& nav] (throw-illegal @@ -1089,29 +1089,28 @@ (compiled-transform* path multi-transform-error-fn structure)) #?(:clj -(defn extend-protocolpath* [protpath protpath-prot extensions] - (let [extensions (partition 2 extensions) - m (-> protpath-prot :sigs keys first) - expected-params (num-needed-params protpath)] - (doseq [[atype apath] extensions] - (let [p (comp-paths-internalized apath) - needed-params (num-needed-params p) - rich-nav (extract-rich-nav p) - ] - (if-not (= needed-params expected-params) - (throw-illegal "Invalid number of params in extended protocol path, expected " - expected-params " but got " needed-params)) - (extend atype protpath-prot {m (fn [_] rich-nav)}) - ))))) + (defn extend-protocolpath* [protpath protpath-prot extensions] + (let [extensions (partition 2 extensions) + m (-> protpath-prot :sigs keys first) + expected-params (num-needed-params protpath)] + (doseq [[atype apath] extensions] + (let [p (comp-paths-internalized apath) + needed-params (num-needed-params p) + rich-nav (extract-rich-nav p)] + + (if-not (= needed-params expected-params) + (throw-illegal "Invalid number of params in extended protocol path, expected " + expected-params " but got " needed-params)) + (extend atype protpath-prot {m (fn [_] rich-nav)})))))) + (defn parameterize-path [apath params params-idx] (if (instance? CompiledPath apath) apath - (bind-params* apath params params-idx) - )) + (bind-params* apath params params-idx))) + (defn mk-jump-next-fn [next-fn init-idx total-params] (let [jumped (+ init-idx total-params)] (fn [params params-idx vals structure] - (next-fn params jumped vals structure) - ))) + (next-fn params jumped vals structure)))) diff --git a/src/clj/com/rpl/specter/macros.clj b/src/clj/com/rpl/specter/macros.clj index 784d617..35327e3 100644 --- a/src/clj/com/rpl/specter/macros.clj +++ b/src/clj/com/rpl/specter/macros.clj @@ -3,8 +3,8 @@ [com.rpl.specter.impl :only [RichNavigator]]) (:require [com.rpl.specter.impl :as i] [clojure.walk :as cljwalk] - [com.rpl.specter.defnavhelpers :as dnh]) - ) + [com.rpl.specter.defnavhelpers :as dnh])) + (defn ^:no-doc gensyms [amt] (vec (repeatedly amt gensym))) @@ -14,8 +14,8 @@ (if-not (= #{'select* 'transform*} (-> grouped keys set)) (i/throw-illegal "defnav must implement select* and transform*, instead got " (keys grouped))) - grouped - )) + grouped)) + (defmacro richnav "Defines a navigator with full access to collected vals, the parameters array, @@ -30,8 +30,8 @@ s-next-fn-sym (last s-params) s-pidx-sym (nth s-params 2) t-next-fn-sym (last t-params) - t-pidx-sym (nth t-params 2) - ] + t-pidx-sym (nth t-params 2)] + `(let [num-params# ~num-params nav# (reify RichNavigator (~'rich-select* ~s-params @@ -39,12 +39,12 @@ ~@s-body)) (~'rich-transform* ~t-params (let [~t-next-fn-sym (i/mk-jump-next-fn ~t-next-fn-sym ~t-pidx-sym num-params#)] - ~@t-body)) - )] + ~@t-body)))] + (if (zero? num-params#) (i/no-params-rich-compiled-path nav#) - (i/->ParamsNeededPath nav# num-params#) - )))) + (i/->ParamsNeededPath nav# num-params#))))) + (defmacro ^:no-doc lean-nav* [& impls] `(reify Navigator ~@impls)) @@ -60,16 +60,15 @@ binding-fn-syms)) body (op-maker binding-declarations)] `(let [~@binding-fn-declarations] - ~body - ))) + ~body))) (defmacro ^:no-doc rich-nav-with-bindings [num-params-code bindings & impls] (let [{[[_ s-structure-sym s-next-fn-sym] & s-body] 'select* [[_ t-structure-sym t-next-fn-sym] & t-body] 'transform*} (determine-params-impls impls) params-sym (gensym "params") - params-idx-sym (gensym "params-idx") - ] + params-idx-sym (gensym "params-idx")] + (operation-with-bindings bindings params-sym @@ -84,8 +83,8 @@ next-params-idx# vals# structure#))] - ~@s-body - )) + ~@s-body)) + (~'rich-transform* [this# ~params-sym ~params-idx-sym vals# ~t-structure-sym next-fn#] (let [~@binding-declarations next-params-idx# (+ ~params-idx-sym ~num-params-code) @@ -94,9 +93,9 @@ next-params-idx# vals# structure#))] - ~@t-body - )) - ))))) + ~@t-body))))))) + + (defmacro ^:no-doc collector-with-bindings [num-params-code bindings impl] (let [[_ [_ structure-sym] & body] impl @@ -110,21 +109,21 @@ `(let [num-params# ~num-params-code cfn# (fn [~params-sym ~params-idx-sym vals# ~structure-sym next-fn#] (let [~@binding-declarations] - (next-fn# ~params-sym (+ ~params-idx-sym num-params#) (conj vals# (do ~@body)) ~structure-sym) - ))] + (next-fn# ~params-sym (+ ~params-idx-sym num-params#) (conj vals# (do ~@body)) ~structure-sym)))] + (reify RichNavigator (~'rich-select* [this# params# params-idx# vals# structure# next-fn#] (cfn# params# params-idx# vals# structure# next-fn#)) (~'rich-transform* [this# params# params-idx# vals# structure# next-fn#] - (cfn# params# params-idx# vals# structure# next-fn#)) - )))))) + (cfn# params# params-idx# vals# structure# next-fn#)))))))) + (defn- delta-param-bindings [params] (->> params (map-indexed (fn [i p] [p `(dnh/param-delta ~i)])) (apply concat) - vec - )) + vec)) + (defmacro nav "Defines a navigator with late bound parameters. This navigator can be precompiled @@ -143,10 +142,10 @@ (i/->ParamsNeededPath (rich-nav-with-bindings ~(count params) ~(delta-param-bindings params) - ~@impls - ) - ~(count params))} - ))) + ~@impls) + + ~(count params))}))) + (defmacro collector "Defines a Collector with late bound parameters. This collector can be precompiled @@ -157,8 +156,8 @@ [params body] `(let [rich-nav# (collector-with-bindings ~(count params) ~(delta-param-bindings params) - ~body - )] + ~body)] + (if ~(empty? params) (i/no-params-rich-compiled-path rich-nav#) (vary-meta @@ -172,9 +171,9 @@ :params-needed-path (i/->ParamsNeededPath rich-nav# - ~(count params) - )} - )))) + ~(count params))})))) + + (defn ^:no-doc fixed-pathed-operation [bindings op-maker] (let [bindings (partition 2 bindings) @@ -184,8 +183,8 @@ compiled-syms (vec (gensyms (count bindings))) runtime-bindings (vec (mapcat (fn [l c d] - `[~l (dnh/bound-params ~c ~d)] - ) + `[~l (dnh/bound-params ~c ~d)]) + late-path-syms compiled-syms delta-syms)) @@ -195,10 +194,10 @@ ~compiled-syms compiled# deltas# (cons 0 (reductions + (map i/num-needed-params compiled#))) ~delta-syms deltas# - ~total-params-sym (last deltas#) - ] - ~body - ))) + ~total-params-sym (last deltas#)] + + ~body))) + (defmacro fixed-pathed-nav "This helper is used to define navigators that take in a fixed number of other @@ -212,16 +211,16 @@ lean-bindings (mapcat vector late-syms compiled-syms)] `(if (zero? ~total-params-sym) (let [~@lean-bindings] - (i/lean-compiled-path (lean-nav* ~@impls)) - ) + (i/lean-compiled-path (lean-nav* ~@impls))) + (i/->ParamsNeededPath (rich-nav-with-bindings ~total-params-sym ~runtime-bindings - ~@impls - ) - ~total-params-sym - ))) - ))) + ~@impls) + + ~total-params-sym)))))) + + (defmacro fixed-pathed-collector @@ -241,21 +240,21 @@ (i/->ParamsNeededPath (collector-with-bindings ~total-params-sym ~runtime-bindings - ~@body - ) - ~total-params-sym - )))))) + ~@body) + + ~total-params-sym)))))) + (defmacro paramsfn [params [structure-sym] & impl] `(nav ~params (~'select* [this# structure# next-fn#] (let [afn# (fn [~structure-sym] ~@impl)] - (i/filter-select afn# structure# next-fn#) - )) + (i/filter-select afn# structure# next-fn#))) + (~'transform* [this# structure# next-fn#] (let [afn# (fn [~structure-sym] ~@impl)] - (i/filter-transform afn# structure# next-fn#) - )))) + (i/filter-transform afn# structure# next-fn#))))) + (defmacro defnav [name & body] `(def ~name (nav ~@body))) @@ -293,24 +292,24 @@ num-params (count params) ssym (gensym "structure") rargs [(gensym "params") (gensym "pidx") (gensym "vals") ssym (gensym "next-fn")] - retrieve `(~m ~ssym) - ] + retrieve `(~m ~ssym)] + `(do (defprotocol ~prot-name (~m [structure#])) (let [nav# (reify RichNavigator (~'rich-select* [this# ~@rargs] (let [inav# ~retrieve] - (i/exec-rich-select* inav# ~@rargs) - )) + (i/exec-rich-select* inav# ~@rargs))) + (~'rich-transform* [this# ~@rargs] (let [inav# ~retrieve] - (i/exec-rich-transform* inav# ~@rargs) - )))] + (i/exec-rich-transform* inav# ~@rargs))))] + (def ~name (if (= ~num-params 0) (i/no-params-rich-compiled-path nav#) - (i/->ParamsNeededPath nav# ~num-params) - ))))))) + (i/->ParamsNeededPath nav# ~num-params)))))))) + @@ -342,12 +341,12 @@ (~'rich-select* [this# ~@rargs] (~select-exec ~declared ~@rargs)) (~'rich-transform* [this# ~@rargs] - (~transform-exec ~declared ~@rargs) - ))] + (~transform-exec ~declared ~@rargs)))] + (if (= ~num-params 0) (i/no-params-rich-compiled-path nav#) - (i/->ParamsNeededPath nav# ~num-params) - ))))))) + (i/->ParamsNeededPath nav# ~num-params)))))))) + (defmacro providepath [name apath] `(let [comped# (i/comp-paths-internalized ~apath) @@ -357,8 +356,8 @@ (i/throw-illegal "Invalid number of params in provided path, expected " expected-params# " but got " needed-params#)) (def ~(declared-name name) - (i/extract-rich-nav (i/coerce-compiled->rich-nav comped#)) - ))) + (i/extract-rich-nav (i/coerce-compiled->rich-nav comped#))))) + (defmacro extend-protocolpath "Used in conjunction with `defprotocolpath`. See [[defprotocolpath]]." @@ -420,15 +419,15 @@ (i/throw-illegal "Expected result navigator '" (quote ~anav) "' from nav constructor '" (quote ~name) "'" " constructed with the provided constructor '" (quote ~csym) - "'")) - ))))] + "'"))))))] + `(def ~name (vary-meta (let [~csym (i/layered-wrapper ~anav)] (fn ~@checked-code)) - assoc :layerednav (or (-> ~anav meta :highernav :type) :rich) - )) - )) + assoc :layerednav (or (-> ~anav meta :highernav :type) :rich))))) + + (defn ^:no-doc ic-prepare-path [locals-set path] @@ -440,8 +439,8 @@ (if (contains? locals-set path) `(com.rpl.specter.impl/->LocalSym ~path (quote ~path)) ;; var-get doesn't work in cljs, so capture the val in the macro instead - `(com.rpl.specter.impl/->VarUse ~path (var ~path) (quote ~path)) - ) + `(com.rpl.specter.impl/->VarUse ~path (var ~path) (quote ~path))) + (i/fn-invocation? path) (let [[op & params] path] @@ -452,12 +451,12 @@ `(com.rpl.specter.impl/->FnInvocation ~(ic-prepare-path locals-set op) ~(mapv #(ic-prepare-path locals-set %) params) - (quote ~path))) - ) + (quote ~path)))) + :else - `(quote ~path) - )) + `(quote ~path))) + (defn ^:no-doc ic-possible-params [path] (do @@ -473,10 +472,10 @@ (concat [e] (rest e) (ic-possible-params e)) (vector? e) - (ic-possible-params e) - )) - path - ))) + (ic-possible-params e))) + + path))) + (defn cljs-macroexpand [env form] (let [expand-fn (i/cljs-analyzer-macroexpand-1) @@ -490,13 +489,13 @@ (#{'fn 'fn* 'cljs.core/fn} (first form))) form (let [expanded (if (seq? form) (cljs-macroexpand env form) form)] - (cljwalk/walk #(cljs-macroexpand-all* env %) identity expanded) - ))) + (cljwalk/walk #(cljs-macroexpand-all* env %) identity expanded)))) + (defn cljs-macroexpand-all [env form] (let [ret (cljs-macroexpand-all* env form)] - ret - )) + ret)) + ;; still possible to mess this up with alter-var-root (defmacro path @@ -509,15 +508,15 @@ platform (if (contains? &env :locals) :cljs :clj) local-syms (if (= platform :cljs) (-> &env :locals keys set) ;cljs - (-> &env keys set) ;clj - ) + (-> &env keys set)) ;clj + used-locals-cell (i/mutable-cell []) _ (cljwalk/postwalk (fn [e] (if (local-syms e) (i/update-cell! used-locals-cell #(conj % e)) - e - )) + e)) + path) used-locals (i/get-cell used-locals-cell) @@ -549,10 +548,10 @@ (alter-var-root (var ~cache-sym) (fn [_#] (i/mutable-cell))) - nil - )))) - cache-sym - ) + nil)))) + + cache-sym) + add-cache-code (if (= platform :clj) `(i/set-cell! ~cache-sym ~info-sym) `(def ~cache-sym ~info-sym)) @@ -567,9 +566,9 @@ `(i/handle-params ~precompiled-sym ~params-maker-sym - ~(mapv (fn [p] `(fn [] ~p)) possible-params) - )) - ] + ~(mapv (fn [p] `(fn [] ~p)) possible-params)))] + + (if (= platform :clj) (i/intern* *ns* cache-sym (i/mutable-cell))) `(let [info# ~get-cache-code @@ -580,13 +579,13 @@ ~prepared-path ~(str *ns*) (quote ~used-locals) - (quote ~possible-params) - )] + (quote ~possible-params))] + ~add-cache-code - ~info-sym - ) - info# - ) + ~info-sym) + + info#) + ~precompiled-sym (.-precompiled info#) ~params-maker-sym (.-params-maker info#)] @@ -594,10 +593,10 @@ (i/comp-paths* ~(if (= (count path) 1) (first path) (vec path))) (if (nil? ~params-maker-sym) ~precompiled-sym - ~handle-params-code - ) - )) - )) + ~handle-params-code))))) + + + (defmacro select "Navigates to and returns a sequence of all the elements specified by the path. @@ -705,5 +704,4 @@ to capture all the collected values as a single vector." [params & body] (let [platform (if (contains? &env :locals) :cljs :clj)] - `(i/collected?* (~'fn [~params] ~@body)) - )) + `(i/collected?* (~'fn [~params] ~@body)))) diff --git a/src/clj/com/rpl/specter/navs.cljc b/src/clj/com/rpl/specter/navs.cljc index cf647f9..cbd734b 100644 --- a/src/clj/com/rpl/specter/navs.cljc +++ b/src/clj/com/rpl/specter/navs.cljc @@ -8,19 +8,19 @@ defnav defpathedfn richnav - defnavconstructor - ]] + defnavconstructor]] + [com.rpl.specter.util-macros :refer - [doseqres]] - )) + [doseqres]])) + (:use #?(:clj [com.rpl.specter macros]) #?(:clj [com.rpl.specter.util-macros :only [doseqres]])) (:require [com.rpl.specter.impl :as i] [clojure.walk :as walk] - #?(:clj [clojure.core.reducers :as r]) - [com.rpl.specter.defnavhelpers] ; so that for cljs it's loaded as macros expand to this - ) - ) + #?(:clj [clojure.core.reducers :as r]) + [com.rpl.specter.defnavhelpers])) ; so that for cljs it's loaded as macros expand to this + + (defn- append [coll elem] (-> coll vec (conj elem))) @@ -42,34 +42,34 @@ (let [r (continue-fn structure)] (if-not (identical? r i/NONE) (i/set-cell! ret r)) - r - ) - (walk/walk this identity structure) - ))] + r) + + (walk/walk this identity structure)))] + (walker structure) - (i/get-cell ret) - )) + (i/get-cell ret))) + (defn key-select [akey structure next-fn] (next-fn (get structure akey))) (defn key-transform [akey structure next-fn] - (assoc structure akey (next-fn (get structure akey)) - )) + (assoc structure akey (next-fn (get structure akey)))) + (defn all-select [structure next-fn] (doseqres i/NONE [e structure] (next-fn e))) #?( -:clj -(defn queue? [coll] - (instance? clojure.lang.PersistentQueue coll)) + :clj + (defn queue? [coll] + (instance? clojure.lang.PersistentQueue coll)) + + :cljs + (defn queue? [coll] + (= (type coll) (type #queue [])))) -:cljs -(defn queue? [coll] - (= (type coll) (type #queue []))) -) (defprotocol AllTransformProtocol (all-transform [structure next-fn])) @@ -78,26 +78,26 @@ (reduce-kv (fn [m k v] (let [[newk newv] (next-fn [k v])] - (assoc m newk newv) - )) + (assoc m newk newv))) + empty-map - structure - )) + structure)) + (extend-protocol AllTransformProtocol nil (all-transform [structure next-fn] - nil - ) + nil) + ;; in cljs they're PersistentVector so don't need a special case #?(:clj clojure.lang.MapEntry) #?(:clj - (all-transform [structure next-fn] - (let [newk (next-fn (key structure)) - newv (next-fn (val structure))] - (clojure.lang.MapEntry. newk newv) - ))) + (all-transform [structure next-fn] + (let [newk (next-fn (key structure)) + newv (next-fn (val structure))] + (clojure.lang.MapEntry. newk newv)))) + #?(:clj clojure.lang.PersistentVector :cljs cljs.core/PersistentVector) (all-transform [structure next-fn] @@ -105,31 +105,31 @@ #?(:clj clojure.lang.PersistentArrayMap) #?(:clj - (all-transform [structure next-fn] - (let [k-it (.keyIterator structure) - v-it (.valIterator structure) - array (i/fast-object-array (* 2 (.count structure)))] - (loop [i 0] - (if (.hasNext k-it) - (let [k (.next k-it) - v (.next v-it) - [newk newv] (next-fn [k v])] - (aset array i newk) - (aset array (inc i) newv) - (recur (+ i 2))))) - (clojure.lang.PersistentArrayMap. array) - ))) + (all-transform [structure next-fn] + (let [k-it (.keyIterator structure) + v-it (.valIterator structure) + array (i/fast-object-array (* 2 (.count structure)))] + (loop [i 0] + (if (.hasNext k-it) + (let [k (.next k-it) + v (.next v-it) + [newk newv] (next-fn [k v])] + (aset array i newk) + (aset array (inc i) newv) + (recur (+ i 2))))) + (clojure.lang.PersistentArrayMap. array)))) + #?(:cljs cljs.core/PersistentArrayMap) #?(:cljs - (all-transform [structure next-fn] - (non-transient-map-all-transform structure next-fn {}) - )) + (all-transform [structure next-fn] + (non-transient-map-all-transform structure next-fn {}))) + #?(:clj clojure.lang.PersistentTreeMap :cljs cljs.core/PersistentTreeMap) (all-transform [structure next-fn] - (non-transient-map-all-transform structure next-fn (empty structure)) - ) + (non-transient-map-all-transform structure next-fn (empty structure))) + #?(:clj clojure.lang.PersistentHashMap :cljs cljs.core/PersistentHashMap) (all-transform [structure next-fn] @@ -137,48 +137,48 @@ (reduce-kv (fn [m k v] (let [[newk newv] (next-fn [k v])] - (assoc! m newk newv) - )) + (assoc! m newk newv))) + (transient - #?(:clj clojure.lang.PersistentHashMap/EMPTY :cljs cljs.core.PersistentHashMap.EMPTY) - ) - structure - ))) + #?(:clj clojure.lang.PersistentHashMap/EMPTY :cljs cljs.core.PersistentHashMap.EMPTY)) + + structure))) + #?(:clj Object) #?(:clj - (all-transform [structure next-fn] - (let [empty-structure (empty structure)] - (cond (and (list? empty-structure) (not (queue? empty-structure))) + (all-transform [structure next-fn] + (let [empty-structure (empty structure)] + (cond (and (list? empty-structure) (not (queue? empty-structure))) ;; this is done to maintain order, otherwise lists get reversed - (doall (map next-fn structure)) + (doall (map next-fn structure)) - (map? structure) + (map? structure) ;; reduce-kv is much faster than doing r/map through call to (into ...) - (reduce-kv - (fn [m k v] - (let [[newk newv] (next-fn [k v])] - (assoc m newk newv) - )) - empty-structure - structure - ) + (reduce-kv + (fn [m k v] + (let [[newk newv] (next-fn [k v])] + (assoc m newk newv))) + + empty-structure + structure) + + + :else + (->> structure (r/map next-fn) (into empty-structure)))))) - :else - (->> structure (r/map next-fn) (into empty-structure)) - )))) #?(:cljs default) #?(:cljs - (all-transform [structure next-fn] - (let [empty-structure (empty structure)] - (if (and (list? empty-structure) (not (queue? empty-structure))) + (all-transform [structure next-fn] + (let [empty-structure (empty structure)] + (if (and (list? empty-structure) (not (queue? empty-structure))) ;; this is done to maintain order, otherwise lists get reversed - (doall (map next-fn structure)) - (into empty-structure (map #(next-fn %)) structure) - )))) - ) + (doall (map next-fn structure)) + (into empty-structure (map #(next-fn %)) structure)))))) + + (defprotocol MapValsTransformProtocol (map-vals-transform [structure next-fn])) @@ -193,36 +193,36 @@ (extend-protocol MapValsTransformProtocol nil (map-vals-transform [structure next-fn] - nil - ) + nil) + #?(:clj clojure.lang.PersistentArrayMap) #?(:clj - (map-vals-transform [structure next-fn] - (let [k-it (.keyIterator structure) - v-it (.valIterator structure) - array (i/fast-object-array (* 2 (.count structure)))] - (loop [i 0] - (if (.hasNext k-it) - (let [k (.next k-it) - v (.next v-it) - newv (next-fn v)] - (aset array i k) - (aset array (inc i) newv) - (recur (+ i 2))))) - (clojure.lang.PersistentArrayMap. array) - ))) + (map-vals-transform [structure next-fn] + (let [k-it (.keyIterator structure) + v-it (.valIterator structure) + array (i/fast-object-array (* 2 (.count structure)))] + (loop [i 0] + (if (.hasNext k-it) + (let [k (.next k-it) + v (.next v-it) + newv (next-fn v)] + (aset array i k) + (aset array (inc i) newv) + (recur (+ i 2))))) + (clojure.lang.PersistentArrayMap. array)))) + #?(:cljs cljs.core/PersistentArrayMap) #?(:cljs - (map-vals-transform [structure next-fn] - (map-vals-non-transient-transform structure {} next-fn) - )) + (map-vals-transform [structure next-fn] + (map-vals-non-transient-transform structure {} next-fn))) + #?(:clj clojure.lang.PersistentTreeMap :cljs cljs.core/PersistentTreeMap) (map-vals-transform [structure next-fn] - (map-vals-non-transient-transform structure (empty structure) next-fn) - ) + (map-vals-non-transient-transform structure (empty structure) next-fn)) + #?(:clj clojure.lang.PersistentHashMap :cljs cljs.core/PersistentHashMap) (map-vals-transform [structure next-fn] @@ -231,10 +231,10 @@ (fn [m k v] (assoc! m k (next-fn v))) (transient - #?(:clj clojure.lang.PersistentHashMap/EMPTY :cljs cljs.core.PersistentHashMap.EMPTY) - ) - structure - ))) + #?(:clj clojure.lang.PersistentHashMap/EMPTY :cljs cljs.core.PersistentHashMap.EMPTY)) + + structure))) + #?(:clj Object :cljs default) (map-vals-transform [structure next-fn] @@ -242,8 +242,8 @@ (fn [m k v] (assoc m k (next-fn v))) (empty structure) - structure)) - ) + structure))) + (defn srange-select [structure start end next-fn] (next-fn (-> structure vec (subvec start end)))) @@ -265,11 +265,11 @@ [ranges curr-start i] :else - [(conj ranges [curr-start (inc curr-last)]) i i] - )) + [(conj ranges [curr-start (inc curr-last)]) i i])) + [[] nil nil] - (concat (matching-indices aseq p) [-1]) - ))) + (concat (matching-indices aseq p) [-1])))) + (defn extract-basic-filter-fn [path] (cond (fn? path) @@ -280,10 +280,10 @@ (reduce (fn [combined afn] (fn [structure] - (and (combined structure) (afn structure)) - )) - path - ))) + (and (combined structure) (afn structure)))) + + path))) + @@ -299,8 +299,8 @@ idx vals structure - next-fn - ))) + next-fn))) + (defn if-transform [params params-idx vals structure next-fn then-tester then-nav then-params else-nav] @@ -315,15 +315,15 @@ idx vals structure - next-fn - ))) + next-fn))) + (defn terminal* [params params-idx vals structure] (let [afn (aget ^objects params params-idx)] (if (identical? vals []) (afn structure) - (apply afn (conj vals structure))) - )) + (apply afn (conj vals structure))))) + (defprotocol AddExtremes @@ -345,15 +345,15 @@ (as-> ret <> (reduce conj! <> elements) (reduce conj! <> structure) - (persistent! <>) - ))) + (persistent! <>)))) + #?(:clj Object :cljs default) (append-all [structure elements] (concat structure elements)) (prepend-all [structure elements] - (concat elements structure)) - ) + (concat elements structure))) + (defprotocol UpdateExtremes @@ -384,31 +384,31 @@ (append (butlast l) (afn (last l)))) #?( -:clj -(defn vec-count [^clojure.lang.IPersistentVector v] - (.length v)) + :clj + (defn vec-count [^clojure.lang.IPersistentVector v] + (.length v)) + + :cljs + (defn vec-count [v] + (count v))) -:cljs -(defn vec-count [v] - (count v)) -) #?( -:clj -(defn transient-vec-count [^clojure.lang.ITransientVector v] - (.count v)) + :clj + (defn transient-vec-count [^clojure.lang.ITransientVector v] + (.count v)) + + :cljs + (defn transient-vec-count [v] + (count v))) -:cljs -(defn transient-vec-count [v] - (count v)) -) (extend-protocol UpdateExtremes #?(:clj clojure.lang.PersistentVector :cljs cljs.core/PersistentVector) (update-first [v afn] (let [val (nth v 0)] - (assoc v 0 (afn val)) - )) + (assoc v 0 (afn val)))) + (update-last [v afn] ;; type-hinting vec-count to ^int caused weird errors with case (let [c (int (vec-count v))] @@ -416,14 +416,14 @@ 1 (let [[e] v] [(afn e)]) 2 (let [[e1 e2] v] [e1 (afn e2)]) (let [i (dec c)] - (assoc v i (afn (nth v i))) - )))) + (assoc v i (afn (nth v i))))))) + #?(:clj Object :cljs default) (update-first [l val] (update-first-list l val)) (update-last [l val] - (update-last-list l val) - )) + (update-last-list l val))) + (extend-protocol GetExtremes #?(:clj clojure.lang.IPersistentVector :cljs cljs.core/PersistentVector) @@ -435,8 +435,8 @@ (get-first [s] (first s)) (get-last [s] - (last s) - )) + (last s))) + (extend-protocol FastEmpty @@ -451,14 +451,14 @@ (= 0 (transient-vec-count v))) #?(:clj Object :cljs default) (fast-empty? [s] - (empty? s)) - ) + (empty? s))) + (defn walk-until [pred on-match-fn structure] (if (pred structure) (on-match-fn structure) - (walk/walk (partial walk-until pred on-match-fn) identity structure) - )) + (walk/walk (partial walk-until pred on-match-fn) identity structure))) + (defn codewalk-until [pred on-match-fn structure] (if (pred structure) @@ -466,8 +466,8 @@ (let [ret (walk/walk (partial codewalk-until pred on-match-fn) identity structure)] (if (and (i/fn-invocation? structure) (i/fn-invocation? ret)) (with-meta ret (meta structure)) - ret - )))) + ret)))) + (def DISPENSE* (i/no-params-rich-compiled-path diff --git a/src/clj/com/rpl/specter/protocols.cljc b/src/clj/com/rpl/specter/protocols.cljc index f734e3a..eee9a8e 100644 --- a/src/clj/com/rpl/specter/protocols.cljc +++ b/src/clj/com/rpl/specter/protocols.cljc @@ -15,8 +15,8 @@ (transform* [this structure next-fn] "An implementation of `transform*` must use `next-fn` to transform any subvalues of `structure` and then merge those transformed values - back into `structure`. Everything else in `structure` must be unchanged." - )) + back into `structure`. Everything else in `structure` must be unchanged.")) + (defprotocol Collector "Do not use this protocol directly. All navigators must be created using diff --git a/src/clj/com/rpl/specter/transients.cljc b/src/clj/com/rpl/specter/transients.cljc index fe7049b..de475f8 100644 --- a/src/clj/com/rpl/specter/transients.cljc +++ b/src/clj/com/rpl/specter/transients.cljc @@ -1,13 +1,13 @@ (ns com.rpl.specter.transients #?(:cljs - (:require-macros [com.rpl.specter.macros - :refer - [defnav - defpathedfn]])) + (:require-macros [com.rpl.specter.macros + :refer + [defnav + defpathedfn]])) (:use #?(:clj - [com.rpl.specter.macros :only - [defnav - defpathedfn]])) + [com.rpl.specter.macros :only + [defnav + defpathedfn]])) (:require [com.rpl.specter.navs :as n] [com.rpl.specter :refer [subselect selected?]])) @@ -60,29 +60,29 @@ (n/PosNavigator t-get-last t-update-last)) #?( -:clj -(defn- select-keys-from-transient-map - "Selects keys from transient map, because built-in select-keys uses + :clj + (defn- select-keys-from-transient-map + "Selects keys from transient map, because built-in select-keys uses `find` which is unsupported." - [m m-keys] - (loop [result {} - m-keys m-keys] - (if-not (seq m-keys) - result - (let [k (first m-keys) + [m m-keys] + (loop [result {} + m-keys m-keys] + (if-not (seq m-keys) + result + (let [k (first m-keys) ;; support Clojure 1.6 where contains? is broken on transients - item (get m k ::not-found)] - (recur (if-not (identical? item ::not-found) - (assoc result k item) - result) - (rest m-keys)))))) + item (get m k ::not-found)] + (recur (if-not (identical? item ::not-found) + (assoc result k item) + result) + (rest m-keys)))))) + + :cljs + (defn- select-keys-from-transient-map + "Uses select-keys on a transient map." + [m m-keys] + (select-keys m m-keys))) -:cljs -(defn- select-keys-from-transient-map - "Uses select-keys on a transient map." - [m m-keys] - (select-keys m m-keys)) -) (defnav ^{:doc "Navigates to the specified persistent submap of a transient map."} diff --git a/src/clj/com/rpl/specter/util_macros.clj b/src/clj/com/rpl/specter/util_macros.clj index b4726db..6850812 100644 --- a/src/clj/com/rpl/specter/util_macros.clj +++ b/src/clj/com/rpl/specter/util_macros.clj @@ -6,8 +6,7 @@ (let [ret# (do ~@body)] (if (identical? ret# ~backup-res) curr# - ret# - ))) + ret#))) + ~backup-res - ~aseq - )) + ~aseq)) diff --git a/src/clj/com/rpl/specter/zipper.cljc b/src/clj/com/rpl/specter/zipper.cljc index 458fe51..2632ccf 100644 --- a/src/clj/com/rpl/specter/zipper.cljc +++ b/src/clj/com/rpl/specter/zipper.cljc @@ -3,8 +3,8 @@ [com.rpl.specter.macros :refer [defnav nav declarepath providepath]])) #?(:clj - (:use - [com.rpl.specter.macros :only [defnav nav declarepath providepath]])) + (:use + [com.rpl.specter.macros :only [defnav nav declarepath providepath]])) (:require [com.rpl.specter :as s] [clojure.zip :as zip])) @@ -12,8 +12,8 @@ (select* [this structure next-fn] (next-fn (constructor structure))) (transform* [this structure next-fn] - (zip/root (next-fn (constructor structure))) - )) + (zip/root (next-fn (constructor structure))))) + (def VECTOR-ZIP (zipper zip/vector-zip)) (def SEQ-ZIP (zipper zip/seq-zip)) @@ -34,12 +34,12 @@ (nav [] (select* [this structure next-fn] (let [ret (znav structure)] - (if ret (next-fn ret)) - )) + (if ret (next-fn ret)))) + (transform* [this structure next-fn] (let [ret (znav structure)] - (if ret (next-fn ret) structure) - )))) + (if ret (next-fn ret) structure))))) + ;; (multi-path RIGHT LEFT) will not navigate to the right and left ;; of the currently navigated element because locations aren't stable @@ -69,12 +69,12 @@ inserts (reduce (fn [z e] (-> z (inserter e) mover)) structure - to-insert - )] + to-insert)] + (if backer (reduce (fn [z _] (backer z)) inserts to-insert) - inserts) - )) + inserts))) + (defnav ^{:doc "Navigate to the empty subsequence directly to the right of this element."} @@ -82,8 +82,8 @@ (select* [this structure next-fn] (next-fn [])) (transform* [this structure next-fn] - (inner-insert structure next-fn zip/insert-right zip/right zip/left) - )) + (inner-insert structure next-fn zip/insert-right zip/right zip/left))) + (defnav ^{:doc "Navigate to the empty subsequence directly to the left of this element."} @@ -91,16 +91,16 @@ (select* [this structure next-fn] (next-fn [])) (transform* [this structure next-fn] - (inner-insert structure next-fn zip/insert-left identity nil) - )) + (inner-insert structure next-fn zip/insert-left identity nil))) + (defnav NODE [] (select* [this structure next-fn] - (next-fn (zip/node structure)) - ) + (next-fn (zip/node structure))) + (transform* [this structure next-fn] - (zip/edit structure next-fn) - )) + (zip/edit structure next-fn))) + (defnav ^{:doc "Navigate to the subsequence containing only the node currently pointed to. This works just @@ -108,13 +108,13 @@ from the structure"} NODE-SEQ [] (select* [this structure next-fn] - (next-fn [(zip/node structure)]) - ) + (next-fn [(zip/node structure)])) + (transform* [this structure next-fn] (let [to-insert (next-fn [(zip/node structure)]) inserted (reduce zip/insert-left structure to-insert)] - (zip/remove inserted) - ))) + (zip/remove inserted)))) + (declarepath ^{:doc "Navigate the zipper to the first element in the structure matching predfn. A linear scan @@ -124,8 +124,8 @@ (providepath find-first (s/if-path [NODE s/pred] s/STAY - [NEXT (s/params-reset find-first)] - )) + [NEXT (s/params-reset find-first)])) + (declarepath ^{:doc "Navigate to every element reachable using calls to NEXT"} @@ -134,5 +134,4 @@ (providepath NEXT-WALK (s/stay-then-continue NEXT - NEXT-WALK - )) + NEXT-WALK)) diff --git a/test/com/rpl/specter/cljs_test_helpers.clj b/test/com/rpl/specter/cljs_test_helpers.clj index 0176219..d09c97c 100644 --- a/test/com/rpl/specter/cljs_test_helpers.clj +++ b/test/com/rpl/specter/cljs_test_helpers.clj @@ -10,4 +10,4 @@ `(cljs.test.check.generators/return ~vars) (reverse parts))] `(cljs.test.check.properties/for-all [~vars ~genned] - ~@body ))) + ~@body))) diff --git a/test/com/rpl/specter/cljs_test_runner.cljs b/test/com/rpl/specter/cljs_test_runner.cljs index 070e965..fd8e55a 100644 --- a/test/com/rpl/specter/cljs_test_runner.cljs +++ b/test/com/rpl/specter/cljs_test_runner.cljs @@ -1,8 +1,8 @@ (ns com.rpl.specter.cljs-test-runner (:require [cljs.test :as test :refer-macros [run-tests]] [com.rpl.specter.core-test] - [com.rpl.specter.zipper-test] - )) + [com.rpl.specter.zipper-test])) + (run-tests 'com.rpl.specter.core-test) (run-tests 'com.rpl.specter.zipper-test) diff --git a/test/com/rpl/specter/core_test.cljc b/test/com/rpl/specter/core_test.cljc index 591de59..92104f9 100644 --- a/test/com/rpl/specter/core_test.cljc +++ b/test/com/rpl/specter/core_test.cljc @@ -1,15 +1,15 @@ (ns com.rpl.specter.core-test #?(:cljs (:require-macros - [cljs.test :refer [is deftest]] - [cljs.test.check.cljs-test :refer [defspec]] - [com.rpl.specter.cljs-test-helpers :refer [for-all+]] - [com.rpl.specter.test-helpers :refer [ic-test]] - [com.rpl.specter.macros - :refer [paramsfn defprotocolpath defnav extend-protocolpath - nav declarepath providepath select select-one select-one! - select-first transform setval replace-in defnavconstructor - select-any selected-any? collected? traverse - multi-transform]])) + [cljs.test :refer [is deftest]] + [cljs.test.check.cljs-test :refer [defspec]] + [com.rpl.specter.cljs-test-helpers :refer [for-all+]] + [com.rpl.specter.test-helpers :refer [ic-test]] + [com.rpl.specter.macros + :refer [paramsfn defprotocolpath defnav extend-protocolpath + nav declarepath providepath select select-one select-one! + select-first transform setval replace-in defnavconstructor + select-any selected-any? collected? traverse + multi-transform]])) (:use #?(:clj [clojure.test :only [deftest is]]) #?(:clj [clojure.test.check.clojure-test :only [defspec]]) @@ -19,9 +19,9 @@ nav declarepath providepath select select-one select-one! select-first transform setval replace-in defnavconstructor select-any selected-any? collected? traverse - multi-transform]]) + multi-transform]])) + - ) (:require #?(:clj [clojure.test.check.generators :as gen]) #?(:clj [clojure.test.check.properties :as prop]) @@ -55,8 +55,8 @@ (gen-map-with-keys gen/keyword gen/int kw))) pred (gen/elements [odd? even?])] (= (select [s/ALL kw pred] v) - (->> v (map kw) (filter pred)) - ))) + (->> v (map kw) (filter pred))))) + (defspec select-pos-extreme-pred (for-all+ @@ -64,48 +64,48 @@ pred (gen/elements [odd? even?]) pos (gen/elements [[s/FIRST first] [s/LAST last]])] (= (select-one [(s/filterer pred) (first pos)] v) - (->> v (filter pred) ((last pos))) - ))) + (->> v (filter pred) ((last pos)))))) + (defspec select-all-on-map (for-all+ [m (limit-size 5 (gen/map gen/keyword gen/int)) p (gen/elements [s/MAP-VALS [s/ALL s/LAST]])] (= (select p m) - (for [[k v] m] v)) - )) + (for [[k v] m] v)))) + (deftest select-one-test (is (thrown? #?(:clj Exception :cljs js/Error) (select-one [s/ALL even?] [1 2 3 4]))) - (is (= 1 (select-one [s/ALL odd?] [2 4 1 6]))) - ) + (is (= 1 (select-one [s/ALL odd?] [2 4 1 6])))) + (deftest select-first-test (is (= 7 (select-first [(s/filterer odd?) s/ALL #(> % 4)] [3 4 2 3 7 5 9 8]))) - (is (nil? (select-first [s/ALL even?] [1 3 5 9]))) - ) + (is (nil? (select-first [s/ALL even?] [1 3 5 9])))) + (defspec transform-all-on-map (for-all+ [m (limit-size 5 (gen/map gen/keyword gen/int)) p (gen/elements [s/MAP-VALS [s/ALL s/LAST]])] (= (transform p inc m) - (into {} (for [[k v] m] [k (inc v)])) - ))) + (into {} (for [[k v] m] [k (inc v)]))))) + (defspec transform-all (for-all+ [v (gen/vector gen/int)] (let [v2 (transform [s/ALL] inc v)] - (and (vector? v2) (= v2 (map inc v))) - ))) + (and (vector? v2) (= v2 (map inc v)))))) + (defspec transform-all-list (for-all+ [v (gen/list gen/int)] (let [v2 (transform [s/ALL] inc v)] - (and (seq? v2) (= v2 (map inc v))) - ))) + (and (seq? v2) (= v2 (map inc v)))))) + (defspec transform-all-filter (for-all+ @@ -113,24 +113,24 @@ pred (gen/elements [odd? even?]) action (gen/elements [inc dec])] (let [v2 (transform [s/ALL pred] action v)] - (= v2 (map (fn [v] (if (pred v) (action v) v)) v)) - ))) + (= v2 (map (fn [v] (if (pred v) (action v) v)) v))))) + (defspec transform-last (for-all+ [v (gen/not-empty (gen/vector gen/int)) pred (gen/elements [inc dec])] (let [v2 (transform [s/LAST] pred v)] - (= v2 (concat (butlast v) [(pred (last v))])) - ))) + (= v2 (concat (butlast v) [(pred (last v))]))))) + (defspec transform-first (for-all+ [v (gen/not-empty (gen/vector gen/int)) pred (gen/elements [inc dec])] (let [v2 (transform [s/FIRST] pred v)] - (= v2 (concat [(pred (first v))] (rest v) )) - ))) + (= v2 (concat [(pred (first v))] (rest v)))))) + (defspec transform-filterer-all-equivalency (prop/for-all @@ -141,8 +141,8 @@ (let [v (into target-type s) v2 (transform [(s/filterer pred) s/ALL] updater v) v3 (transform [s/ALL pred] updater v)] - (and (= v2 v3) (= (type v2) (type v3))) - ))) + (and (= v2 v3) (= (type v2) (type v3)))))) + (defspec transform-with-context (for-all+ @@ -153,8 +153,8 @@ (= (transform [(s/collect-one kw2) kw1 pred] + m) (if (pred (kw1 m)) (assoc m kw1 (+ (kw1 m) (kw2 m))) - m - )))) + m)))) + (defn differing-elements [v1 v2] (->> (map vector v1 v2) @@ -171,8 +171,8 @@ differing-elems (differing-elements v v2)] (and (= (count v2) (count v)) (= (count differing-elems) 1) - (every? (complement pred) (drop (first differing-elems) v2)) - )))) + (every? (complement pred) (drop (first differing-elems) v2)))))) + ;; max sizes prevent too much data from being generated and keeps test from taking forever (defspec transform-keyword @@ -187,8 +187,8 @@ pred (gen/elements [inc dec])] (let [m2 (transform [k1 k2] pred m1)] (and (= (assoc-in m1 [k1 k2] nil) (assoc-in m2 [k1 k2] nil)) - (= (pred (get-in m1 [k1 k2])) (get-in m2 [k1 k2]))) - ))) + (= (pred (get-in m1 [k1 k2])) (get-in m2 [k1 k2])))))) + (defspec replace-in-test (for-all+ @@ -200,8 +200,8 @@ (apply concat)) user-ret (if (empty? user-ret) nil user-ret)] (= (replace-in [s/ALL even?] (fn [v] [(inc v) [v v]]) v) - [res user-ret] - )))) + [res user-ret])))) + (defspec replace-in-custom-merge (for-all+ @@ -211,8 +211,8 @@ user-ret (if last-even {:a last-even})] (= (replace-in [s/ALL even?] (fn [v] [(inc v) v]) v :merge-fn (fn [curr new] (assoc curr :a new))) - [res user-ret] - )))) + [res user-ret])))) + (defspec srange-extremes-test (for-all+ @@ -221,15 +221,15 @@ (let [b (setval s/BEGINNING v2 v) e (setval s/END v2 v)] (and (= b (concat v2 v)) - (= e (concat v v2))) - ))) + (= e (concat v v2)))))) + (defspec srange-test (for-all+ [v (gen/vector gen/int) b (gen/elements (-> v count inc range)) - e (gen/elements (range b (-> v count inc))) - ] + e (gen/elements (range b (-> v count inc)))] + (let [sv (subvec v b e) predcount (fn [pred v] (->> v (filter pred) count)) even-count (partial predcount even?) @@ -237,13 +237,13 @@ b (transform (s/srange b e) (fn [r] (filter odd? r)) v)] (and (= (odd-count v) (odd-count b)) (= (+ (even-count b) (even-count sv)) - (even-count v))) - ))) + (even-count v)))))) + (deftest structure-path-directly-test (is (= 3 (select-one :b {:a 1 :b 3}))) - (is (= 5 (select-one (s/comp-paths :a :b) {:a {:b 5}}))) - ) + (is (= 5 (select-one (s/comp-paths :a :b) {:a {:b 5}})))) + (deftest atom-test (let [v (transform s/ATOM inc (atom 1))] @@ -256,23 +256,23 @@ afn (gen/elements [inc dec])] (= (first (select (s/view afn) i)) (afn i) - (transform (s/view afn) identity i) - ))) + (transform (s/view afn) identity i)))) + (defspec must-test (for-all+ [k1 gen/int k2 (gen/such-that #(not= k1 %) gen/int) m (gen-map-with-keys gen/int gen/int k1) - op (gen/elements [inc dec]) - ] + op (gen/elements [inc dec])] + (let [m (dissoc m k2)] (and (= (transform (s/must k1) op m) (transform (s/keypath k1) op m)) (= (transform (s/must k2) op m) m) (= (select (s/must k1) m) (select (s/keypath k1) m)) - (empty? (select (s/must k2) m)) - )))) + (empty? (select (s/must k2) m)))))) + (defspec parser-test (for-all+ @@ -283,18 +283,18 @@ (and (= (select-one! (s/parser afn bfn) i) (afn i)) (= (transform (s/parser afn bfn) cfn i) - (-> i afn cfn bfn)) - ))) + (-> i afn cfn bfn))))) + (deftest selected?-test (is (= [[1 3 5] [2 :a] [7 11 4 2 :a] [10 1 :a] []] (setval [s/ALL (s/selected? s/ALL even?) s/END] [:a] - [[1 3 5] [2] [7 11 4 2] [10 1] []] - ))) + [[1 3 5] [2] [7 11 4 2] [10 1] []]))) + (is (= [2 4] (select [s/ALL (s/selected? even?)] [1 2 3 4]))) - (is (= [1 3] (select [s/ALL (s/not-selected? even?)] [1 2 3 4]))) - ) + (is (= [1 3] (select [s/ALL (s/not-selected? even?)] [1 2 3 4])))) + (defspec identity-test (for-all+ @@ -313,8 +313,8 @@ c gen/int] (= (transform [(s/putval c) kw] + m) (transform [kw (s/putval c)] + m) - (assoc m kw (+ c (get m kw))) - ))) + (assoc m kw (+ c (get m kw)))))) + (defspec empty-selector-test (for-all+ @@ -324,8 +324,8 @@ (select nil v) (select (s/comp-paths) v) (select (s/comp-paths nil) v) - (select [nil nil nil] v) - ))) + (select [nil nil nil] v)))) + (defspec empty-selector-transform-test (for-all+ @@ -335,20 +335,20 @@ (transform nil identity m) (transform [] identity m) (transform (s/comp-paths []) identity m) - (transform (s/comp-paths nil nil) identity m) - ) + (transform (s/comp-paths nil nil) identity m)) + (= (transform kw inc m) (transform [nil kw] inc m) (transform (s/comp-paths kw nil) inc m) - (transform (s/comp-paths nil kw nil) inc m) - )))) + (transform (s/comp-paths nil kw nil) inc m))))) + (deftest compose-empty-comp-path-test (let [m {:a 1}] (is (= [1] (select [:a (s/comp-paths)] m) - (select [(s/comp-paths) :a] m) - )))) + (select [(s/comp-paths) :a] m))))) + (defspec mixed-selector-test (for-all+ @@ -364,8 +364,8 @@ (select [(s/comp-paths k1) k2] m) (select [(s/comp-paths k1 k2) nil] m) (select [(s/comp-paths) k1 k2] m) - (select [k1 (s/comp-paths) k2] m) - ))) + (select [k1 (s/comp-paths) k2] m)))) + (deftest cond-path-test (is (= [4 2 6 8 10] @@ -376,16 +376,16 @@ (is (= [6 2 10 6 14] (transform [(s/putval 2) s/ALL - (s/if-path odd? [(s/view inc) (s/view inc)] (s/view dec))] + (s/if-path odd? [(s/view inc) (s/view inc)] (s/view dec))] * - [1 2 3 4 5] - ))) + [1 2 3 4 5]))) + (is (= 2 (transform [(s/putval 2) - (s/if-path odd? (s/view inc))] + (s/if-path odd? (s/view inc))] * - 2))) - ) + 2)))) + (defspec cond-path-selector-test (for-all+ @@ -399,48 +399,48 @@ k1 k2 k3)) - pred (gen/elements [odd? even?]) - ] + pred (gen/elements [odd? even?])] + (let [v1 (get m k1) k (if (pred v1) k2 k3)] (and (= (transform (s/if-path [k1 pred] k2 k3) inc m) (transform k inc m)) (= (select (s/if-path [k1 pred] k2 k3) m) - (select k m)) - )))) + (select k m)))))) + (deftest optimized-if-path-test (is (= [-4 -2] (select [s/ALL (s/if-path [even? neg?] s/STAY)] [1 2 -3 -4 0 -2]))) (is (= [1 2 -3 4 0 2] (transform [s/ALL (s/if-path [even? neg?] s/STAY)] - - [1 2 -3 -4 0 -2]))) - ) + [1 2 -3 -4 0 -2])))) + (defspec multi-path-test (for-all+ [k1 (limit-size 3 gen/keyword) - k2 (limit-size 3 gen/keyword) - m (limit-size 5 - (gen-map-with-keys - gen/keyword - gen/int - k1 - k2)) - ] + k2 (limit-size 3 gen/keyword) + m (limit-size 5 + (gen-map-with-keys + gen/keyword + gen/int + k1 + k2))] + (= (transform (s/multi-path k1 k2) inc m) (->> m (transform k1 inc) - (transform k2 inc))) - )) + (transform k2 inc))))) + (deftest empty-pos-transform (is (empty? (select s/FIRST []))) (is (empty? (select s/LAST []))) (is (= [] (transform s/FIRST inc []))) - (is (= [] (transform s/LAST inc []))) - ) + (is (= [] (transform s/LAST inc [])))) + (defspec set-filter-test (for-all+ @@ -448,13 +448,13 @@ k2 (gen/such-that #(not= k1 %) gen/keyword) k3 (gen/such-that (complement #{k1 k2}) gen/keyword) v (gen/vector (gen/elements [k1 k2 k3]))] - (= (filter #{k1 k2} v) (select [s/ALL #{k1 k2}] v)) - )) + (= (filter #{k1 k2} v) (select [s/ALL #{k1 k2}] v)))) + (deftest nil-select-one-test (is (= nil (select-one! s/ALL [nil]))) - (is (thrown? #?(:clj Exception :cljs js/Error) (select-one! s/ALL []))) - ) + (is (thrown? #?(:clj Exception :cljs js/Error) (select-one! s/ALL [])))) + (defspec transformed-test @@ -463,8 +463,8 @@ pred (gen/elements [even? odd?]) op (gen/elements [inc dec])] (= (select-one (s/transformed [s/ALL pred] op) v) - (transform [s/ALL pred] op v)) - )) + (transform [s/ALL pred] op v)))) + (defspec basic-parameterized-composition-test (for-all+ @@ -475,12 +475,12 @@ gen/keyword (gen-map-with-keys gen/keyword gen/int k2) k1)) - pred (gen/elements [inc dec])] + pred (gen/elements [inc dec])] (let [p (s/comp-paths s/keypath s/keypath)] (and (= (s/compiled-select (p k1 k2) m1) (select [k1 k2] m1)) - (= (s/compiled-transform (p k1 k2) pred m1) (transform [k1 k2] pred m1)) - )))) + (= (s/compiled-transform (p k1 k2) pred m1) (transform [k1 k2] pred m1)))))) + (defspec various-orders-comp-test (for-all+ @@ -495,24 +495,24 @@ (gen-map-with-keys gen/keyword gen/int - k3 - ) + k3) + k2) k1)) - pred (gen/elements [inc dec])] + pred (gen/elements [inc dec])] (let [paths [((s/comp-paths s/keypath s/keypath k3) k1 k2) (s/comp-paths k1 k2 k3) ((s/comp-paths s/keypath k2 s/keypath) k1 k3) ((s/comp-paths k1 s/keypath k3) k2) (s/comp-paths k1 (s/keypath k2) k3) ((s/comp-paths (s/keypath k1) s/keypath (s/keypath k3)) k2) - ((s/comp-paths s/keypath (s/keypath k2) s/keypath) k1 k3) - ] - ] + ((s/comp-paths s/keypath (s/keypath k2) s/keypath) k1 k3)]] + + (and (apply = (for [p paths] (s/compiled-select p m1))) - (apply = (for [p paths] (s/compiled-transform p pred m1))) - )))) + (apply = (for [p paths] (s/compiled-transform p pred m1))))))) + (defspec filterer-param-test (for-all+ @@ -524,8 +524,8 @@ gen/keyword gen/int k - k2 - ))) + k2))) + pred (gen/elements [odd? even?]) updater (gen/elements [inc dec])] (and @@ -536,8 +536,8 @@ v) (s/compiled-transform (s/comp-paths (s/filterer k pred) s/ALL k2) updater - v)) - ))) + v))))) + (deftest nested-param-paths (let [p (s/filterer s/keypath (s/selected? s/ALL s/keypath (s/filterer s/keypath even?) s/ALL)) @@ -545,13 +545,13 @@ p3 (s/filterer :a (s/selected? s/ALL :b (s/filterer :c even?) s/ALL)) data [{:a [{:b [{:c 4 :d 5}]}]} {:a [{:c 3}]} - {:a [{:b [{:c 7}] :e [1]}]}] - ] + {:a [{:b [{:c 7}] :e [1]}]}]] + (is (= (select p2 data) (select p3 data) - [[{:a [{:b [{:c 4 :d 5}]}]}]] - )) - )) + [[{:a [{:b [{:c 4 :d 5}]}]}]])))) + + (defspec subselect-nested-vectors (for-all+ @@ -581,8 +581,8 @@ v)] (and (= (map k v) (reverse (map k v2))) (= (map #(dissoc % k) v) - (map #(dissoc % k) v2))) ; only key k was touched in any of the maps - )))) + (map #(dissoc % k) v2))))))) ; only key k was touched in any of the maps + (defspec param-multi-path-test (for-all+ @@ -595,28 +595,28 @@ gen/int k1 k2 - k3 - )) + k3)) + pred1 (gen/elements [odd? even?]) pred2 (gen/elements [odd? even?]) - updater (gen/elements [inc dec]) - ] - (let [paths [((s/multi-path [s/keypath pred1] [s/keypath pred2] k3) k1 k2) - ((s/multi-path [k1 pred1] [s/keypath pred2] s/keypath) k2 k3) - ((s/multi-path [s/keypath pred1] [s/keypath pred2] s/keypath) k1 k2 k3) - (s/multi-path [k1 pred1] [k2 pred2] k3) - ((s/multi-path [k1 pred1] [s/keypath pred2] k3) k2) - ]] - (and - (apply = - (for [p paths] - (select p m) - )) - (apply = - (for [p paths] - (transform p updater m) - )) - )))) + updater (gen/elements [inc dec])] + + (let [paths [((s/multi-path [s/keypath pred1] [s/keypath pred2] k3) k1 k2) + ((s/multi-path [k1 pred1] [s/keypath pred2] s/keypath) k2 k3) + ((s/multi-path [s/keypath pred1] [s/keypath pred2] s/keypath) k1 k2 k3) + (s/multi-path [k1 pred1] [k2 pred2] k3) + ((s/multi-path [k1 pred1] [s/keypath pred2] k3) k2)]] + + (and + (apply = + (for [p paths] + (select p m))) + + (apply = + (for [p paths] + (transform p updater m))))))) + + (defspec paramsfn-test (for-all+ @@ -626,8 +626,8 @@ comparator (gen/elements [= > <])] (let [cpath (s/comp-paths s/ALL (paramsfn [p] [v] (comparator v p)))] (= (transform (cpath val) op v) - (transform [s/ALL #(comparator % val)] op v))) - )) + (transform [s/ALL #(comparator % val)] op v))))) + (defspec subset-test (for-all+ @@ -644,8 +644,8 @@ (and (= (transform (s/subset s3) identity combined) combined) (= (setval (s/subset s3) #{} combined) (set/difference combined s2)) - (= (setval (s/subset s3) s4 combined) (-> combined (set/difference s2) (set/union s4))) - )))) + (= (setval (s/subset s3) s4 combined) (-> combined (set/difference s2) (set/union s4))))))) + (deftest submap-test (is (= [{:foo 1}] @@ -665,8 +665,8 @@ (is (= {:a #{:b :c :d}} (setval [:a s/NIL->SET (s/subset #{})] #{:b} {:a #{:c :d}}))) (is (= {:a [:b]} - (setval [:a s/NIL->VECTOR s/END] [:b] nil))) - ) + (setval [:a s/NIL->VECTOR s/END] [:b] nil)))) + (defspec void-test (for-all+ @@ -677,8 +677,8 @@ (= s1 (transform s/STOP inc s1)) (= s1 (transform [s/ALL s/STOP s/ALL] inc s1)) (= (transform [s/ALL (s/cond-path even? nil odd? s/STOP)] inc s1) - (transform [s/ALL even?] inc s1)) - ))) + (transform [s/ALL even?] inc s1))))) + (deftest stay-continue-tests (is (= [[1 2 [:a :b]] [3 [:a :b]] [:a :b [:a :b]]] @@ -688,8 +688,8 @@ (is (= [[1 2 3] 1 3] (select (s/stay-then-continue s/ALL odd?) [1 2 3]))) (is (= [1 3 [1 2 3]] - (select (s/continue-then-stay s/ALL odd?) [1 2 3]))) - ) + (select (s/continue-then-stay s/ALL odd?) [1 2 3])))) + (declarepath MyWalker) @@ -698,19 +698,19 @@ (s/if-path vector? (s/if-path [s/FIRST #(= :abc %)] (s/continue-then-stay s/ALL MyWalker) - [s/ALL MyWalker] - ))) + [s/ALL MyWalker]))) + (deftest recursive-path-test (is (= [9 1 10 3 1] (select [MyWalker s/ALL number?] - [:bb [:aa 34 [:abc 10 [:ccc 9 8 [:abc 9 1]]]] [:abc 1 [:abc 3]]]) - )) + [:bb [:aa 34 [:abc 10 [:ccc 9 8 [:abc 9 1]]]] [:abc 1 [:abc 3]]]))) + (is (= [:bb [:aa 34 [:abc 11 [:ccc 9 8 [:abc 10 2]]]] [:abc 2 [:abc 4]]] (transform [MyWalker s/ALL number?] inc - [:bb [:aa 34 [:abc 10 [:ccc 9 8 [:abc 9 1]]]] [:abc 1 [:abc 3]]]) - )) - ) + [:bb [:aa 34 [:abc 10 [:ccc 9 8 [:abc 9 1]]]] [:abc 1 [:abc 3]]])))) + + (declarepath map-key-walker [akey]) @@ -722,23 +722,23 @@ (deftest recursive-params-path-test (is (= #{1 2 3} (set (select (map-key-walker :aaa) - {:a {:aaa 3 :b {:c {:aaa 2} :aaa 1}}})))) + {:a {:aaa 3 :b {:c {:aaa 2} :aaa 1}}})))) (is (= {:a {:aaa 4 :b {:c {:aaa 3} :aaa 2}}} (transform (map-key-walker :aaa) inc {:a {:aaa 3 :b {:c {:aaa 2} :aaa 1}}}))) (is (= {:a {:c {:b "X"}}} - (setval (map-key-walker :b) "X" {:a {:c {:b {:d 1}}}}))) - ) + (setval (map-key-walker :b) "X" {:a {:c {:b {:d 1}}}})))) + (deftest recursive-params-composable-path-test (let [p (s/comp-paths s/keypath map-key-walker)] - (is (= [1] (select (p 1 :a) [{:a 3} {:a 1} {:a 2}]))) - )) + (is (= [1] (select (p 1 :a) [{:a 3} {:a 1} {:a 2}]))))) + (deftest all-map-test (is (= {3 3} (transform [s/ALL s/FIRST] inc {2 3}))) - (is (= {3 21 4 31} (transform [s/ALL s/ALL] inc {2 20 3 30}))) - ) + (is (= {3 21 4 31} (transform [s/ALL s/ALL] inc {2 20 3 30})))) + (declarepath NestedHigherOrderWalker [k]) @@ -746,113 +746,113 @@ (s/if-path vector? (s/if-path [s/FIRST (paramsfn [k] [e] (= k e))] (s/continue-then-stay s/ALL (s/params-reset NestedHigherOrderWalker)) - [s/ALL (s/params-reset NestedHigherOrderWalker)] - ))) + [s/ALL (s/params-reset NestedHigherOrderWalker)]))) + (deftest nested-higher-order-walker-test (is (= [:q [:abc :I 3] [:ccc [:abc :I] [:abc :I "a" [:abc :I [:abc :I [:d]]]]]] (setval [(NestedHigherOrderWalker :abc) (s/srange 1 1)] - [:I] - [:q [:abc 3] [:ccc [:abc] [:abc "a" [:abc [:abc [:d]]]]]] - )))) + [:I] + [:q [:abc 3] [:ccc [:abc] [:abc "a" [:abc [:abc [:d]]]]]])))) + #?(:clj -(deftest large-params-test - (let [path (apply s/comp-paths (repeat 25 s/keypath)) - m (reduce - (fn [m k] - {k m}) - :a - (reverse (range 25)))] - (is (= :a (select-one (apply path (range 25)) m))) - ))) + (deftest large-params-test + (let [path (apply s/comp-paths (repeat 25 s/keypath)) + m (reduce + (fn [m k] + {k m}) + :a + (reverse (range 25)))] + (is (= :a (select-one (apply path (range 25)) m)))))) + ;;TODO: there's a bug in clojurescript that won't allow ;; non function implementations of IFn to have more than 20 arguments #?(:clj -(do - (defprotocolpath AccountPath []) - (defrecord Account [funds]) - (defrecord User [account]) - (defrecord Family [accounts]) - (extend-protocolpath AccountPath User :account Family [:accounts s/ALL]) - )) - -#?(:clj -(deftest protocolpath-basic-test - (let [data [(->User (->Account 30)) - (->User (->Account 50)) - (->Family [(->Account 51) (->Account 52)])]] - (is (= [30 50 51 52] - (select [s/ALL AccountPath :funds] data))) - (is (= [(->User (->Account 31)) - (->User (->Account 51)) - (->Family [(->Account 52) (->Account 53)])] - (transform [s/ALL AccountPath :funds] - inc - data))) - ))) - -#?(:clj -(do - (defprotocolpath LabeledAccountPath [label]) - (defrecord LabeledUser [account]) - (defrecord LabeledFamily [accounts]) - (extend-protocolpath LabeledAccountPath - LabeledUser [:account s/keypath] - LabeledFamily [:accounts s/keypath s/ALL]) - )) - -#?(:clj -(deftest protocolpath-params-test - (let [data [(->LabeledUser {:a (->Account 30)}) - (->LabeledUser {:a (->Account 50)}) - (->LabeledFamily {:a [(->Account 51) (->Account 52)]})]] - (is (= [30 50 51 52] - (select [s/ALL (LabeledAccountPath :a) :funds] data))) - (is (= [(->LabeledUser {:a (->Account 31)}) - (->LabeledUser {:a (->Account 51)}) - (->LabeledFamily {:a [(->Account 52) (->Account 53)]})] - (transform [s/ALL (LabeledAccountPath :a) :funds] - inc - data))) - ))) + (do + (defprotocolpath AccountPath []) + (defrecord Account [funds]) + (defrecord User [account]) + (defrecord Family [accounts]) + (extend-protocolpath AccountPath User :account Family [:accounts s/ALL]))) #?(:clj -(do - (defprotocolpath CustomWalker []) - (extend-protocolpath CustomWalker - Object nil - clojure.lang.PersistentHashMap [(s/keypath :a) CustomWalker] - clojure.lang.PersistentArrayMap [(s/keypath :a) CustomWalker] - clojure.lang.PersistentVector [s/ALL CustomWalker] - ))) + (deftest protocolpath-basic-test + (let [data [(->User (->Account 30)) + (->User (->Account 50)) + (->Family [(->Account 51) (->Account 52)])]] + (is (= [30 50 51 52] + (select [s/ALL AccountPath :funds] data))) + (is (= [(->User (->Account 31)) + (->User (->Account 51)) + (->Family [(->Account 52) (->Account 53)])] + (transform [s/ALL AccountPath :funds] + inc + data)))))) + #?(:clj -(deftest mixed-rich-regular-protocolpath - (is (= [1 2 3 11 21 22 25] - (select [CustomWalker number?] [{:a [1 2 :c [3]]} [[[[[[11]]] 21 [22 :c 25]]]]]))) - (is (= [2 3 [[[4]] :b 0] {:a 4 :b 10}] - (transform [CustomWalker number?] inc [1 2 [[[3]] :b -1] {:a 3 :b 10}]))) - )) + (do + (defprotocolpath LabeledAccountPath [label]) + (defrecord LabeledUser [account]) + (defrecord LabeledFamily [accounts]) + (extend-protocolpath LabeledAccountPath + LabeledUser [:account s/keypath] + LabeledFamily [:accounts s/keypath s/ALL]))) + + +#?(:clj + (deftest protocolpath-params-test + (let [data [(->LabeledUser {:a (->Account 30)}) + (->LabeledUser {:a (->Account 50)}) + (->LabeledFamily {:a [(->Account 51) (->Account 52)]})]] + (is (= [30 50 51 52] + (select [s/ALL (LabeledAccountPath :a) :funds] data))) + (is (= [(->LabeledUser {:a (->Account 31)}) + (->LabeledUser {:a (->Account 51)}) + (->LabeledFamily {:a [(->Account 52) (->Account 53)]})] + (transform [s/ALL (LabeledAccountPath :a) :funds] + inc + data)))))) + + + +#?(:clj + (do + (defprotocolpath CustomWalker []) + (extend-protocolpath CustomWalker + Object nil + clojure.lang.PersistentHashMap [(s/keypath :a) CustomWalker] + clojure.lang.PersistentArrayMap [(s/keypath :a) CustomWalker] + clojure.lang.PersistentVector [s/ALL CustomWalker]))) + + +#?(:clj + (deftest mixed-rich-regular-protocolpath + (is (= [1 2 3 11 21 22 25] + (select [CustomWalker number?] [{:a [1 2 :c [3]]} [[[[[[11]]] 21 [22 :c 25]]]]]))) + (is (= [2 3 [[[4]] :b 0] {:a 4 :b 10}] + (transform [CustomWalker number?] inc [1 2 [[[3]] :b -1] {:a 3 :b 10}]))))) + #?( -:clj -(defn make-queue [coll] - (reduce - #(conj %1 %2) - clojure.lang.PersistentQueue/EMPTY - coll)) + :clj + (defn make-queue [coll] + (reduce + #(conj %1 %2) + clojure.lang.PersistentQueue/EMPTY + coll)) + + :cljs + (defn make-queue [coll] + (reduce + #(conj %1 %2) + #queue [] + coll))) -:cljs -(defn make-queue [coll] - (reduce - #(conj %1 %2) - #queue [] - coll)) -) (defspec transform-idempotency 50 (for-all+ @@ -896,8 +896,8 @@ (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}))) - ) + (is (= 3 (select-one! (some-keypath 1 2 3 4 5) {"a" 1 "a!" 2 "bbb" 3 "d" 4})))) + (def ^:dynamic *APATH* s/keypath) @@ -936,8 +936,8 @@ (*APATH* k) str {:a 1 :b 2} - [[:a] [:b] [:c]] - ) + [[:a] [:b] [:c]]) + (binding [*APATH* s/must] (ic-test false @@ -945,50 +945,50 @@ (*APATH* k) inc {:a 1 :b 2} - [[:a] [:b] [:c]] - )) + [[:a] [:b] [:c]])) + (ic-test true [k k2] [s/ALL (s/selected? (s/must k) #(> % 2)) (s/must k2)] dec [{:a 1 :b 2} {:a 10 :b 6} {:c 7 :b 8} {:c 1 :d 9} {:c 3 :d -1}] - [[:a :b] [:b :a] [:c :d] [:b :c]] - ) + [[:a :b] [:b :a] [:c :d] [:b :c]]) + (ic-test true [] [(s/transformed s/STAY inc)] inc 10 - [] - ) + []) + (s/must-cache-paths!) (is (thrown? #?(:clj Exception :cljs js/Error) - (select (if true :a :b) nil) - )) + (select (if true :a :b) nil))) + (is (thrown? #?(:clj Exception :cljs js/Error) - (select (*APATH* :a) nil) - )) + (select (*APATH* :a) nil))) + (is (thrown? #?(:clj Exception :cljs js/Error) - (select [:a (identity even?)] {:a 2}) - )) + (select [:a (identity even?)] {:a 2}))) + ;; this tests a bug that existed before ^:staticparam annotation ;; for pathedfns (is (thrown? #?(:clj Exception :cljs js/Error) - (select [(s/putval 10) (s/transformed s/STAY #(inc %))] 10) - )) + (select [(s/putval 10) (s/transformed s/STAY #(inc %))] 10))) + (let [p :a] (is (thrown? #?(:clj Exception :cljs js/Error) - (select [p even?] {:a 2}) - ))) + (select [p even?] {:a 2})))) + (let [p :a] (is (thrown? #?(:clj Exception :cljs js/Error) - (select [s/ALL (s/selected? p even?)] [{:a 2}]) - ))) - (s/must-cache-paths! false) - ) + (select [s/ALL (s/selected? p even?)] [{:a 2}])))) + + (s/must-cache-paths! false)) + (deftest nested-inline-caching-test (is (= [[1]] @@ -998,52 +998,52 @@ (fn [v] (select [(s/keypath v) (s/keypath a)] {:a {:b 1}}))) - :a - )))) - ) + :a))))) + + (defspec continuous-subseqs-filter-equivalence (for-all+ [aseq (gen/vector (gen/elements [1 2 3 :a :b :c 4 5 :d :e])) pred (gen/elements [keyword? number?])] (= (setval (s/continuous-subseqs pred) nil aseq) - (filter (complement pred) aseq)) - )) + (filter (complement pred) aseq)))) + (deftest continuous-subseqs-test (is (= [1 "ab" 2 3 "c" 4 "def"] (transform (s/continuous-subseqs string?) (fn [s] [(apply str s)]) - [1 "a" "b" 2 3 "c" 4 "d" "e" "f"] - ))) + [1 "a" "b" 2 3 "c" 4 "d" "e" "f"]))) + (is (= [[] [2] [4 6]] (select [(s/continuous-subseqs number?) (s/filterer even?)] - [1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"] - ))) - ) + [1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"])))) + + ;; there was a bug where the transform-fn was being factored by inline caching ;; this verifies that it doesn't do inline caching (deftest transformed-inline-caching (dotimes [i 10] - (is (= [(inc i)] (select (s/transformed s/STAY #(+ % i)) 1))) - )) + (is (= [(inc i)] (select (s/transformed s/STAY #(+ % i)) 1))))) + ;; test for issue #103 (deftest nil->val-regression-test (is (= false (transform (s/nil->val true) identity false))) - (is (= false (select-one! (s/nil->val true) false))) - ) + (is (= false (select-one! (s/nil->val true) false)))) + #?(:clj -(deftest all-map-entry - (let [e (transform s/ALL inc (first {1 3}))] - (is (instance? clojure.lang.MapEntry e)) - (is (= 2 (key e))) - (is (= 4 (val e))) - ))) + (deftest all-map-entry + (let [e (transform s/ALL inc (first {1 3}))] + (is (instance? clojure.lang.MapEntry e)) + (is (= 2 (key e))) + (is (= 4 (val e)))))) + (deftest select-on-empty-vector (is (= s/NONE (select-any s/ALL []))) @@ -1054,8 +1054,8 @@ (is (nil? (select-first s/FIRST []))) (is (nil? (select-one s/FIRST []))) (is (nil? (select-first s/LAST []))) - (is (nil? (select-one s/LAST []))) - ) + (is (nil? (select-one s/LAST [])))) + (defspec select-first-one-any-equivalency (for-all+ @@ -1067,17 +1067,17 @@ r3 (select-one [s/ALL (s/pred apred)] data) r4 (first (select [s/ALL (s/pred apred)] data)) r5 (select-any [s/FIRST (s/pred apred)] data) - r6 (select-any [s/LAST (s/pred apred)] data) - ] + r6 (select-any [s/LAST (s/pred apred)] data)] + (or (and (= r1 s/NONE) (nil? r2) (nil? r3) (nil? r4) (= r5 s/NONE) (= r6 s/NONE)) - (and (not= r1 s/NONE) (some? r1) (= r1 r2 r3 r4 r5 r6))) - ))) + (and (not= r1 s/NONE) (some? r1) (= r1 r2 r3 r4 r5 r6)))))) + (deftest select-any-static-fn (is (= 2 (select-any even? 2))) - (is (= s/NONE (select-any odd? 2))) - ) + (is (= s/NONE (select-any odd? 2)))) + (deftest select-any-keywords (is (= s/NONE (select-any [:a even?] {:a 1}))) @@ -1086,8 +1086,8 @@ (is (= 2 (select-any [(s/keypath "a") even?] {"a" 2}))) (is (= s/NONE (select-any (s/must :b) {:a 1 :c 3}))) (is (= 2 (select-any (s/must :b) {:a 1 :b 2 :c 3}))) - (is (= s/NONE (select-any [(s/must :b) odd?] {:a 1 :b 2 :c 3}))) - ) + (is (= s/NONE (select-any [(s/must :b) odd?] {:a 1 :b 2 :c 3})))) + (defspec select-any-ALL (for-all+ @@ -1096,21 +1096,21 @@ (let [r1 (select [s/ALL pred] v) r2 (select-any [s/ALL pred] v)] (or (and (empty? r1) (= s/NONE r2)) - (contains? (set r1) r2) - )))) + (contains? (set r1) r2))))) + (deftest select-any-beginning-end (is (= [] (select-any s/BEGINNING [1 2 3]) (select-any s/END [1]))) - (is (= s/NONE (select-any [s/BEGINNING s/STOP] [1 2 3]) (select-any [s/END s/STOP] [2 3]))) - ) + (is (= s/NONE (select-any [s/BEGINNING s/STOP] [1 2 3]) (select-any [s/END s/STOP] [2 3])))) + (deftest select-any-walker (let [data [1 [2 3 4] [[6]]]] (is (= s/NONE (select-any (s/walker keyword?) data))) (is (= s/NONE (select-any [(s/walker number?) neg?] data))) (is (#{1 3} (select-any [(s/walker number?) odd?] data))) - (is (#{2 4 6} (select-any [(s/walker number?) even?] data))) - )) + (is (#{2 4 6} (select-any [(s/walker number?) even?] data))))) + (defspec selected-any?-select-equivalence (for-all+ @@ -1118,8 +1118,8 @@ pred (gen/elements [even? odd?])] (let [r1 (not (empty? (select [s/ALL pred] v))) r2 (selected-any? [s/ALL pred] v)] - (= r1 r2) - ))) + (= r1 r2)))) + (defn div-by-3? [v] (= 0 (mod v 3))) @@ -1130,29 +1130,29 @@ pred (gen/elements [even? odd?])] (and (= (select-any [s/ALL pred] v) - (select-any [s/ALL (s/selected? pred)] v) - ) + (select-any [s/ALL (s/selected? pred)] v)) + (= (select-any [s/ALL pred div-by-3?] v) - (select-any [s/ALL (s/selected? pred) div-by-3?] v) - ) - ))) + (select-any [s/ALL (s/selected? pred) div-by-3?] v))))) + + (deftest multi-path-select-any-test (is (= s/NONE (select-any (s/multi-path s/STOP s/STOP) 1))) (is (= 1 (select-any (s/multi-path s/STAY s/STOP) 1) (select-any (s/multi-path s/STOP s/STAY) 1) - (select-any (s/multi-path s/STOP s/STAY s/STOP) 1) - )) - (is (= s/NONE (select-any [(s/multi-path s/STOP s/STAY) even?] 1))) - ) + (select-any (s/multi-path s/STOP s/STAY s/STOP) 1))) + + (is (= s/NONE (select-any [(s/multi-path s/STOP s/STAY) even?] 1)))) + (deftest if-path-select-any-test (is (= s/NONE (select-any (s/if-path even? s/STAY) 1))) (is (= 2 (select-any (s/if-path even? s/STAY s/STAY) 2))) (is (= s/NONE (select-any [(s/if-path even? s/STAY s/STAY) odd?] 2))) (is (= 2 (select-any (s/if-path odd? s/STOP s/STAY) 2))) - (is (= s/NONE (select-any [(s/if-path odd? s/STOP s/STAY) odd?] 2))) - ) + (is (= s/NONE (select-any [(s/if-path odd? s/STOP s/STAY) odd?] 2)))) + (defspec transient-vector-test (for-all+ @@ -1202,13 +1202,13 @@ (is (nil? (transform s/ALL inc nil))) (is (empty? (select s/FIRST nil))) (is (empty? (select s/LAST nil))) - (is (empty? (select s/ALL nil))) - ) + (is (empty? (select s/ALL nil)))) + (deftest map-vals-nil (is (= nil (transform s/MAP-VALS inc nil))) - (is (empty? (select s/MAP-VALS nil))) - ) + (is (empty? (select s/MAP-VALS nil)))) + (defspec dispense-test (for-all+ @@ -1224,8 +1224,8 @@ m) (select [(s/collect-one (s/keypath k2)) (s/keypath k3)] - m) - ))) + m)))) + (deftest collected?-test (let [data {:active-id 1 :items [{:id 1 :name "a"} {:id 2 :name "b"}]}] @@ -1235,18 +1235,18 @@ s/ALL (s/collect-one :id) (collected? [a i] (= a i)) - s/DISPENSE - ] - data) + s/DISPENSE] + + data) (select-any [(s/collect-one :active-id) :items s/ALL (s/collect-one :id) (collected? v (apply = v)) - s/DISPENSE - ] - data) - ))) + s/DISPENSE] + + data)))) + (let [data {:active 3 :items [{:id 1 :val 0} {:id 3 :val 11}]}] (is (= (transform [:items s/ALL (s/selected? :id #(= % 3)) :val] inc data) (transform [(s/collect-one :active) @@ -1257,8 +1257,8 @@ s/DISPENSE :val] inc - data) - )))) + data))))) + (defspec traverse-test (for-all+ @@ -1269,8 +1269,8 @@ (= (reduce + (traverse [s/ALL p] v)) (reduce + (filter p v))) (= (reduce + i (traverse [s/ALL p] v)) - (reduce + i (filter p v))) - ))) + (reduce + i (filter p v)))))) + (declarepath KeyAccumWalker [k]) (providepath KeyAccumWalker @@ -1286,8 +1286,8 @@ (is (= {"e1" {"e2" {"e1" "e1e2e1" "e2" "e1e2e2"}}} (transform (KeyAccumWalker :template) (fn [& all] (apply str (butlast all))) - data))) - )) + data))))) + (deftest multi-path-vals-test (is (= {:a 1 :b 6 :c 3} @@ -1296,14 +1296,14 @@ {:a 1 :b 2 :c 3}))) (is (= [[1 2] [3 2]] (select [(s/multi-path (s/collect-one :a) (s/collect-one :c)) :b] - {:a 1 :b 2 :c 3}))) - ) + {:a 1 :b 2 :c 3})))) + (deftest sorted-map-by-transform (let [amap (sorted-map-by > 1 10 2 20 3 30)] (is (= [3 2 1] (keys (transform s/MAP-VALS inc amap)))) - (is (= [3 2 1] (keys (transform [s/ALL s/LAST] inc amap)))) - )) + (is (= [3 2 1] (keys (transform [s/ALL s/LAST] inc amap)))))) + (deftest setval-vals-collection-test (is (= 2 (setval s/VAL 2 :a)))) @@ -1317,17 +1317,17 @@ (multi-transform (s/multi-path [(s/keypath kw1) s/VAL (s/terminal +)] [(s/keypath kw2) (s/terminal dec)]) - m - )))) + m)))) + (deftest multi-transform-overrun-error - (is (thrown? #?(:clj Exception :cljs js/Error) (multi-transform s/STAY 3))) - ) + (is (thrown? #?(:clj Exception :cljs js/Error) (multi-transform s/STAY 3)))) + (deftest terminal-val-test (is (= 3 (multi-transform (s/terminal-val 3) 2))) - (is (= 3 (multi-transform [s/VAL (s/terminal-val 3)] 2))) - ) + (is (= 3 (multi-transform [s/VAL (s/terminal-val 3)] 2)))) + (deftest multi-path-order-test @@ -1337,8 +1337,7 @@ [odd? (s/terminal #(* 2 %))] [even? (s/terminal-val 100)] [#(= 100 %) (s/terminal inc)] - [#(= 101 %) (s/terminal inc)] + [#(= 101 %) (s/terminal inc)]) - ) - 1 - )))) + + 1)))) diff --git a/test/com/rpl/specter/test_helpers.clj b/test/com/rpl/specter/test_helpers.clj index 6a1b4a0..f304b43 100644 --- a/test/com/rpl/specter/test_helpers.clj +++ b/test/com/rpl/specter/test_helpers.clj @@ -1,9 +1,9 @@ (ns com.rpl.specter.test-helpers - (:require [clojure.test.check + (:require [clojure.test.check [generators :as gen] [properties :as prop]] - [clojure.test] - ) + [clojure.test]) + (:use [com.rpl.specter.macros :only [select transform]] [com.rpl.specter :only [select* transform* must-cache-paths!]])) @@ -19,7 +19,7 @@ `(gen/return ~vars) (reverse parts))] `(prop/for-all [~vars ~genned] - ~@body ))) + ~@body))) (defmacro ic-test [must-cache? params-decl apath transform-fn data params] @@ -29,13 +29,12 @@ icfntran# (fn [~@params-decl] (transform ~apath ~transform-fn ~data)) regfnsel# (fn [~@params-decl] (select* ~apath ~data)) regfntran# (fn [~@params-decl] (transform* ~apath ~transform-fn ~data)) - params# (if (empty? ~params) [[]] ~params) - ] + params# (if (empty? ~params) [[]] ~params)] + (must-cache-paths! ~must-cache?) (dotimes [_# 3] (doseq [ps# params#] (~is-sym (= (apply icfnsel# ps#) (apply regfnsel# ps#))) - (~is-sym (= (apply icfntran# ps#) (apply regfntran# ps#))) - )) - (must-cache-paths! false) - ))) + (~is-sym (= (apply icfntran# ps#) (apply regfntran# ps#))))) + + (must-cache-paths! false)))) diff --git a/test/com/rpl/specter/zipper_test.cljc b/test/com/rpl/specter/zipper_test.cljc index 63730a2..d845f22 100644 --- a/test/com/rpl/specter/zipper_test.cljc +++ b/test/com/rpl/specter/zipper_test.cljc @@ -1,20 +1,20 @@ (ns com.rpl.specter.zipper-test #?(:cljs (:require-macros - [cljs.test :refer [is deftest]] - [cljs.test.check.cljs-test :refer [defspec]] - [com.rpl.specter.cljs-test-helpers :refer [for-all+]] - [com.rpl.specter.macros - :refer [declarepath providepath select select-one select-one! - select-first transform setval replace-in]] - )) + [cljs.test :refer [is deftest]] + [cljs.test.check.cljs-test :refer [defspec]] + [com.rpl.specter.cljs-test-helpers :refer [for-all+]] + [com.rpl.specter.macros + :refer [declarepath providepath select select-one select-one! + select-first transform setval replace-in]])) + (:use #?(:clj [clojure.test :only [deftest is]]) #?(:clj [clojure.test.check.clojure-test :only [defspec]]) #?(:clj [com.rpl.specter.test-helpers :only [for-all+]]) #?(:clj [com.rpl.specter.macros :only [declarepath providepath select select-one select-one! - select-first transform setval replace-in]]) - ) + select-first transform setval replace-in]])) + (:require #?(:clj [clojure.test.check.generators :as gen]) #?(:clj [clojure.test.check.properties :as prop]) #?(:cljs [cljs.test.check :as tc]) @@ -28,8 +28,8 @@ [v (gen/not-empty (gen/vector gen/int)) i (gen/vector gen/int)] (= (setval s/END i v) - (setval [z/VECTOR-ZIP z/DOWN z/RIGHTMOST z/INNER-RIGHT] i v)) - )) + (setval [z/VECTOR-ZIP z/DOWN z/RIGHTMOST z/INNER-RIGHT] i v)))) + (deftest zipper-multi-insert-test (is (= [1 2 :a :b 3 :a :b 4] @@ -37,22 +37,22 @@ z/DOWN z/RIGHT z/RIGHT - (s/multi-path z/INNER-RIGHT z/INNER-LEFT) - ] + (s/multi-path z/INNER-RIGHT z/INNER-LEFT)] + [:a :b] - [1 2 3 4] - ) - (setval [z/VECTOR-ZIP - z/DOWN - z/RIGHT - z/RIGHT - (s/multi-path z/INNER-LEFT z/INNER-RIGHT) - ] - [:a :b] - [1 2 3 4] - ) - )) - ) + [1 2 3 4]) + + (setval [z/VECTOR-ZIP + z/DOWN + z/RIGHT + z/RIGHT + (s/multi-path z/INNER-LEFT z/INNER-RIGHT)] + + [:a :b] + [1 2 3 4])))) + + + (deftest zipper-down-up-test (is (= [1 [2 3 5] 6] @@ -67,9 +67,9 @@ [z/UP z/RIGHT]) z/NODE] inc - [1 [2 3 4] 5] - ))) - ) + [1 [2 3 4] 5])))) + + (deftest next-terminate-test @@ -83,10 +83,10 @@ (s/selected? z/NODE number? even?) z/NODE-SEQ] [] - [1 2 [3 [[4]] 5] 6] - ) - )) - ) + [1 2 [3 [[4]] 5] 6])))) + + + (deftest zipper-nav-stop-test (is (= [1] @@ -96,19 +96,19 @@ (is (= [1] (transform [z/VECTOR-ZIP z/DOWN z/RIGHT z/NODE] inc [1]))) (is (= [] - (transform [z/VECTOR-ZIP z/DOWN z/NODE] inc []))) - ) + (transform [z/VECTOR-ZIP z/DOWN z/NODE] inc [])))) + (deftest find-first-test (is (= [1 [3 [[4]] 5] 6] (setval [z/VECTOR-ZIP (z/find-first #(and (number? %) (even? %))) - z/NODE-SEQ - ] + z/NODE-SEQ] + [] - [1 2 [3 [[4]] 5] 6]) - )) - ) + [1 2 [3 [[4]] 5] 6])))) + + (deftest nodeseq-expand-test (is (= [2 [2] [[4 4 4]] 4 4 4 6] @@ -119,6 +119,4 @@ z/NODE-SEQ] (fn [v _] (repeat v (inc v))) - [1 [2] [[3]] 3 6] - ))) - ) + [1 [2] [[3]] 3 6]))))