git.fiddlerwoaroof.com
out/clojure/walk.cljs
cde696c2
 ;   Copyright (c) Rich Hickey. All rights reserved.
 ;   The use and distribution terms for this software are covered by the
 ;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
 ;   which can be found in the file epl-v10.html at the root of this distribution.
 ;   By using this software in any fashion, you are agreeing to be bound by
 ;   the terms of this license.
 ;   You must not remove this notice, or any other, from this software.
 
 ;;; walk.cljs - generic tree walker with replacement
 
 ;; by Stuart Sierra
 ;; Jul5 17, 2011
 
 ;; CHANGE LOG:
 ;;
 ;; * July 17, 2011: Port to ClojureScript
 ;; 
 ;; * December 15, 2008: replaced 'walk' with 'prewalk' & 'postwalk'
 ;;
 ;; * December 9, 2008: first version
 
 
 (ns 
   ^{:author "Stuart Sierra",
      :doc "This file defines a generic tree walker for Clojure data
 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."}
   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. Consumes seqs as with doall."
 
   {:added "1.1"}
   [inner outer form]
   (cond
     (list? form)   (outer (apply list (map inner form)))
     (seq? form)    (outer (doall (map inner form)))
     (record? form) (outer (reduce (fn [r x] (conj r (inner x))) form 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. Consumes seqs as with doall."
   {:added "1.1"}
   [f form]
   (walk (partial postwalk f) f form))
 
 (defn prewalk
   "Like postwalk, but does pre-order traversal."
   {:added "1.1"}
   [f form]
   (walk (partial prewalk f) identity (f form)))
 
 (defn keywordize-keys
   "Recursively transforms all map keys from strings to keywords."
   {:added "1.1"}
   [m]
   (let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))]
     ;; only apply to maps
     (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
 
 (defn stringify-keys
   "Recursively transforms all map keys from keywords to strings."
   {:added "1.1"}
   [m]
   (let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))]
     ;; only apply to maps
     (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
 
 (defn prewalk-replace
   "Recursively transforms form by replacing keys in smap with their
   values.  Like clojure/replace but works on any data structure.  Does
   replacement at the root of the tree first."
   {:added "1.1"}
   [smap form]
   (prewalk (fn [x] (if (contains? smap x) (smap x) x)) form))
 
 (defn postwalk-replace
   "Recursively transforms form by replacing keys in smap with their
   values.  Like clojure/replace but works on any data structure.  Does
   replacement at the leaves of the tree first."
   {:added "1.1"}
   [smap form]
   (postwalk (fn [x] (if (contains? smap x) (smap x) x)) form))