Mercurial > lasercutter
diff src/clojure/contrib/test_contrib/pprint/examples/json.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/contrib/test_contrib/pprint/examples/json.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,142 @@ 1.4 +;;; json.clj: A pretty printing version of the JavaScript Object Notation (JSON) generator 1.5 + 1.6 +;; by Tom Faulhaber, based on the version by Stuart Sierra (clojure.contrib.json.write) 1.7 +;; May 9, 2009 1.8 + 1.9 +;; Copyright (c) Tom Faulhaber/Stuart Sierra, 2009. All rights reserved. The use 1.10 +;; and distribution terms for this software are covered by the Eclipse 1.11 +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.12 +;; which can be found in the file epl-v10.html at the root of this 1.13 +;; distribution. By using this software in any fashion, you are 1.14 +;; agreeing to be bound by the terms of this license. You must not 1.15 +;; remove this notice, or any other, from this software. 1.16 + 1.17 + 1.18 +(ns 1.19 + #^{:author "Tom Faulhaber (based on the version by Stuart Sierra)", 1.20 + :doc "Pretty printing JavaScript Object Notation (JSON) generator. 1.21 + 1.22 +This is an example of using a pretty printer dispatch function to generate JSON output", 1.23 + :see-also [["http://json.org/", "JSON Home Page"]]} 1.24 + clojure.contrib.pprint.examples.json 1.25 + (:use [clojure.test :only (deftest- is)] 1.26 + [clojure.contrib.string :only (as-str)] 1.27 + [clojure.contrib.pprint :only (write formatter-out)])) 1.28 + 1.29 + 1.30 + 1.31 +(defmulti dispatch-json 1.32 + "The dispatch function for printing objects as JSON" 1.33 + {:arglists '[[x]]} 1.34 + (fn [x] (cond 1.35 + (nil? x) nil ;; prevent NullPointerException on next line 1.36 + (.isArray (class x)) ::array 1.37 + :else (type x)))) 1.38 + 1.39 +;; Primitive types can be printed with Clojure's pr function. 1.40 +(derive java.lang.Boolean ::pr) 1.41 +(derive java.lang.Byte ::pr) 1.42 +(derive java.lang.Short ::pr) 1.43 +(derive java.lang.Integer ::pr) 1.44 +(derive java.lang.Long ::pr) 1.45 +(derive java.lang.Float ::pr) 1.46 +(derive java.lang.Double ::pr) 1.47 + 1.48 +;; Collection types can be printed as JSON objects or arrays. 1.49 +(derive java.util.Map ::object) 1.50 +(derive java.util.Collection ::array) 1.51 + 1.52 +;; Symbols and keywords are converted to strings. 1.53 +(derive clojure.lang.Symbol ::symbol) 1.54 +(derive clojure.lang.Keyword ::symbol) 1.55 + 1.56 + 1.57 +(defmethod dispatch-json ::pr [x] (pr x)) 1.58 + 1.59 +(defmethod dispatch-json nil [x] (print "null")) 1.60 + 1.61 +(defmethod dispatch-json ::symbol [x] (pr (name x))) 1.62 + 1.63 +(defmethod dispatch-json ::array [s] 1.64 + ((formatter-out "~<[~;~@{~w~^, ~:_~}~;]~:>") s)) 1.65 + 1.66 +(defmethod dispatch-json ::object [m] 1.67 + ((formatter-out "~<{~;~@{~<~w:~_~w~:>~^, ~_~}~;}~:>") 1.68 + (for [[k v] m] [(as-str k) v]))) 1.69 + 1.70 +(defmethod dispatch-json java.lang.CharSequence [s] 1.71 + (print \") 1.72 + (dotimes [i (count s)] 1.73 + (let [cp (Character/codePointAt s i)] 1.74 + (cond 1.75 + ;; Handle printable JSON escapes before ASCII 1.76 + (= cp 34) (print "\\\"") 1.77 + (= cp 92) (print "\\\\") 1.78 + ;; Print simple ASCII characters 1.79 + (< 31 cp 127) (print (.charAt s i)) 1.80 + ;; Handle non-printable JSON escapes 1.81 + (= cp 8) (print "\\b") 1.82 + (= cp 12) (print "\\f") 1.83 + (= cp 10) (print "\\n") 1.84 + (= cp 13) (print "\\r") 1.85 + (= cp 9) (print "\\t") 1.86 + ;; Any other character is printed as Hexadecimal escape 1.87 + :else (printf "\\u%04x" cp)))) 1.88 + (print \")) 1.89 + 1.90 +(defn print-json 1.91 + "Prints x as JSON. Nil becomes JSON null. Keywords become 1.92 + strings, without the leading colon. Maps become JSON objects, all 1.93 + other collection types become JSON arrays. Java arrays become JSON 1.94 + arrays. Unicode characters in strings are escaped as \\uXXXX. 1.95 + Numbers print as with pr." 1.96 + [x] 1.97 + (write x :dispatch dispatch-json)) 1.98 + 1.99 +(defn json-str 1.100 + "Converts x to a JSON-formatted string." 1.101 + [x] 1.102 + (with-out-str (print-json x))) 1.103 + 1.104 + 1.105 + 1.106 +;;; TESTS 1.107 + 1.108 +;; Run these tests with 1.109 +;; (clojure.test/run-tests 'clojure.contrib.print-json) 1.110 + 1.111 +;; Bind clojure.test/*load-tests* to false to omit these 1.112 +;; tests from production code. 1.113 + 1.114 +(deftest- can-print-json-strings 1.115 + (is (= "\"Hello, World!\"" (json-str "Hello, World!"))) 1.116 + (is (= "\"\\\"Embedded\\\" Quotes\"" (json-str "\"Embedded\" Quotes")))) 1.117 + 1.118 +(deftest- can-print-unicode 1.119 + (is (= "\"\\u1234\\u4567\"" (json-str "\u1234\u4567")))) 1.120 + 1.121 +(deftest- can-print-json-null 1.122 + (is (= "null" (json-str nil)))) 1.123 + 1.124 +(deftest- can-print-json-arrays 1.125 + (is (= "[1, 2, 3]" (json-str [1 2 3]))) 1.126 + (is (= "[1, 2, 3]" (json-str (list 1 2 3)))) 1.127 + (is (= "[1, 2, 3]" (json-str (sorted-set 1 2 3)))) 1.128 + (is (= "[1, 2, 3]" (json-str (seq [1 2 3]))))) 1.129 + 1.130 +(deftest- can-print-java-arrays 1.131 + (is (= "[1, 2, 3]" (json-str (into-array [1 2 3]))))) 1.132 + 1.133 +(deftest- can-print-empty-arrays 1.134 + (is (= "[]" (json-str []))) 1.135 + (is (= "[]" (json-str (list)))) 1.136 + (is (= "[]" (json-str #{})))) 1.137 + 1.138 +(deftest- can-print-json-objects 1.139 + (is (= "{\"a\":1, \"b\":2}" (json-str (sorted-map :a 1 :b 2))))) 1.140 + 1.141 +(deftest- object-keys-must-be-strings 1.142 + (is (= "{\"1\":1, \"2\":2}" (json-str (sorted-map 1 1 2 2))))) 1.143 + 1.144 +(deftest- can-print-empty-objects 1.145 + (is (= "{}" (json-str {}))))