aboutsummaryrefslogtreecommitdiff
path: root/src/clojure
diff options
context:
space:
mode:
Diffstat (limited to 'src/clojure')
-rw-r--r--src/clojure/contrib/base64.clj99
-rw-r--r--src/clojure/contrib/datalog.clj3
-rw-r--r--src/clojure/contrib/http/agent.clj59
-rw-r--r--src/clojure/contrib/java_utils.clj28
-rw-r--r--src/clojure/contrib/macro_utils.clj5
-rw-r--r--src/clojure/contrib/monads.clj4
-rw-r--r--src/clojure/contrib/str_utils2.clj105
-rw-r--r--src/clojure/contrib/test_contrib.clj2
-rw-r--r--src/clojure/contrib/test_contrib/java_utils.clj10
-rw-r--r--src/clojure/contrib/test_contrib/str_utils2.clj83
10 files changed, 340 insertions, 58 deletions
diff --git a/src/clojure/contrib/base64.clj b/src/clojure/contrib/base64.clj
new file mode 100644
index 00000000..5e1e3310
--- /dev/null
+++ b/src/clojure/contrib/base64.clj
@@ -0,0 +1,99 @@
+;;; 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 #^{: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)))
+
+(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)
+ ;; 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 b0 2))
+ s1 (bit-and 0x3F
+ (bit-or (bit-shift-left b0 4)
+ (bit-shift-right b1 4)))
+ s2 (bit-and 0x3F
+ (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 b0 2))
+ s1 (bit-and 0x3F
+ (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 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)))))
+ (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")))
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
diff --git a/src/clojure/contrib/http/agent.clj b/src/clojure/contrib/http/agent.clj
index d63cfd1e..806cb1af 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,16 +89,16 @@
(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)))
(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 [conn (::connection state)]
+ (let [#^HttpURLConnection conn (::connection state)]
(assoc state
::response-stream (if (connection-success? conn)
(.getInputStream conn)
@@ -117,8 +119,9 @@
"Agent action that closes the response body stream and disconnects
the HttpURLConnection."
[state options]
- (.close (::response-stream state))
- (.disconnect (::connection state))
+ (when (::response-stream state)
+ (.close #^InputStream (::response-stream state)))
+ (.disconnect #^HttpURLConnection (::connection state))
(assoc state
::response-stream nil
::state ::disconnected))
@@ -127,10 +130,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
@@ -143,20 +147,20 @@
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))
;;; 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
@@ -240,7 +244,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 +261,10 @@
headers, or clojure.contrib.duck-streams/*default-encoding* if it is
not specified."
([http-agnt]
- (string http-agnt (or (.getContentEncoding (::connection @http-agnt))
- duck/*default-encoding*)))
- ([http-agnt encoding]
+ (string http-agnt (or (.getContentEncoding
+ #^HttpURLConnection (::connection @http-agnt))
+ duck/*default-encoding*)))
+ ([http-agnt #^String encoding]
(.toString (get-byte-buffer http-agnt) encoding)))
@@ -302,14 +308,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,15 +324,16 @@
[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]
diff --git a/src/clojure/contrib/java_utils.clj b/src/clojure/contrib/java_utils.clj
index 6944f9ee..579d1128 100644
--- a/src/clojure/contrib/java_utils.clj
+++ b/src/clojure/contrib/java_utils.clj
@@ -90,11 +90,29 @@
(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)))
+ "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/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
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]
diff --git a/src/clojure/contrib/str_utils2.clj b/src/clojure/contrib/str_utils2.clj
index 5a32df6f..9a1ea9f7 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
@@ -29,8 +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))
- (:require [clojure.contrib.java-utils :as j])
+ (:refer-clojure :exclude (take replace drop butlast partition
+ contains? get repeat reverse partial))
(:import (java.util.regex Pattern)))
@@ -88,12 +88,13 @@
(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]
- (if-let [r (cmap s)]
+ (if-let [r (cmap c)]
(.append buffer r)
(.append buffer c)))
(.toString buffer)))
@@ -104,7 +105,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 +116,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)
""
@@ -132,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.
@@ -224,9 +244,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
@@ -235,10 +259,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
+ "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
+ #^"[I" 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 swap-case [#^String s]
- (throw (IllegalStateException. "swap-case not implemented yet.")))
+(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 #^String (subs s 0 1))
+ (.toLowerCase #^String (subs s 1)))))
(defn ltrim
"Removes whitespace from the left side of string."
@@ -255,6 +303,33 @@
[#^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))
+
+(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.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}))))
diff --git a/src/clojure/contrib/test_contrib/str_utils2.clj b/src/clojure/contrib/test_contrib/str_utils2.clj
index dac0893a..ee6aa68e 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 (= "&lt;foo&amp;bar&gt;"
+ (s/escape "<foo&bar>" {\& "&amp;" \< "&lt;" \> "&gt;"})))
+ (is (= " \\\"foo\\\" "
+ (s/escape " \"foo\" " {\" "\\\""})))
+ (is (= "faabor" (s/escape "foobar" {\a \o, \o \a}))))
+
(deftest t-blank
(is (s/blank? nil))
(is (s/blank? ""))
@@ -29,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")))
@@ -38,7 +56,64 @@
(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-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))))
+
+(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"))))