aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Sierra <mail@stuartsierra.com>2009-05-13 14:15:12 +0000
committerStuart Sierra <mail@stuartsierra.com>2009-05-13 14:15:12 +0000
commit295a1bf6e1e217b446a2415c8e777fd8770e6409 (patch)
tree37639b541db66fa5873153d9dabbc284d91d783f
parent68dae64556c970555317a21bcaae2bf0e1ee2cf4 (diff)
duck_streams.clj: added functions to open writers for appending
-rw-r--r--src/clojure/contrib/duck_streams.clj48
1 files changed, 44 insertions, 4 deletions
diff --git a/src/clojure/contrib/duck_streams.clj b/src/clojure/contrib/duck_streams.clj
index 60241910..4e8a4d11 100644
--- a/src/clojure/contrib/duck_streams.clj
+++ b/src/clojure/contrib/duck_streams.clj
@@ -1,7 +1,7 @@
;;; duck_streams.clj -- duck-typed I/O streams for Clojure
;; by Stuart Sierra, http://stuartsierra.com/
-;; May 3, 2009
+;; May 13, 2009
;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use
;; and distribution terms for this software are covered by the Eclipse
@@ -26,6 +26,8 @@
;; CHANGE LOG
;;
+;; May 13, 2009: added functions to open writers for appending
+;;
;; May 3, 2009: renamed file to file-str, for compatibility with
;; clojure.contrib.java-utils. reader/writer no longer use this
;; function.
@@ -121,6 +123,11 @@
(throw (Exception. (str "Cannot open " (pr-str x) " as a reader."))))
+(def
+ #^{:doc "If true, writer and spit will open files in append mode.
+ Defaults to false. Use append-writer or append-spit."}
+ *append-to-writer* false)
+
(defmulti #^{:tag PrintWriter
:doc "Attempts to coerce its argument into an open java.io.PrintWriter
@@ -137,22 +144,33 @@
:arglists '([x])}
writer class)
-(defmethod writer PrintWriter [x] x)
+(defn- assert-not-appending []
+ (when *append-to-writer*
+ (throw (Exception. "Cannot change an open stream to append mode."))))
+
+(defmethod writer PrintWriter [x]
+ (assert-not-appending)
+ x)
(defmethod writer BufferedWriter [#^BufferedWriter x]
+ (assert-not-appending)
(PrintWriter. x))
(defmethod writer Writer [x]
+ (assert-not-appending)
;; Writer includes sub-classes such as FileWriter
(PrintWriter. (BufferedWriter. x)))
(defmethod writer OutputStream [x]
+ (assert-not-appending)
(PrintWriter.
(BufferedWriter.
(OutputStreamWriter. x *default-encoding*))))
(defmethod writer File [#^File x]
- (writer (FileOutputStream. x)))
+ (let [stream (FileOutputStream. x *append-to-writer*)]
+ (binding [*append-to-writer* false]
+ (writer stream))))
(defmethod writer URL [#^URL x]
(if (= "file" (.getProtocol x))
@@ -172,6 +190,14 @@
(throw (Exception. (str "Cannot open <" (pr-str x) "> as a writer."))))
+(defn append-writer
+ "Like writer but opens file for appending. Does not work on streams
+ that are already open."
+ [x]
+ (binding [*append-to-writer* true]
+ (writer x)))
+
+
(defn write-lines
"Writes lines (a seq) to f, separated by newlines. f is opened with
writer, and automatically closed at the end of the sequence."
@@ -212,6 +238,12 @@
(with-open [#^PrintWriter w (writer f)]
(.print w content)))
+(defn append-spit
+ "Like spit but appends to file."
+ [f content]
+ (with-open [#^PrintWriter w (append-writer f)]
+ (.print w content)))
+
(defn pwd
"Returns current working directory as a String. (Like UNIX 'pwd'.)
Note: In Java, you cannot change the current working directory."
@@ -221,12 +253,20 @@
(defmacro with-out-writer
- "Opens a writer on f, binds it to *out*, and evalutes body."
+ "Opens a writer on f, binds it to *out*, and evalutes body.
+ Anything printed within body will be written to f."
[f & body]
`(with-open [stream# (writer ~f)]
(binding [*out* stream#]
~@body)))
+(defmacro with-out-append-writer
+ "Like with-out-writer but appends to file."
+ [f & body]
+ `(with-open [stream# (append-writer ~f)]
+ (binding [*out* stream#]
+ ~@body)))
+
(defmacro with-in-reader
"Opens a PushbackReader on f, binds it to *in*, and evaluates body."
[f & body]