From 9b9005448b2c56ef197a87d75a4fe6019a814f30 Mon Sep 17 00:00:00 2001 From: "Michael S. Klishin" Date: Tue, 6 Mar 2012 19:38:40 +0400 Subject: [PATCH] Implement monger.internal.fn/expand-all-with --- src/monger/internal/fn.clj | 46 +++++++++++++++++++++----------- test/monger/test/internal/fn.clj | 9 ++++++- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/monger/internal/fn.clj b/src/monger/internal/fn.clj index 04f3690..46b4a6c 100644 --- a/src/monger/internal/fn.clj +++ b/src/monger/internal/fn.clj @@ -19,41 +19,55 @@ (into {} (for [[k v] m] [k (f v)]))) - ;; ;; API ;; +(defn fpartial + "Like clojure.core/partial but prepopulates last N arguments (first is passed in later)" + [f & args] + (fn [arg & more] (apply f arg (concat args more)))) + (defprotocol IFNExpansion - (expand-all [x] "Invokes functions, recursively expands maps, evaluates all other values to themselves")) + (expand-all [x] "Replaces functions with their invocation results, recursively expands maps, evaluates all other values to themselves") + (expand-all-with [x f] "Replaces functions with their invocation results that function f is applied to, recursively expands maps, evaluates all other values to themselves")) (extend-protocol IFNExpansion java.lang.Integer - (expand-all [i] i) + (expand-all [i] i) + (expand-all-with [i f] i) java.lang.Long - (expand-all [l] l) + (expand-all [l] l) + (expand-all-with [l f] l) java.lang.String - (expand-all [s] s) + (expand-all [s] s) + (expand-all-with [s f] s) java.lang.Float - (expand-all [f] f) + (expand-all [fl] fl) + (expand-all-with [fl f] fl) java.lang.Double - (expand-all [d] d) + (expand-all [d] d) + (expand-all-with [d f] d) - java.util.Map - (expand-all [m] (apply-to-values m expand-all)) + ;; maps are also functions, so be careful here. MK. + clojure.lang.IPersistentMap + (expand-all [m] (apply-to-values m expand-all)) + (expand-all-with [m f] (apply-to-values m (fpartial expand-all-with f))) clojure.lang.PersistentVector - (expand-all [v] (map expand-all v)) + (expand-all [v] (map expand-all v)) + (expand-all-with [v f] (map (fpartial expand-all-with f) v)) - clojure.lang.APersistentMap - (expand-all [m] (apply-to-values m expand-all)) - - clojure.lang.IFn - (expand-all [f] (f)) + ;; this distinguishes functions from maps, sets and so on, which are also + ;; clojure.lang.AFn subclasses. MK. + clojure.lang.AFunction + (expand-all [f] (f)) + (expand-all-with [f expander] (expander (f))) Object - (expand-all [x] x)) + (expand-all [x] x) + (expand-all-with [x f] x)) diff --git a/test/monger/test/internal/fn.clj b/test/monger/test/internal/fn.clj index 62064bf..4d7c72b 100644 --- a/test/monger/test/internal/fn.clj +++ b/test/monger/test/internal/fn.clj @@ -3,7 +3,7 @@ [monger.internal.fn])) -(deftest test-recursive-function-values-expansion +(deftest test-expand-all (are [i o] (is (= (expand-all i) o)) { :int (fn [] 1) :str "Clojure" :float (Float/valueOf 11.0) } { :int 1 :str "Clojure" :float (Float/valueOf 11.0 )} { :long (fn [] (Long/valueOf 11)) } { :long (Long/valueOf 11) } @@ -36,3 +36,10 @@ :nested { :a { :b { :c "d" } } } } })) + +(deftest test-expand-all-with + (let [expander-fn (fn [v] + (* 3 v))] + (are [i o] (is (= (expand-all-with i expander-fn) o)) + { :a 1 :int (fn [] 3) } { :a 1 :int 9 } + { :v [(fn [] 1) (fn [] 11)] :m { :inner (fn [] 3) } :s "Clojure" } { :v [3 33] :m { :inner 9 } :s "Clojure" })))