aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clojure/contrib/java_utils.clj60
-rw-r--r--src/clojure/contrib/test_contrib.clj4
-rw-r--r--src/clojure/contrib/test_contrib/test_java_utils.clj37
3 files changed, 100 insertions, 1 deletions
diff --git a/src/clojure/contrib/java_utils.clj b/src/clojure/contrib/java_utils.clj
new file mode 100644
index 00000000..1ea420ea
--- /dev/null
+++ b/src/clojure/contrib/java_utils.clj
@@ -0,0 +1,60 @@
+; Copyright (c) Stuart Halloway, April 2009. 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.
+
+; Design goals:
+;
+; (1) Ease-of-use. These APIs should be convenient. Performance is secondary.
+;
+; (2) Duck typing. I hate having to think about the difference between
+; a string that names a file, and a File. Ditto for a ton of other
+; wrapper classes in the Java world (URL, InternetAddress). With these
+; APIs you should be able to think about domain equivalence, not type
+; equivalence.
+;
+; (3) No bossiness. I am not marking any of these functions as private;
+; the docstrings will tell you the intended usage but do what works for you.
+;
+; Feedback welcome!
+;
+; If something in this module violates the principle of least surprise, please
+; let me (Stu) and the Clojure community know via the mailing list.
+
+(ns clojure.contrib.java-utils
+ (:import [java.io File]))
+
+(defmulti relative-path-string
+ "Interpret a String or java.io.File as a relative path string.
+ Building block for clojure.contrib.java-utils/file."
+ class)
+
+(defmethod relative-path-string String [s]
+ (relative-path-string (File. s)))
+
+(defmethod relative-path-string File [f]
+ (if (.isAbsolute f)
+ (throw (IllegalArgumentException. (str f " is not a relative path")))
+ (.getPath f)))
+
+(defmulti as-file
+ "Interpret a String or a java.io.File as a File. Building block
+ for clojure.contrib.java-utils/file, which you should prefer
+ in most cases."
+ class)
+(defmethod as-file String [s] (File. s))
+(defmethod as-file File [f] f)
+
+(defn file
+ "Returns a java.io.File from string or file args."
+ ([arg]
+ (as-file arg))
+ ([parent child]
+ (File. (as-file parent) (relative-path-string child)))
+ ([parent child & more]
+ (reduce file (file parent child) more)))
+
+ \ No newline at end of file
diff --git a/src/clojure/contrib/test_contrib.clj b/src/clojure/contrib/test_contrib.clj
index 8e35e4b9..88e2b42e 100644
--- a/src/clojure/contrib/test_contrib.clj
+++ b/src/clojure/contrib/test_contrib.clj
@@ -16,7 +16,7 @@
(:use [clojure.contrib.test-is :only (run-tests)])
(:gen-class))
-(def test-names [:complex-numbers :monads :str-utils :shell-out :test-graph :test-dataflow])
+(def test-names [:complex-numbers :monads :str-utils :shell-out :test-graph :test-dataflow :test-java-utils])
(def test-namespaces
(map #(symbol (str "clojure.contrib.test-contrib." (name %)))
@@ -34,3 +34,5 @@
[& args]
(run)
(System/exit 0))
+
+(run) \ No newline at end of file
diff --git a/src/clojure/contrib/test_contrib/test_java_utils.clj b/src/clojure/contrib/test_contrib/test_java_utils.clj
new file mode 100644
index 00000000..9c536322
--- /dev/null
+++ b/src/clojure/contrib/test_contrib/test_java_utils.clj
@@ -0,0 +1,37 @@
+(ns clojure.contrib.test-contrib.test-java-utils
+ (:use clojure.contrib.test-is
+ clojure.contrib.java-utils)
+ (:import [java.io File]))
+
+(deftest test-relative-path-string
+ (testing "strings"
+ (is (= "foo" (relative-path-string "foo"))))
+ (testing "absolute path strings are forbidden"
+ (is (thrown? IllegalArgumentException (relative-path-string "/baz"))))
+ (testing "relative File paths"
+ (is (= "bar" (relative-path-string (File. "bar")))))
+ (testing "absolute File paths are forbidden"
+ (is (thrown? IllegalArgumentException (relative-path-string (File. "/quux")))))
+)
+
+(deftest test-as-file
+ (testing "strings"
+ (is (= (File. "foo") (as-file "foo"))))
+ (testing "Files"
+ (is (= (File. "bar") (as-file (File. "bar")))))
+)
+
+(deftest test-file
+ (testing "single argument"
+ (is (= (File. "foo") (file "foo"))))
+ (testing "two arguments"
+ (is (= (File. "foo/bar") (file "foo" "bar"))))
+ (testing "N arguments"
+ (is (= (File. "foo/bar/baz/quux") (file "foo" "bar" "baz" "quux"))))
+ (testing "no sneaking in absolute paths!"
+ (is (thrown? IllegalArgumentException (file "foo" "bar" "/boom" "baz" "quux"))))
+)
+
+
+
+