From cb32dc51ee01ee76f88e8cd61498e9bfd70e8c2f Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Tue, 18 Aug 2009 12:55:35 -0400 Subject: http/agent.clj: added type hints to avoid reflection --- src/clojure/contrib/http/agent.clj | 40 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/http/agent.clj b/src/clojure/contrib/http/agent.clj index d63cfd1e..2121b9db 100644 --- a/src/clojure/contrib/http/agent.clj +++ b/src/clojure/contrib/http/agent.clj @@ -63,7 +63,9 @@ clojure.contrib.http.agent (:require [clojure.contrib.http.connection :as c] [clojure.contrib.duck-streams :as duck]) - (:import (java.io ByteArrayOutputStream ByteArrayInputStream))) + (:import (java.io InputStream ByteArrayOutputStream + ByteArrayInputStream) + (java.net HttpURLConnection))) ;;; PRIVATE @@ -73,7 +75,7 @@ (defn- setup-http-connection "Sets the instance method, redirect behavior, and request headers of the HttpURLConnection." - [conn options] + [#^HttpURLConnection conn options] (.setRequestMethod conn (:method options)) (.setInstanceFollowRedirects conn (:follow-redirects options)) (doseq [[name value] (:headers options)] @@ -87,7 +89,7 @@ (c/start-http-connection conn (:body options)) (assoc state ::state ::started))) -(defn- connection-success? [conn] +(defn- connection-success? [#^HttpURLConnection conn] "Returns true if the HttpURLConnection response code is in the 2xx range." (= 2 (unchecked-divide (.getResponseCode conn) 100))) @@ -96,7 +98,7 @@ "Agent action that opens the response body stream on the HTTP request; this will block until the response stream is available." [state options] - (let [conn (::connection state)] + (let [#^HttpURLConnection conn (::connection state)] (assoc state ::response-stream (if (connection-success? conn) (.getInputStream conn) @@ -117,8 +119,8 @@ "Agent action that closes the response body stream and disconnects the HttpURLConnection." [state options] - (.close (::response-stream state)) - (.disconnect (::connection state)) + (.close #^InputStream (::response-stream state)) + (.disconnect #^HttpURLConnection (::connection state)) (assoc state ::response-stream nil ::state ::disconnected)) @@ -127,10 +129,11 @@ "Returns true if the response status of the HTTP agent begins with digit, an Integer." [digit http-agnt] - (= digit (unchecked-divide (.getResponseCode (::connection @http-agnt)) + (= digit (unchecked-divide (.getResponseCode + #^HttpURLConnection (::connection @http-agnt)) 100))) -(defn- get-byte-buffer [http-agnt] +(defn- #^ByteArrayOutputStream get-byte-buffer [http-agnt] (let [buffer (result http-agnt)] (if (instance? ByteArrayOutputStream buffer) buffer @@ -240,7 +243,8 @@ (let [a @http-agnt] (if (= (::state a) ::receiving) (::response-stream a) - (ByteArrayInputStream. (.toByteArray (result http-agnt)))))) + (ByteArrayInputStream. + (.toByteArray (get-byte-buffer http-agnt)))))) (defn bytes "Returns a Java byte array of the content returned by the server; @@ -256,9 +260,10 @@ headers, or clojure.contrib.duck-streams/*default-encoding* if it is not specified." ([http-agnt] - (string http-agnt (or (.getContentEncoding (::connection @http-agnt)) + (string http-agnt (or (.getContentEncoding + #^HttpURLConnection (::connection @http-agnt)) duck/*default-encoding*))) - ([http-agnt encoding] + ([http-agnt #^String encoding] (.toString (get-byte-buffer http-agnt) encoding))) @@ -302,14 +307,14 @@ received." [http-agnt] (when (done? http-agnt) - (.getResponseCode (::connection @http-agnt)))) + (.getResponseCode #^HttpURLConnection (::connection @http-agnt)))) (defn message "Returns the HTTP response message (e.g. 'Not Found'), for this request, or nil if the response has not yet been received." [http-agnt] (when (done? http-agnt) - (.getResponseMessage (::connection http-agnt)))) + (.getResponseMessage #^HttpURLConnection (::connection http-agnt)))) (defn headers "Returns a map of HTTP response headers. Header names are converted @@ -318,20 +323,21 @@ [http-agnt] (reduce (fn [m [#^String k v]] (assoc m (when k (keyword (.toLowerCase k))) (last v))) - {} (.getHeaderFields (::connection @http-agnt)))) + {} (.getHeaderFields + #^HttpURLConnection (::connection @http-agnt))) (defn headers-seq "Returns the HTTP response headers in order as a sequence of [String,String] pairs. The first 'header' name may be null for the HTTP status line." [http-agnt] - (let [conn (::connection @http-agnt) - f (fn thisfn [i] + (let [#^HttpURLConnection conn (::connection @http-agnt) + f (fn thisfn [#^Integer i] ;; Get value first because first key may be nil. (when-let [value (.getHeaderField conn i)] (cons [(.getHeaderFieldKey conn i) value] (thisfn (inc i)))))] - (lazy-seq (f 0)))) + (lazy-seq (f 0))))) ;;; RESPONSE STATUS CODE ACCESSORS -- cgit v1.2.3-18-g5258 From 9f3bc3b359a977e978a6ad0c8cd0481b5765f511 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Tue, 18 Aug 2009 12:59:19 -0400 Subject: http/agent.clj: fixed misplaced parenthesis --- src/clojure/contrib/http/agent.clj | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/http/agent.clj b/src/clojure/contrib/http/agent.clj index 2121b9db..4ade2b91 100644 --- a/src/clojure/contrib/http/agent.clj +++ b/src/clojure/contrib/http/agent.clj @@ -96,7 +96,7 @@ (defn- open-response "Agent action that opens the response body stream on the HTTP - request; this will block until the response stream is available." + request; this will block until the response stream is available." ; [state options] (let [#^HttpURLConnection conn (::connection state)] (assoc state @@ -153,13 +153,13 @@ ;;; CONSTRUCTOR (def *http-agent-defaults* - {:method "GET" - :headers {} - :body nil - :connect-timeout 0 - :read-timeout 0 - :follow-redirects true - :handler buffer-bytes}) + {:method "GET" + :headers {} + :body nil + :connect-timeout 0 + :read-timeout 0 + :follow-redirects true + :handler buffer-bytes}) (defn http-agent "Creates (and immediately returns) an Agent representing an HTTP @@ -262,7 +262,7 @@ ([http-agnt] (string http-agnt (or (.getContentEncoding #^HttpURLConnection (::connection @http-agnt)) - duck/*default-encoding*))) + duck/*default-encoding*))) ([http-agnt #^String encoding] (.toString (get-byte-buffer http-agnt) encoding))) @@ -324,7 +324,7 @@ (reduce (fn [m [#^String k v]] (assoc m (when k (keyword (.toLowerCase k))) (last v))) {} (.getHeaderFields - #^HttpURLConnection (::connection @http-agnt))) + #^HttpURLConnection (::connection @http-agnt)))) (defn headers-seq "Returns the HTTP response headers in order as a sequence of @@ -337,7 +337,7 @@ (when-let [value (.getHeaderField conn i)] (cons [(.getHeaderFieldKey conn i) value] (thisfn (inc i)))))] - (lazy-seq (f 0))))) + (lazy-seq (f 0)))) ;;; RESPONSE STATUS CODE ACCESSORS -- cgit v1.2.3-18-g5258 From 8b360da5be1cac6612b3882037efa4c4c89ae643 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Tue, 18 Aug 2009 16:17:06 -0400 Subject: str_utils2.clj: implemented swap-case, added capitalize --- src/clojure/contrib/str_utils2.clj | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index 5a32df6f..25e03ad3 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -235,10 +235,34 @@ (replace s #"[\r\n]+$" "")) (defn title-case [#^String s] - (throw (IllegalStateException. "title-case not implemented yet."))) + (throw (Exception. "title-case not implemeted yet"))) -(defn swap-case [#^String s] - (throw (IllegalStateException. "swap-case not implemented yet."))) +(defn swap-case + "Changes upper case characters to lower case and vice-versa. + Handles Unicode supplementary characters correctly. Uses the + locale-sensitive String.toUpperCase() and String.toLowerCase() + methods." + [#^String s] + (let [buffer (StringBuilder. (.length s)) + ;; array to make a String from one code point + array (make-array Integer/TYPE 1)] + (docodepoints [c s] + (aset-int array 0 c) + (if (Character/isLowerCase c) + ;; Character.toUpperCase is not locale-sensitive, but + ;; String.toUpperCase is; so we use a String. + (.append buffer (.toUpperCase (String. array 0 1))) + (.append buffer (.toLowerCase (String. array 0 1))))) + (.toString buffer))) + +(defn capitalize + "Converts first character of the string to upper-case, all other + characters to lower-case." + [#^String s] + (if (< (count s) 2) + (.toUpperCase s) + (str (.toUpperCase (subs s 0 1)) + (.toLowerCase (subs s 1))))) (defn ltrim "Removes whitespace from the left side of string." -- cgit v1.2.3-18-g5258 From 3b6d95140393bf78930c9f4045ba2feab36f3946 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Tue, 18 Aug 2009 16:27:29 -0400 Subject: str_utils2.clj: explain argument order of take/drop/butlast, refs #17 --- src/clojure/contrib/str_utils2.clj | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index 25e03ad3..ec2741ce 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -104,7 +104,10 @@ (every? (fn [#^Character c] (Character/isWhitespace c)) s)) (defn take - "Take first n characters from s, up to the length of s." + "Take first n characters from s, up to the length of s. + + Note the argument order is the opposite of clojure.core/take; this + is to keep the string as the first argument for use with ->" [#^String s n] (if (< (count s) n) s @@ -112,14 +115,20 @@ (defn drop [#^String s n] "Drops first n characters from s. Returns an empty string if n is - greater than the length of s." + greater than the length of s. + + Note the argument order is the opposite of clojure.core/drop; this + is to keep the string as the first argument for use with ->" (if (< (count s) n) "" (.substring s n))) (defn butlast "Returns s without the last n characters. Returns an empty string - if n is greater than the length of s." + if n is greater than the length of s. + + Note the argument order is the opposite of clojure.core/butlast; + this is to keep the string as the first argument for use with ->" [#^String s n] (if (< (count s) n) "" -- cgit v1.2.3-18-g5258 From c20fbee2d68fdcde18c7001f859d32513cf0bde6 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Tue, 18 Aug 2009 16:59:49 -0400 Subject: str_utils2.clj: fix escape so it actually works, add tests --- src/clojure/contrib/str_utils2.clj | 2 +- src/clojure/contrib/test_contrib/str_utils2.clj | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index ec2741ce..26dd849f 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -93,7 +93,7 @@ [#^String s cmap] (let [buffer (StringBuilder. (.length s))] (dochars [c s] - (if-let [r (cmap s)] + (if-let [r (cmap c)] (.append buffer r) (.append buffer c))) (.toString buffer))) diff --git a/src/clojure/contrib/test_contrib/str_utils2.clj b/src/clojure/contrib/test_contrib/str_utils2.clj index dac0893a..4b466774 100644 --- a/src/clojure/contrib/test_contrib/str_utils2.clj +++ b/src/clojure/contrib/test_contrib/str_utils2.clj @@ -41,4 +41,11 @@ (deftest t-codepoints (is (= (list 102 111 111 65536 98 97 114) (s/codepoints "foo\uD800\uDC00bar")) - "Handles Unicode supplementary characters"))) + "Handles Unicode supplementary characters")) + +(deftest t-escape + (is (= "<foo&bar>" + (s/escape "" {\& "&" \< "<" \> ">"}))) + (is (= " \\\"foo\\\" " + (s/escape " \"foo\" " {\" "\\\""}))) + (is (= "faabor" (s/escape "foobar" {\a \o, \o \a})))) -- cgit v1.2.3-18-g5258 From 132f0e501ba181f6491ef0150d0db5cbccae5c3b Mon Sep 17 00:00:00 2001 From: Konrad Hinsen Date: Wed, 19 Aug 2009 12:01:30 +0200 Subject: macro-utils: removed unused dependency on walk --- src/clojure/contrib/macro_utils.clj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/macro_utils.clj b/src/clojure/contrib/macro_utils.clj index 08c743e1..98685b77 100644 --- a/src/clojure/contrib/macro_utils.clj +++ b/src/clojure/contrib/macro_utils.clj @@ -1,7 +1,7 @@ ;; Macrolet and symbol-macrolet ;; by Konrad Hinsen -;; last updated May 25, 2009 +;; last updated August 19, 2009 ;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use ;; and distribution terms for this software are covered by the Eclipse @@ -26,8 +26,7 @@ of another macro, they may be used anywhere. Global symbol macros can be used only inside a with-symbol-macros form."} clojure.contrib.macro-utils - (:use [clojure.contrib.def :only (defvar-)]) - (:use [clojure.walk :only (prewalk)])) + (:use [clojure.contrib.def :only (defvar-)])) ; A set of all special forms. Special forms are not macro-expanded, making ; it impossible to shadow them by macro definitions. For most special -- cgit v1.2.3-18-g5258 From 34fc5f2bc4dbae6b1b05b77cda98f56cc62e73b7 Mon Sep 17 00:00:00 2001 From: Konrad Hinsen Date: Wed, 19 Aug 2009 12:02:31 +0200 Subject: monads: correction in comment --- src/clojure/contrib/monads.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/monads.clj b/src/clojure/contrib/monads.clj index 68e03c13..8d287105 100644 --- a/src/clojure/contrib/monads.clj +++ b/src/clojure/contrib/monads.clj @@ -1,7 +1,7 @@ ;; Monads in Clojure ;; by Konrad Hinsen -;; last updated June 23, 2009 +;; last updated June 30, 2009 ;; Copyright (c) Konrad Hinsen, 2009. All rights reserved. The use ;; and distribution terms for this software are covered by the Eclipse @@ -335,7 +335,7 @@ ; State monad (defmonad state-m "Monad describing stateful computations. The monadic values have the - structure (fn [old-state] (list result new-state))." + structure (fn [old-state] [result new-state])." [m-result (fn m-result-state [v] (fn [s] [v s])) m-bind (fn m-bind-state [mv f] -- cgit v1.2.3-18-g5258 From 9374fa2ba6e05d7f523bef7698609d641cc916ac Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 11:50:45 -0400 Subject: str_utils2.clj: added type hints to avoid reflection --- src/clojure/contrib/str_utils2.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index 26dd849f..e5a541cf 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -254,7 +254,7 @@ [#^String s] (let [buffer (StringBuilder. (.length s)) ;; array to make a String from one code point - array (make-array Integer/TYPE 1)] + #^"[I" array (make-array Integer/TYPE 1)] (docodepoints [c s] (aset-int array 0 c) (if (Character/isLowerCase c) @@ -270,8 +270,8 @@ [#^String s] (if (< (count s) 2) (.toUpperCase s) - (str (.toUpperCase (subs s 0 1)) - (.toLowerCase (subs s 1))))) + (str (.toUpperCase #^String (subs s 0 1)) + (.toLowerCase #^String (subs s 1))))) (defn ltrim "Removes whitespace from the left side of string." -- cgit v1.2.3-18-g5258 From 31ffb915af12133275f5ed6a67e312fc92635e7d Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 12:09:14 -0400 Subject: test_contrib/str_utils2.clj: added lots more tests This should provide complete coverage of str-utils2 --- src/clojure/contrib/test_contrib/str_utils2.clj | 77 +++++++++++++++++++++---- 1 file changed, 67 insertions(+), 10 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/test_contrib/str_utils2.clj b/src/clojure/contrib/test_contrib/str_utils2.clj index 4b466774..ecc68e19 100644 --- a/src/clojure/contrib/test_contrib/str_utils2.clj +++ b/src/clojure/contrib/test_contrib/str_utils2.clj @@ -2,6 +2,18 @@ (:require [clojure.contrib.str-utils2 :as s]) (:use clojure.test)) +(deftest t-codepoints + (is (= (list 102 111 111 65536 98 97 114) + (s/codepoints "foo\uD800\uDC00bar")) + "Handles Unicode supplementary characters")) + +(deftest t-escape + (is (= "<foo&bar>" + (s/escape "" {\& "&" \< "<" \> ">"}))) + (is (= " \\\"foo\\\" " + (s/escape " \"foo\" " {\" "\\\""}))) + (is (= "faabor" (s/escape "foobar" {\a \o, \o \a})))) + (deftest t-blank (is (s/blank? nil)) (is (s/blank? "")) @@ -38,14 +50,59 @@ (is (= "barbarfoo" (s/replace-first "foobarfoo" #"foo" "bar"))) (is (= "FOObarfoo" (s/replace-first "foobarfoo" #"foo" s/upper-case)))) -(deftest t-codepoints - (is (= (list 102 111 111 65536 98 97 114) - (s/codepoints "foo\uD800\uDC00bar")) - "Handles Unicode supplementary characters")) +(deftest t-partition + (is (= (list "" "abc" "123" "def") + (s/partition "abc123def" #"[a-z]+")))) -(deftest t-escape - (is (= "<foo&bar>" - (s/escape "" {\& "&" \< "<" \> ">"}))) - (is (= " \\\"foo\\\" " - (s/escape " \"foo\" " {\" "\\\""}))) - (is (= "faabor" (s/escape "foobar" {\a \o, \o \a})))) +(deftest t-join + (is (= "1,2,3" (s/join \, [1 2 3]))) + (is (= "" (s/join \, []))) + (is (= "1 and-a 2 and-a 3" (s/join " and-a " [1 2 3])))) + +(deftest t-chop + (is (= "fo" (s/chop "foo"))) + (is (= "") (s/chop "f")) + (is (= "") (s/chop ""))) + +(deftest t-chomp + (is (= "foo" (s/chomp "foo\n"))) + (is (= "foo" (s/chomp "foo\r\n"))) + (is (= "foo" (s/chomp "foo"))) + (is (= "" (s/chomp "")))) + +(deftest t-swap-case + (is (= "fOO!bAR" (s/swap-case "Foo!Bar"))) + (is (= "" (s/swap-case "")))) + +(deftest t-capitalize + (is (= "Foobar" (s/capitalize "foobar"))) + (is (= "Foobar" (s/capitalize "FOOBAR")))) + +(deftest t-ltrim + (is (= "foo " (s/ltrim " foo "))) + (is (= "" (s/ltrim " ")))) + +(deftest t-rtrim + (is (= " foo" (s/rtrim " foo "))) + (is (= "" (s/rtrim " ")))) + +(deftest t-split-lines + (is (= (list "one" "two" "three") + (s/split-lines "one\ntwo\r\nthree"))) + (is (= (list "foo") (s/split-lines "foo")))) + +(deftest t-upper-case + (is (= "FOOBAR" (s/upper-case "Foobar")))) + +(deftest t-lower-case + (is (= "foobar" (s/lower-case "FooBar")))) + +(deftest t-trim + (is (= "foo" (s/trim " foo \r\n")))) + +(deftest t-contains + (is (s/contains? "foobar" "foo")) + (is (not (s/contains? "foobar" "baz")))) + +(deftest t-get + (is (= \o (s/get "foo" 1)))) -- cgit v1.2.3-18-g5258 From b77d22fb567127edf5d3f5caebfbfbd9d7ce4ab2 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 12:09:53 -0400 Subject: str_utils2.clj: avoid error on zero-length string in chop --- src/clojure/contrib/str_utils2.clj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index e5a541cf..b70a9ba4 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -233,9 +233,13 @@ (apply str (interpose separator coll))) (defn chop - "Removes the last character of string." + "Removes the last character of string, does nothing on a zero-length + string." [#^String s] - (subs s 0 (dec (count s)))) + (let [size (count s)] + (if (zero? size) + s + (subs s 0 (dec (count s)))))) (defn chomp "Removes all trailing newline \\n or return \\r characters from -- cgit v1.2.3-18-g5258 From 35fa51c46e772eec302521eef1382798eb4290b1 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 12:35:36 -0400 Subject: str_utils2.clj: added map-str and grep from Compojure --- src/clojure/contrib/str_utils2.clj | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index b70a9ba4..33ed857c 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -292,6 +292,20 @@ [#^String s] (seq (.split #"\r?\n" s))) +;; borrowed from compojure.str-utils, by James Reeves, EPL 1.0 +(defn map-str + "Apply f to each element of coll, concatenate all results into a + String." + [f coll] + (apply str (map f coll))) + +;; borrowed from compojure.str-utils, by James Reeves, EPL 1.0 +(defn grep + "Filters elements of coll by a regular expression. The String + representation (with str) of each element is tested with re-find." + [re coll] + (filter (fn [x] (re-find re (str x))) coll)) + ;;; WRAPPERS -- cgit v1.2.3-18-g5258 From bb633a1ccd99c0dc7bede9fb4268649e254b5702 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 12:35:54 -0400 Subject: str_utils2.clj: modified doc string for escape --- src/clojure/contrib/str_utils2.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index 33ed857c..8efbfd0a 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -88,8 +88,9 @@ (lazy-seq (f s 0)))) (defn escape - "Escapes characters in string according to a cmap, a function or map - from characters to their replacements." + "Returns a new String by applying cmap (a function or a map) to each + character in s. If cmap returns nil, the original character is + added to the output unchanged." [#^String s cmap] (let [buffer (StringBuilder. (.length s))] (dochars [c s] -- cgit v1.2.3-18-g5258 From fda5d6a8ad310624f9efb487a2c9ed8616557ef3 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 12:36:12 -0400 Subject: str_utils2.clj: modified header comments --- src/clojure/contrib/str_utils2.clj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index 8efbfd0a..8529d2c4 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -1,7 +1,7 @@ -;;; str_utils2.clj -- experimental new string utilities for Clojure +;;; str_utils2.clj -- functional string utilities for Clojure ;; by Stuart Sierra, http://stuartsierra.com/ -;; June 4, 2009 +;; August 19, 2009 ;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use ;; and distribution terms for this software are covered by the Eclipse @@ -30,7 +30,6 @@ http://github.com/francoisdevlin/devlinsf-clojure-utils/"} clojure.contrib.str-utils2 (:refer-clojure :exclude (take replace drop butlast partition contains? get)) - (:require [clojure.contrib.java-utils :as j]) (:import (java.util.regex Pattern))) -- cgit v1.2.3-18-g5258 From aae84a8b7e47622a4ca324a2828757996b592ea4 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 14:04:02 -0400 Subject: str_utils2.clj: added repeat and reverse, with tests --- src/clojure/contrib/str_utils2.clj | 13 ++++++++++++- src/clojure/contrib/test_contrib/str_utils2.clj | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index 8529d2c4..1fbd030d 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -29,7 +29,8 @@ Some ideas are borrowed from http://github.com/francoisdevlin/devlinsf-clojure-utils/"} clojure.contrib.str-utils2 - (:refer-clojure :exclude (take replace drop butlast partition contains? get)) + (:refer-clojure :exclude (take replace drop butlast partition + contains? get repeat reverse)) (:import (java.util.regex Pattern))) @@ -141,6 +142,16 @@ s (.substring s (- (count s) n)))) +(defn repeat + "Returns a new String containing s repeated n times." + [#^String s n] + (apply str (clojure.core/repeat n s))) + +(defn reverse + "Returns s with its characters reversed." + [#^String s] + (.toString (.reverse (StringBuilder. s)))) + (defmulti #^{:doc "Replaces all instances of pattern in string with replacement. diff --git a/src/clojure/contrib/test_contrib/str_utils2.clj b/src/clojure/contrib/test_contrib/str_utils2.clj index ecc68e19..6d1f94d2 100644 --- a/src/clojure/contrib/test_contrib/str_utils2.clj +++ b/src/clojure/contrib/test_contrib/str_utils2.clj @@ -41,6 +41,12 @@ (is (= "foobar" (s/tail "foobar" 9))) (is (= "" (s/tail "foobar" 0)))) +(deftest t-repeat + (is (= "foofoofoo" (s/repeat "foo" 3)))) + +(deftest t-reverse + (is (= "tab" (s/reverse "bat")))) + (deftest t-replace (is (= "faabar" (s/replace "foobar" \o \a))) (is (= "barbarbar" (s/replace "foobarfoo" "foo" "bar"))) -- cgit v1.2.3-18-g5258 From b086e55310f9002dd09b61a5389a943a724897a5 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 18:57:54 -0400 Subject: base64.clj: Base-64 encoding Next step: implement decoding! --- src/clojure/contrib/base64.clj | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/clojure/contrib/base64.clj (limited to 'src/clojure') diff --git a/src/clojure/contrib/base64.clj b/src/clojure/contrib/base64.clj new file mode 100644 index 00000000..ccd2bf45 --- /dev/null +++ b/src/clojure/contrib/base64.clj @@ -0,0 +1,89 @@ +;;; base64.clj: Experimental Base-64 encoding and (later) decoding + +;; by Stuart Sierra, http://stuartsierra.com/ +;; August 19, 2009 + +;; Copyright (c) Stuart Sierra, 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. + + +(ns clojure.contrib.base64 + (:import (java.io InputStream Writer ByteArrayInputStream + StringWriter))) + +(def *base64-alphabet* + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") + +(defn encode + "Encodes bytes of input, writing Base 64 text on output. alphabet + is a 65-character String containing the 64 characters to use in the + encoding; the 65th character is the pad character. line-length is + the maximum number of characters per line, nil for no line breaks." + [#^InputStream input #^Writer output #^String alphabet line-length] + (let [buffer (make-array Byte/TYPE 3)] + (loop [line 0] + (let [len (.read input buffer)] + (when (pos? len) + (cond (= len 3) + (let [s0 (bit-and 0x3F (bit-shift-right (aget buffer 0) 2)) + s1 (bit-and 0x3F + (bit-or (bit-shift-left (aget buffer 0) 4) + (bit-shift-right (aget buffer 1) 4))) + s2 (bit-and 0x3F + (bit-or (bit-shift-left (aget buffer 1) 2) + (bit-shift-right (aget buffer 2) 6))) + s3 (bit-and 0x3F (aget buffer 2))] + (.append output (.charAt alphabet s0)) + (.append output (.charAt alphabet s1)) + (.append output (.charAt alphabet s2)) + (.append output (.charAt alphabet s3))) + + (= len 2) + (let [s0 (bit-and 0x3F (bit-shift-right (aget buffer 0) 2)) + s1 (bit-and 0x3F + (bit-or (bit-shift-left (aget buffer 0) 4) + (bit-shift-right (aget buffer 1) 4))) + s2 (bit-and 0x3F (bit-shift-left (aget buffer 1) 2))] + (.append output (.charAt alphabet s0)) + (.append output (.charAt alphabet s1)) + (.append output (.charAt alphabet s2)) + (.append output (.charAt alphabet 64))) + + (= len 1) + (let [s0 (bit-and 0x3F (bit-shift-right (aget buffer 0) 2)) + s1 (bit-and 0x3F (bit-shift-left (aget buffer 0) 4))] + (.append output (.charAt alphabet s0)) + (.append output (.charAt alphabet s1)) + (.append output (.charAt alphabet 64)) + (.append output (.charAt alphabet 64)))) + (if (and line-length (> (+ line 4) line-length)) + (do (.append output \newline) + (recur 0)) + (recur (+ line 4)))))))) + +(defn encode-str + "Encodes String in base 64; returns a String. If not specified, + encoding is UTF-8 and line-length is nil." + ([s] (encode-str s "UTF-8" nil)) + ([#^String s #^String encoding line-length] + (let [output (StringWriter.)] + (encode (ByteArrayInputStream. (.getBytes s encoding)) + output *base64-alphabet* line-length) + (.toString output)))) + + +;;; tests + +;; (deftest t-encode-str +;; (is (= (encode-str "") "")) +;; (is (= (encode-str "f") "Zg==")) +;; (is (= (encode-str "fo") "Zm8=")) +;; (is (= (encode-str "foo") "Zm9v")) +;; (is (= (encode-str "foob") "Zm9vYg==")) +;; (is (= (encode-str "fooba") "Zm9vYmE=")) +;; (is (= (encode-str "foobar") "Zm9vYmFy"))) -- cgit v1.2.3-18-g5258 From 54a19a97e34c04dd7f9410e7683b13c240241458 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Wed, 19 Aug 2009 22:43:23 -0400 Subject: base64.clj: performance enhancement for encode Use boxed Integers instead of primitive bytes, because Clojure's bit operations only support Integer, Long, and BigInteger. --- src/clojure/contrib/base64.clj | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/base64.clj b/src/clojure/contrib/base64.clj index ccd2bf45..1243dfee 100644 --- a/src/clojure/contrib/base64.clj +++ b/src/clojure/contrib/base64.clj @@ -29,38 +29,43 @@ (loop [line 0] (let [len (.read input buffer)] (when (pos? len) + ;; Pre-boxing the bytes as Integers is more efficient for + ;; Clojure's bit operations. + (let [b0 (Integer/valueOf (int (aget buffer 0))) + b1 (Integer/valueOf (int (aget buffer 1))) + b2 (Integer/valueOf (int (aget buffer 2)))] (cond (= len 3) - (let [s0 (bit-and 0x3F (bit-shift-right (aget buffer 0) 2)) + (let [s0 (bit-and 0x3F (bit-shift-right b0 2)) s1 (bit-and 0x3F - (bit-or (bit-shift-left (aget buffer 0) 4) - (bit-shift-right (aget buffer 1) 4))) + (bit-or (bit-shift-left b0 4) + (bit-shift-right b1 4))) s2 (bit-and 0x3F - (bit-or (bit-shift-left (aget buffer 1) 2) - (bit-shift-right (aget buffer 2) 6))) - s3 (bit-and 0x3F (aget buffer 2))] + (bit-or (bit-shift-left b1 2) + (bit-shift-right b2 6))) + s3 (bit-and 0x3F b2)] (.append output (.charAt alphabet s0)) (.append output (.charAt alphabet s1)) (.append output (.charAt alphabet s2)) (.append output (.charAt alphabet s3))) (= len 2) - (let [s0 (bit-and 0x3F (bit-shift-right (aget buffer 0) 2)) + (let [s0 (bit-and 0x3F (bit-shift-right b0 2)) s1 (bit-and 0x3F - (bit-or (bit-shift-left (aget buffer 0) 4) - (bit-shift-right (aget buffer 1) 4))) - s2 (bit-and 0x3F (bit-shift-left (aget buffer 1) 2))] + (bit-or (bit-shift-left b0 4) + (bit-shift-right b1 4))) + s2 (bit-and 0x3F (bit-shift-left b1 2))] (.append output (.charAt alphabet s0)) (.append output (.charAt alphabet s1)) (.append output (.charAt alphabet s2)) (.append output (.charAt alphabet 64))) (= len 1) - (let [s0 (bit-and 0x3F (bit-shift-right (aget buffer 0) 2)) - s1 (bit-and 0x3F (bit-shift-left (aget buffer 0) 4))] + (let [s0 (bit-and 0x3F (bit-shift-right b0 2)) + s1 (bit-and 0x3F (bit-shift-left b0 4))] (.append output (.charAt alphabet s0)) (.append output (.charAt alphabet s1)) (.append output (.charAt alphabet 64)) - (.append output (.charAt alphabet 64)))) + (.append output (.charAt alphabet 64))))) (if (and line-length (> (+ line 4) line-length)) (do (.append output \newline) (recur 0)) -- cgit v1.2.3-18-g5258 From ef69dc58760232c75b55e91d405116aa5ed03d51 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Thu, 20 Aug 2009 11:20:26 -0400 Subject: str_utils2.clj: added partial, with tests Alternate definition of partial for fns that take their primary argument first. --- src/clojure/contrib/str_utils2.clj | 15 ++++++++++++++- src/clojure/contrib/test_contrib/str_utils2.clj | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj index 1fbd030d..9a1ea9f7 100644 --- a/src/clojure/contrib/str_utils2.clj +++ b/src/clojure/contrib/str_utils2.clj @@ -30,7 +30,7 @@ http://github.com/francoisdevlin/devlinsf-clojure-utils/"} clojure.contrib.str-utils2 (:refer-clojure :exclude (take replace drop butlast partition - contains? get repeat reverse)) + contains? get repeat reverse partial)) (:import (java.util.regex Pattern))) @@ -317,6 +317,19 @@ [re coll] (filter (fn [x] (re-find re (str x))) coll)) +(defn partial + "Like clojure.core/partial for functions that take their primary + argument first. + + Takes a function f and its arguments, NOT INCLUDING the first + argument. Returns a new function whose first argument will be the + first argument to f. + + Example: (str-utils2/partial str-utils2/take 2) + ;;=> (fn [s] (str-utils2/take s 2))" + [f & args] + (fn [s & more] (apply f s (concat args more)))) + ;;; WRAPPERS diff --git a/src/clojure/contrib/test_contrib/str_utils2.clj b/src/clojure/contrib/test_contrib/str_utils2.clj index 6d1f94d2..ee6aa68e 100644 --- a/src/clojure/contrib/test_contrib/str_utils2.clj +++ b/src/clojure/contrib/test_contrib/str_utils2.clj @@ -112,3 +112,8 @@ (deftest t-get (is (= \o (s/get "foo" 1)))) + +(deftest t-partial + (is (= "bar" ((s/partial s/drop 3) "foobar"))) + (is (= "ooba" ((comp (s/partial s/take 4) + (s/partial s/drop 1)) "foobar")))) -- cgit v1.2.3-18-g5258 From 7b661cfc55e2293d14bed4fd801c017b3f68d291 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Thu, 20 Aug 2009 11:32:10 -0400 Subject: base64.clj: added namespace metadata doc --- src/clojure/contrib/base64.clj | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/base64.clj b/src/clojure/contrib/base64.clj index 1243dfee..5e1e3310 100644 --- a/src/clojure/contrib/base64.clj +++ b/src/clojure/contrib/base64.clj @@ -12,7 +12,12 @@ ;; remove this notice, or any other, from this software. -(ns clojure.contrib.base64 +(ns #^{:doc "Base-64 encoding and (maybe later) decoding. + + This is mainly here as an example. It is much slower than the + Apache Commons Codec implementation or sun.misc.BASE64Encoder." + :author "Stuart Sierra"} + clojure.contrib.base64 (:import (java.io InputStream Writer ByteArrayInputStream StringWriter))) -- cgit v1.2.3-18-g5258 From 0ab6bd4dfa56e4977944355e02a68c80d7c38fb8 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Thu, 20 Aug 2009 16:11:42 -0400 Subject: http/agent.clj: handle null InputStream from HTTP response --- src/clojure/contrib/http/agent.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/http/agent.clj b/src/clojure/contrib/http/agent.clj index 4ade2b91..c5a6b51c 100644 --- a/src/clojure/contrib/http/agent.clj +++ b/src/clojure/contrib/http/agent.clj @@ -146,7 +146,7 @@ retrieved with the 'stream', 'string', and 'bytes' functions." [http-agnt] (let [output (ByteArrayOutputStream.)] - (duck/copy (stream http-agnt) output) + (duck/copy (or (stream http-agnt) "") output) output)) -- cgit v1.2.3-18-g5258 From a9f24ee1192447344d9ac02a37e0c521412fbe1e Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Thu, 20 Aug 2009 16:14:15 -0400 Subject: http/agent.clj: handle null response stream on disconnect --- src/clojure/contrib/http/agent.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/http/agent.clj b/src/clojure/contrib/http/agent.clj index c5a6b51c..47424e2f 100644 --- a/src/clojure/contrib/http/agent.clj +++ b/src/clojure/contrib/http/agent.clj @@ -119,7 +119,8 @@ "Agent action that closes the response body stream and disconnects the HttpURLConnection." [state options] - (.close #^InputStream (::response-stream state)) + (when (::response-stream state) + (.close #^InputStream (::response-stream state))) (.disconnect #^HttpURLConnection (::connection state)) (assoc state ::response-stream nil -- cgit v1.2.3-18-g5258 From 1e0d828a9b7ff1a4cbc19365c7df5663419631e9 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Thu, 20 Aug 2009 17:26:31 -0400 Subject: http/agent.clj: fix missing @ in 'message' --- src/clojure/contrib/http/agent.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/http/agent.clj b/src/clojure/contrib/http/agent.clj index 47424e2f..806cb1af 100644 --- a/src/clojure/contrib/http/agent.clj +++ b/src/clojure/contrib/http/agent.clj @@ -315,7 +315,7 @@ request, or nil if the response has not yet been received." [http-agnt] (when (done? http-agnt) - (.getResponseMessage #^HttpURLConnection (::connection http-agnt)))) + (.getResponseMessage #^HttpURLConnection (::connection @http-agnt)))) (defn headers "Returns a map of HTTP response headers. Header names are converted -- cgit v1.2.3-18-g5258 From 5dbecc380cbb65afff33648325f1e3b44b535143 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Fri, 21 Aug 2009 14:31:58 -0400 Subject: java_utils.clj: made as-str variadic like str, fixes #18 This commit also includes tests for this function. --- src/clojure/contrib/java_utils.clj | 36 +++++++++++++++++++++---- src/clojure/contrib/test_contrib.clj | 2 +- src/clojure/contrib/test_contrib/java_utils.clj | 10 +++++++ 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 src/clojure/contrib/test_contrib/java_utils.clj (limited to 'src/clojure') diff --git a/src/clojure/contrib/java_utils.clj b/src/clojure/contrib/java_utils.clj index 75e8ca8b..5f34df16 100644 --- a/src/clojure/contrib/java_utils.clj +++ b/src/clojure/contrib/java_utils.clj @@ -90,11 +90,37 @@ (reduce file (file parent child) more))) (defn as-str - "Returns the name or string representation of x" - [x] - (if (instance? clojure.lang.Named x) - (name x) - (str x))) + "Returns the name or string representation of args, concatenated to + a single string. Like clojure.core/str, but uses the names of + keywords and symbols instead of their literal representation." + [& args] + (apply str (map (fn [x] (if (instance? clojure.lang.Named x) + (name x) x)) + args))) +(defn as-str + "Like clojure.core/str, but if an argument is a keyword or symbol, + its name will be used instead of its literal representation. + + Example: + (str :foo :bar) ;;=> \":foo:bar\" + (as-str :foo :bar) ;;=> \"foobar\" + + Note that this does not apply to keywords or symbols nested within + data structures; they will be rendered as with str. + + Example: + (str {:foo :bar}) ;;=> \"{:foo :bar}\" + (as-str {:foo :bar}) ;;=> \"{:foo :bar}\" " + ([] "") + ([x] (if (instance? clojure.lang.Named x) + (name x) + (str x))) + ([x & ys] + ((fn [#^StringBuilder sb more] + (if more + (recur (. sb (append (as-str (first more)))) (next more)) + (str sb))) + (new StringBuilder #^String (as-str x)) ys))) (defn get-system-property "Get a system property." diff --git a/src/clojure/contrib/test_contrib.clj b/src/clojure/contrib/test_contrib.clj index 17f3e0e9..d7b2597b 100644 --- a/src/clojure/contrib/test_contrib.clj +++ b/src/clojure/contrib/test_contrib.clj @@ -20,7 +20,7 @@ [:complex-numbers :fnmap :macro-utils :monads :pprint.pretty :pprint.cl-format :str-utils :shell-out :test-graph :test-dataflow :test-java-utils :test-lazy-seqs - :test-trace :test-jmx]) + :test-trace :test-jmx :java-utils]) (def test-namespaces (map #(symbol (str "clojure.contrib.test-contrib." (name %))) diff --git a/src/clojure/contrib/test_contrib/java_utils.clj b/src/clojure/contrib/test_contrib/java_utils.clj new file mode 100644 index 00000000..44901ad1 --- /dev/null +++ b/src/clojure/contrib/test_contrib/java_utils.clj @@ -0,0 +1,10 @@ +(ns clojure.contrib.test-contrib.java-utils + (:use clojure.test clojure.contrib.java-utils)) + +(deftest t-as-str + (is (= "foo" (as-str "foo"))) + (is (= "foo" (as-str 'foo))) + (is (= "foo" (as-str :foo))) + (is (= "[1 2 3]" (as-str [1 2 3]))) + (is (= "Hello, World!" (as-str "Hello, " :World \!))) + (is (= (str {:foo :bar}) (as-str {:foo :bar})))) -- cgit v1.2.3-18-g5258 From a0cadf5768c4cb1ce0cbeb23a264246bd82fe151 Mon Sep 17 00:00:00 2001 From: Stuart Sierra Date: Fri, 21 Aug 2009 14:34:45 -0400 Subject: java_utils.clj Correct previous commit with duplicate definition of as-str --- src/clojure/contrib/java_utils.clj | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/java_utils.clj b/src/clojure/contrib/java_utils.clj index 5f34df16..ce2b7777 100644 --- a/src/clojure/contrib/java_utils.clj +++ b/src/clojure/contrib/java_utils.clj @@ -89,14 +89,6 @@ ([parent child & more] (reduce file (file parent child) more))) -(defn as-str - "Returns the name or string representation of args, concatenated to - a single string. Like clojure.core/str, but uses the names of - keywords and symbols instead of their literal representation." - [& args] - (apply str (map (fn [x] (if (instance? clojure.lang.Named x) - (name x) x)) - args))) (defn as-str "Like clojure.core/str, but if an argument is a keyword or symbol, its name will be used instead of its literal representation. -- cgit v1.2.3-18-g5258 From ab7e1757c4de4c5d05b8c286646c152d19e29825 Mon Sep 17 00:00:00 2001 From: Tom Faulhaber Date: Fri, 21 Aug 2009 23:48:29 -0700 Subject: Translated Jeffrey's overview of Datalog from the old google code wiki into the new documentation structure. --- src/clojure/contrib/datalog.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/clojure') diff --git a/src/clojure/contrib/datalog.clj b/src/clojure/contrib/datalog.clj index ebc52cf0..93e132de 100644 --- a/src/clojure/contrib/datalog.clj +++ b/src/clojure/contrib/datalog.clj @@ -19,8 +19,7 @@ (ns #^{:author "Jeffrey Straszheim", - :doc "A Clojure implementation of Datalog" - :see-also ["DatalogOverview"]} + :doc "A Clojure implementation of Datalog"} clojure.contrib.datalog (:use clojure.contrib.datalog.rules clojure.contrib.datalog.softstrat -- cgit v1.2.3-18-g5258