summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Halloway <stu@thinkrelevance.com>2010-04-22 21:45:24 -0400
committerStuart Halloway <stu@thinkrelevance.com>2010-04-24 14:34:34 -0400
commitc73a4bad6297251ab5545affd6baf79d2390f8c6 (patch)
treecdd708a0a1bb4732236ed91fd52869bfb12fdc99
parentc487e48a65ee7cef66ef017c87a754fc88ba57e0 (diff)
re-import changed deftype, see #303
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
-rw-r--r--src/clj/clojure/core_deftype.clj3
-rw-r--r--src/jvm/clojure/lang/Namespace.java26
-rw-r--r--test/clojure/test_clojure/ns_libs.clj39
3 files changed, 63 insertions, 5 deletions
diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj
index 0a90356e..f18b690f 100644
--- a/src/clj/clojure/core_deftype.clj
+++ b/src/clj/clojure/core_deftype.clj
@@ -18,7 +18,6 @@
(vector name (vec (map tag args)) (tag name)))
cname (with-meta (symbol (str *ns* "." name)) (meta name))]
`(do (gen-interface :name ~cname :methods ~(vec (map psig sigs)))
- (ns-unmap (find-ns '~(ns-name *ns*)) '~name)
(import ~cname))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;; reify/deftype ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -289,7 +288,6 @@
~(emit-defrecord name gname (vec hinted-fields) (vec interfaces) methods)
(defmethod print-method ~classname [o# w#]
((var print-defrecord) o# w#))
- (ns-unmap (find-ns '~(ns-name *ns*)) '~name)
(import ~classname)
#_(defn ~name
([~@fields] (new ~classname ~@fields nil nil))
@@ -379,7 +377,6 @@
fields (vec (map #(with-meta % nil) fields))]
`(do
~(emit-deftype* name gname (vec hinted-fields) (vec interfaces) methods)
- (ns-unmap (find-ns '~(ns-name *ns*)) '~name)
(import ~classname))))
diff --git a/src/jvm/clojure/lang/Namespace.java b/src/jvm/clojure/lang/Namespace.java
index 09d87037..85505d91 100644
--- a/src/jvm/clojure/lang/Namespace.java
+++ b/src/jvm/clojure/lang/Namespace.java
@@ -86,6 +86,30 @@ Object reference(Symbol sym, Object val){
throw new IllegalStateException(sym + " already refers to: " + o + " in namespace: " + name);
}
+public static boolean areDifferentInstancesOfSameClassName(Class cls1, Class cls2) {
+ return (cls1 != cls2) && (cls1.getName().equals(cls2.getName()));
+}
+
+Class referenceClass(Symbol sym, Class val){
+ if(sym.ns != null)
+ {
+ throw new IllegalArgumentException("Can't intern namespace-qualified symbol");
+ }
+ IPersistentMap map = getMappings();
+ Class c = (Class) map.valAt(sym);
+ while((c == null) || (areDifferentInstancesOfSameClassName(c, val)))
+ {
+ IPersistentMap newMap = map.assoc(sym, val);
+ mappings.compareAndSet(map, newMap);
+ map = getMappings();
+ c = (Class) map.valAt(sym);
+ }
+ if(c == val)
+ return c;
+
+ throw new IllegalStateException(sym + " already refers to: " + c + " in namespace: " + name);
+}
+
public void unmap(Symbol sym) throws Exception{
if(sym.ns != null)
{
@@ -101,7 +125,7 @@ public void unmap(Symbol sym) throws Exception{
}
public Class importClass(Symbol sym, Class c){
- return (Class) reference(sym, c);
+ return referenceClass(sym, c);
}
diff --git a/test/clojure/test_clojure/ns_libs.clj b/test/clojure/test_clojure/ns_libs.clj
index c5b9666a..10844ded 100644
--- a/test/clojure/test_clojure/ns_libs.clj
+++ b/test/clojure/test_clojure/ns_libs.clj
@@ -6,7 +6,7 @@
; the terms of this license.
; You must not remove this notice, or any other, from this software.
-; Author: Frantisek Sodomka
+; Authors: Frantisek Sodomka, Stuart Halloway
(ns clojure.test-clojure.ns-libs
(:use clojure.test))
@@ -34,3 +34,40 @@
(is (thrown? Exception (use :foo)))
(is (thrown? Exception (use))))
+(deftest reimporting-deftypes
+ (let [inst1 (binding [*ns* *ns*]
+ (eval '(do (ns exporter)
+ (defrecord ReimportMe [a])
+ (ns importer)
+ (import exporter.ReimportMe)
+ (ReimportMe. 1))))
+ inst2 (binding [*ns* *ns*]
+ (eval '(do (ns exporter)
+ (defrecord ReimportMe [a b])
+ (ns importer)
+ (import exporter.ReimportMe)
+ (ReimportMe. 1 2))))]
+ (testing "you can reimport a changed class and see the changes"
+ (is (= [:a] (keys inst1)))
+ (is (= [:a :b] (keys inst2))))
+ (testing "you cannot import same local name from a different namespace"
+ (is (thrown? clojure.lang.Compiler$CompilerException
+ #"ReimportMe already refers to: class exporter.ReimportMe in namespace: importer"
+ (binding [*ns* *ns*]
+ (eval '(do (ns exporter-2)
+ (defrecord ReimportMe [a b])
+ (ns importer)
+ (import exporter-2.ReimportMe)
+ (ReimportMe. 1 2)))))))))
+
+(deftest naming-types
+ (testing "you cannot use a name already referred from another namespace"
+ (is (thrown? IllegalStateException
+ #"String already refers to: class java.lang.String"
+ (definterface String)))
+ (is (thrown? IllegalStateException
+ #"StringBuffer already refers to: class java.lang.StringBuffer"
+ (deftype StringBuffer [])))
+ (is (thrown? IllegalStateException
+ #"Integer already refers to: class java.lang.Integer"
+ (defrecord Integer [])))))