From 629338817926f4949389bfc648f7dd3511ba9007 Mon Sep 17 00:00:00 2001
From: Timothy Pratley <timothypratley@gmail.com>
Date: Thu, 28 Jan 2010 16:18:09 +1100
Subject: [PATCH] Added sorted-by support for walk and tests

---
 src/clj/clojure/walk.clj                   |   25 ++++--------
 test/clojure/test_clojure.clj              |    1 +
 test/clojure/test_clojure/clojure_walk.clj |   56 ++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 17 deletions(-)
 create mode 100644 test/clojure/test_clojure/clojure_walk.clj

diff --git a/src/clj/clojure/walk.clj b/src/clj/clojure/walk.clj
index b025705..0eb0d45 100644
--- a/src/clj/clojure/walk.clj
+++ b/src/clj/clojure/walk.clj
@@ -25,35 +25,26 @@ structures.  It takes any data structure (list, vector, map, set,
 seq), calls a function on every element, and uses the return value
 of the function in place of the original.  This makes it fairly
 easy to write recursive search-and-replace functions, as shown in
-the examples.
-
-Note: \"walk\" supports all Clojure data structures EXCEPT maps
-created with sorted-map-by.  There is no (obvious) way to retrieve
-the sorting function."}
+the examples."}
   clojure.walk)
 
 (defn walk
   "Traverses form, an arbitrary data structure.  inner and outer are
   functions.  Applies inner to each element of form, building up a
   data structure of the same type, then applies outer to the result.
-  Recognizes all Clojure data structures except sorted-map-by.
-  Consumes seqs as with doall."
+  Recognizes all Clojure data structures. Consumes seqs as with doall."
   [inner outer form]
   (cond
-   (list? form) (outer (apply list (map inner form)))
-   (seq? form) (outer (doall (map inner form)))
-   (vector? form) (outer (vec (map inner form)))
-   (map? form) (outer (into (if (sorted? form) (sorted-map) {})
-                            (map inner form)))
-   (set? form) (outer (into (if (sorted? form) (sorted-set) #{})
-                            (map inner form)))
-   :else (outer form)))
+    (list? form) (outer (apply list (map inner form)))
+    (instance? clojure.lang.IMapEntry form) (outer (vec (map inner form)))
+    (seq? form) (outer (doall (map inner form)))
+    (coll? form) (outer (into (empty form) (map inner form)))
+    :else (outer form)))
 
 (defn postwalk
   "Performs a depth-first, post-order traversal of form.  Calls f on
   each sub-form, uses f's return value in place of the original.
-  Recognizes all Clojure data structures except sorted-map-by.
-  Consumes seqs as with doall."
+  Recognizes all Clojure data structures. Consumes seqs as with doall."
   [f form]
   (walk (partial postwalk f) f form))
 
diff --git a/test/clojure/test_clojure.clj b/test/clojure/test_clojure.clj
index ac264e0..e88a210 100644
--- a/test/clojure/test_clojure.clj
+++ b/test/clojure/test_clojure.clj
@@ -48,6 +48,7 @@
       :clojure-set
       :clojure-xml
       :clojure-zip
+      :clojure-walk
       ])
 
 (def test-namespaces
diff --git a/test/clojure/test_clojure/clojure_walk.clj b/test/clojure/test_clojure/clojure_walk.clj
new file mode 100644
index 0000000..7095522
--- /dev/null
+++ b/test/clojure/test_clojure/clojure_walk.clj
@@ -0,0 +1,56 @@
+(ns clojure.test-clojure.clojure-walk
+  (:require [clojure.walk :as w])
+  (:use clojure.test))
+
+(deftest t-prewalk-replace
+  (is (= (w/prewalk-replace {:a :b} [:a {:a :a} (list 3 :c :a)])
+         [:b {:b :b} (list 3 :c :b)])))
+
+(deftest t-postwalk-replace 
+  (is (= (w/postwalk-replace {:a :b} [:a {:a :a} (list 3 :c :a)])
+         [:b {:b :b} (list 3 :c :b)])))
+
+(deftest t-stringify-keys
+  (is (= (w/stringify-keys {:a 1, nil {:b 2 :c 3}, :d 4})
+         {"a" 1, nil {"b" 2 "c" 3}, "d" 4})))
+
+(deftest t-prewalk-order
+  (is (= (let [a (atom [])]
+           (w/prewalk (fn [form] (swap! a conj form) form)
+                      [1 2 {:a 3} (list 4 [5])])
+           @a)
+         [[1 2 {:a 3} (list 4 [5])]
+          1 2 {:a 3} [:a 3] :a 3 (list 4 [5])
+          4 [5] 5])))
+
+(deftest t-postwalk-order
+  (is (= (let [a (atom [])]
+           (w/postwalk (fn [form] (swap! a conj form) form)
+                      [1 2 {:a 3} (list 4 [5])])
+           @a)
+         [1 2
+          :a 3 [:a 3] {:a 3}
+          4 5 [5] (list 4 [5])
+          [1 2 {:a 3} (list 4 [5])]])))
+
+(deftest walk
+         "Checks that walk returns the correct result and type of collection"
+         (let [colls ['(1 2 3)
+                      [1 2 3]
+                      #{1 2 3}
+                      (sorted-set-by > 1 2 3)
+                      {:a 1, :b 2, :c 3}
+                      (sorted-map-by > 1 10, 2 20, 3 30)]]
+           (doseq [c colls]
+             (let [walked (w/walk identity identity c)]
+               (is (= c walked))
+               (is (= (type c) (type walked)))
+               (if (map? c)
+                 (is (= (w/walk #(update-in % [1] inc) #(reduce + (vals %)) c)
+                        (reduce + (map (comp inc val) c))))
+                 (is (= (w/walk inc #(reduce + %) c)
+                        (reduce + (map inc c)))))
+               (when (or (instance? clojure.lang.PersistentTreeMap c)
+                         (instance? clojure.lang.PersistentTreeSet c))
+                 (is (= (.comparator c) (.comparator walked))))))))
+
-- 
1.6.3.3

