Permalink
Browse files

*default-data-reader-fn* for handling unknown tags

Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
  • Loading branch information...
1 parent 4784f4c commit 79a1b793f87af417b430450f3c24e7cfe456e3e2 @miner miner committed with stuarthalloway Oct 20, 2012
View
@@ -6819,6 +6819,13 @@
data_readers.clj or by rebinding this Var."
{})
+(def ^{:added "1.5" :dynamic true} *default-data-reader-fn*
+ "When no data reader is found for a tag and *default-data-reader-fn*
+ is non-nil, it will be called with two arguments,
+ the tag and the value. If *default-data-reader-fn* is nil (the
+ default), an exception will be thrown for the unknown tag."
+ nil)
+
(defn- data-reader-urls []
(enumeration-seq
(.. Thread currentThread getContextClassLoader
@@ -1179,8 +1179,13 @@ private Object readTagged(PushbackReader reader, Symbol tag){
if(data_reader == null){
data_readers = (ILookup)RT.DEFAULT_DATA_READERS.deref();
data_reader = (IFn)RT.get(data_readers, tag);
- if(data_reader == null)
+ if(data_reader == null){
+ IFn default_reader = (IFn)RT.DEFAULT_DATA_READER_FN.deref();
+ if(default_reader != null)
+ return default_reader.invoke(tag, o);
+ else
throw new RuntimeException("No reader function for tag " + tag.toString());
+ }
}
return data_reader.invoke(o);
@@ -183,6 +183,7 @@
final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.intern("*agent*"), null).setDynamic();
final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.intern("*read-eval*"), T).setDynamic();
final static public Var DATA_READERS = Var.intern(CLOJURE_NS, Symbol.intern("*data-readers*"), RT.map()).setDynamic();
+final static public Var DEFAULT_DATA_READER_FN = Var.intern(CLOJURE_NS, Symbol.intern("*default-data-reader-fn*"), RT.map()).setDynamic();
final static public Var DEFAULT_DATA_READERS = Var.intern(CLOJURE_NS, Symbol.intern("default-data-readers"), RT.map());
final static public Var ASSERT = Var.intern(CLOJURE_NS, Symbol.intern("*assert*"), T).setDynamic();
final static public Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.intern("*math-context*"), null).setDynamic();
@@ -541,3 +541,33 @@
(is (= 4 (.version #uuid "550e8400-e29b-41d4-a716-446655440000")))
(is (= (print-str #uuid "550e8400-e29b-41d4-a716-446655440000")
"#uuid \"550e8400-e29b-41d4-a716-446655440000\"")))
+
+(deftest unknown-tag
+ (let [my-unknown (fn [tag val] {:unknown-tag tag :value val})
+ throw-on-unknown (fn [tag val] (throw (RuntimeException. (str "No data reader function for tag " tag))))
+ my-uuid (partial my-unknown 'uuid)
+ u "#uuid \"550e8400-e29b-41d4-a716-446655440000\""
+ s "#never.heard.of/some-tag [1 2]" ]
+ (binding [*data-readers* {'uuid my-uuid}
+ *default-data-reader-fn* my-unknown]
+ (testing "Unknown tag"
+ (is (= (read-string s)
+ {:unknown-tag 'never.heard.of/some-tag
+ :value [1 2]})))
+ (testing "Override uuid tag"
+ (is (= (read-string u)
+ {:unknown-tag 'uuid
+ :value "550e8400-e29b-41d4-a716-446655440000"}))))
+
+ (binding [*default-data-reader-fn* throw-on-unknown]
+ (testing "Unknown tag with custom throw-on-unknown"
+ (are [err msg form] (thrown-with-msg? err msg (read-string form))
+ Exception #"No data reader function for tag foo" "#foo [1 2]"
+ Exception #"No data reader function for tag bar/foo" "#bar/foo [1 2]"
+ Exception #"No data reader function for tag bar.baz/foo" "#bar.baz/foo [1 2]")))
+
+ (testing "Unknown tag out-of-the-box behavior (like Clojure 1.4)"
+ (are [err msg form] (thrown-with-msg? err msg (read-string form))
+ Exception #"No reader function for tag foo" "#foo [1 2]"
+ Exception #"No reader function for tag bar/foo" "#bar/foo [1 2]"
+ Exception #"No reader function for tag bar.baz/foo" "#bar.baz/foo [1 2]"))))

0 comments on commit 79a1b79

Please sign in to comment.