diff options
-rw-r--r-- | modules/apply-macro/pom.xml | 16 | ||||
-rw-r--r-- | modules/apply-macro/src/main/clojure/clojure/contrib/apply_macro.clj | 45 | ||||
-rw-r--r-- | modules/http-agent/pom.xml | 26 | ||||
-rw-r--r-- | modules/http-agent/src/main/clojure/clojure/contrib/http/agent.clj | 386 | ||||
-rw-r--r-- | modules/http-connection/pom.xml | 21 | ||||
-rw-r--r-- | modules/http-connection/src/main/clojure/clojure/contrib/http/connection.clj | 62 | ||||
-rw-r--r-- | modules/javadoc/pom.xml | 26 | ||||
-rw-r--r-- | modules/javadoc/src/main/clojure/clojure/contrib/javadoc.clj | 4 | ||||
-rw-r--r-- | modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse.clj | 51 | ||||
-rw-r--r-- | modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse_ui.clj | 31 | ||||
-rw-r--r-- | modules/properties/pom.xml | 26 | ||||
-rw-r--r-- | modules/properties/src/main/clojure/clojure/contrib/properties.clj | 77 | ||||
-rw-r--r-- | modules/properties/src/test/clojure/clojure/contrib/test_properties.clj | 63 | ||||
-rw-r--r-- | modules/test-is/pom.xml | 16 | ||||
-rw-r--r-- | modules/test-is/src/main/clojure/clojure/contrib/test_is.clj | 119 | ||||
-rw-r--r-- | pom.xml | 6 |
16 files changed, 975 insertions, 0 deletions
diff --git a/modules/apply-macro/pom.xml b/modules/apply-macro/pom.xml new file mode 100644 index 00000000..23048791 --- /dev/null +++ b/modules/apply-macro/pom.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.clojure.contrib</groupId> + <artifactId>parent</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../parent</relativePath> + </parent> + <artifactId>apply-macro</artifactId> + <dependencies> + </dependencies> +</project>
\ No newline at end of file diff --git a/modules/apply-macro/src/main/clojure/clojure/contrib/apply_macro.clj b/modules/apply-macro/src/main/clojure/clojure/contrib/apply_macro.clj new file mode 100644 index 00000000..9df85407 --- /dev/null +++ b/modules/apply-macro/src/main/clojure/clojure/contrib/apply_macro.clj @@ -0,0 +1,45 @@ +;;; apply_macro.clj: make macros behave like functions + +;; by Stuart Sierra, http://stuartsierra.com/ +;; January 28, 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. + + +;; Don't use this. I mean it. It's evil. How evil? You can't +;; handle it, that's how evil it is. That's right. I did it so you +;; don't have to, ok? Look but don't touch. Use this lib and you'll +;; go blind. + +;; DEPRECATED in 1.2 with no replacement. + +(ns ^{:deprecated "1.2"} + clojure.contrib.apply-macro) + +;; Copied from clojure.core/spread, which is private. +(defn- spread + "Flatten final argument list as in apply." + [arglist] + (cond + (nil? arglist) nil + (nil? (rest arglist)) (seq (first arglist)) + :else (cons (first arglist) (spread (rest arglist))))) + +(defmacro apply-macro + "This is evil. Don't ever use it. It makes a macro behave like a + function. Seriously, how messed up is that? + + Evaluates all args, then uses them as arguments to the macro as with + apply. + + (def things [true true false]) + (apply-macro and things) + ;; Expands to: (and true true false)" + [macro & args] + (cons macro (spread (map eval args)))) diff --git a/modules/http-agent/pom.xml b/modules/http-agent/pom.xml new file mode 100644 index 00000000..4de1a63c --- /dev/null +++ b/modules/http-agent/pom.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.clojure.contrib</groupId> + <artifactId>parent</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../parent</relativePath> + </parent> + <artifactId>http-agent</artifactId> + <dependencies> + <dependency> + <groupId>org.clojure.contrib</groupId> + <artifactId>http-connection</artifactId> + <version>1.3.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.clojure.contrib</groupId> + <artifactId>io</artifactId> + <version>1.3.0-SNAPSHOT</version> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/modules/http-agent/src/main/clojure/clojure/contrib/http/agent.clj b/modules/http-agent/src/main/clojure/clojure/contrib/http/agent.clj new file mode 100644 index 00000000..a42431f6 --- /dev/null +++ b/modules/http-agent/src/main/clojure/clojure/contrib/http/agent.clj @@ -0,0 +1,386 @@ +;;; http/agent.clj: agent-based asynchronous HTTP client + +;; by Stuart Sierra, http://stuartsierra.com/ +;; August 17, 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. + +;; DEPRECATED IN 1.2. Use direct Java bits, or take a look at +;; http://github.com/technomancy/clojure-http-client + +(ns ^{:deprecated "1.2" + :doc "Agent-based asynchronous HTTP client. + + This is a HTTP client library based on Java's HttpURLConnection + class and Clojure's Agent system. It allows you to make multiple + HTTP requests in parallel. + + Start an HTTP request with the 'http-agent' function, which + immediately returns a Clojure Agent. You will never deref this + agent; that is handled by the accessor functions. The agent will + execute the HTTP request on a separate thread. + + If you pass a :handler function to http-agent, that function will be + called as soon as the HTTP response body is ready. The handler + function is called with one argument, the HTTP agent itself. The + handler can read the response body by calling the 'stream' function + on the agent. + + The value returned by the handler function becomes part of the state + of the agent, and you can retrieve it with the 'result' function. + If you call 'result' before the HTTP request has finished, it will + block until the handler function returns. + + If you don't provide a handler function, the default handler will + buffer the entire response body in memory, which you can retrieve + with the 'bytes', 'string', or 'stream' functions. Like 'result', + these functions will block until the HTTP request is completed. + + If you want to check if an HTTP request is finished without + blocking, use the 'done?' function. + + A single GET request could be as simple as: + + (string (http-agent \"http://www.stuartsierra.com/\")) + + A simple POST might look like: + + (http-agent \"http...\" :method \"POST\" :body \"foo=1\") + + And you could write the response directly to a file like this: + + (require '[clojure.contrib.io :as d]) + + (http-agent \"http...\" + :handler (fn [agnt] + (with-open [w (d/writer \"/tmp/out\")] + (d/copy (stream agnt) w)))) +" + :author "Stuart Sierra" + } + + clojure.contrib.http.agent + (:refer-clojure :exclude [bytes]) + (:require [clojure.contrib.http.connection :as c] + [clojure.contrib.io :as duck]) + (:import (java.io InputStream ByteArrayOutputStream + ByteArrayInputStream) + (java.net HttpURLConnection))) + + +;;; PRIVATE + +(declare result stream) + +(defn- setup-http-connection + "Sets the instance method, redirect behavior, and request headers of + the HttpURLConnection." + [^HttpURLConnection conn options] + (when-let [t (:connect-timeout options)] + (.setConnectTimeout conn t)) + (when-let [t (:read-timeout options)] + (.setReadTimeout conn t)) + (.setRequestMethod conn (:method options)) + (.setInstanceFollowRedirects conn (:follow-redirects options)) + (doseq [[name value] (:headers options)] + (.setRequestProperty conn name value))) + +(defn- start-request + "Agent action that starts sending the HTTP request." + [state options] + (let [conn (::connection state)] + (setup-http-connection conn options) + (c/start-http-connection conn (:body options)) + (assoc state ::state ::started))) + +(defn- connection-success? [^HttpURLConnection conn] + "Returns true if the HttpURLConnection response code is in the 2xx + range." + (= 2 (quot (.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." ; + [state options] + (let [^HttpURLConnection conn (::connection state)] + (assoc state + ::response-stream (if (connection-success? conn) + (.getInputStream conn) + (.getErrorStream conn)) + ::state ::receiving))) + +(defn- handle-response + "Agent action that calls the provided handler function, with no + arguments, and sets the ::result key of the agent to the handler's + return value." + [state handler options] + (let [conn (::connection state)] + (assoc state + ::result (handler) + ::state ::finished))) + +(defn- disconnect + "Agent action that closes the response body stream and disconnects + the HttpURLConnection." + [state options] + (when (::response-stream state) + (.close ^InputStream (::response-stream state))) + (.disconnect ^HttpURLConnection (::connection state)) + (assoc state + ::response-stream nil + ::state ::disconnected)) + +(defn- status-in-range? + "Returns true if the response status of the HTTP agent begins with + digit, an Integer." + [digit http-agnt] + (= digit (quot (.getResponseCode + ^HttpURLConnection (::connection @http-agnt)) + 100))) + +(defn- ^ByteArrayOutputStream get-byte-buffer [http-agnt] + (let [buffer (result http-agnt)] + (if (instance? ByteArrayOutputStream buffer) + buffer + (throw (Exception. "Handler result was not a ByteArrayOutputStream"))))) + + +(defn buffer-bytes + "The default HTTP agent result handler; it collects the response + body in a java.io.ByteArrayOutputStream, which can later be + retrieved with the 'stream', 'string', and 'bytes' functions." + [http-agnt] + (let [output (ByteArrayOutputStream.)] + (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}) + +(defn http-agent + "Creates (and immediately returns) an Agent representing an HTTP + request running in a new thread. + + options are key/value pairs: + + :method string + + The HTTP method name. Default is \"GET\". + + :headers h + + HTTP headers, as a Map or a sequence of pairs like + ([key1,value1], [key2,value2]) Default is nil. + + :body b + + HTTP request entity body, one of nil, String, byte[], InputStream, + Reader, or File. Default is nil. + + :connect-timeout int + + Timeout value, in milliseconds, when opening a connection to the + URL. Default is zero, meaning no timeout. + + :read-timeout int + + Timeout value, in milliseconds, when reading data from the + connection. Default is zero, meaning no timeout. + + :follow-redirects boolean + + If true, HTTP 3xx redirects will be followed automatically. Default + is true. + + :handler f + + Function to be called when the HTTP response body is ready. If you + do not provide a handler function, the default is to buffer the + entire response body in memory. + + The handler function will be called with the HTTP agent as its + argument, and can use the 'stream' function to read the response + body. The return value of this function will be stored in the state + of the agent and can be retrieved with the 'result' function. Any + exceptions thrown by this function will be added to the agent's + error queue (see agent-errors). The default function collects the + response stream in a memory buffer. + " + ([uri & options] + (let [opts (merge *http-agent-defaults* (apply array-map options))] + (let [a (agent {::connection (c/http-connection uri) + ::state ::created + ::uri uri + ::options opts})] + (send-off a start-request opts) + (send-off a open-response opts) + (send-off a handle-response (partial (:handler opts) a) opts) + (send-off a disconnect opts))))) + + +;;; RESPONSE BODY ACCESSORS + +(defn result + "Returns the value returned by the :handler function of the HTTP + agent; blocks until the HTTP request is completed. The default + handler function returns a ByteArrayOutputStream." + [http-agnt] + (await http-agnt) + (::result @http-agnt)) + +(defn stream + "Returns an InputStream of the HTTP response body. When called by + the handler function passed to http-agent, this is the raw + HttpURLConnection stream. + + If the default handler function was used, this function returns a + ByteArrayInputStream on the buffered response body." + [http-agnt] + (let [a @http-agnt] + (if (= (::state a) ::receiving) + (::response-stream a) + (ByteArrayInputStream. + (.toByteArray (get-byte-buffer http-agnt)))))) + +(defn bytes + "Returns a Java byte array of the content returned by the server; + nil if the content is not yet available." + [http-agnt] + (.toByteArray (get-byte-buffer http-agnt))) + +(defn string + "Returns the HTTP response body as a string, using the given + encoding. + + If no encoding is given, uses the encoding specified in the server + headers, or clojure.contrib.io/*default-encoding* if it is + not specified." + ([http-agnt] + (await http-agnt) ;; have to wait for Content-Encoding + (string http-agnt (or (.getContentEncoding + ^HttpURLConnection (::connection @http-agnt)) + duck/*default-encoding*))) + ([http-agnt ^String encoding] + (.toString (get-byte-buffer http-agnt) encoding))) + + +;;; REQUEST ACCESSORS + +(defn request-uri + "Returns the URI/URL requested by this HTTP agent, as a String." + [http-agnt] + (::uri @http-agnt)) + +(defn request-headers + "Returns the request headers specified for this HTTP agent." + [http-agnt] + (:headers (::options @http-agnt))) + +(defn method + "Returns the HTTP method name used by this HTTP agent, as a String." + [http-agnt] + (:method (::options @http-agnt))) + +(defn request-body + "Returns the HTTP request body given to this HTTP agent. + + Note: if the request body was an InputStream or a Reader, it will no + longer be usable." + [http-agnt] + (:body (::options @http-agnt))) + + +;;; RESPONSE ACCESSORS + +(defn done? + "Returns true if the HTTP request/response has completed." + [http-agnt] + (if (#{::finished ::disconnected} (::state @http-agnt)) + true false)) + +(defn status + "Returns the HTTP response status code (e.g. 200, 404) for this + request, as an Integer, or nil if the status has not yet been + received." + [http-agnt] + (when (done? 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 ^HttpURLConnection (::connection @http-agnt)))) + +(defn headers + "Returns a map of HTTP response headers. Header names are converted + to keywords in all lower-case Header values are strings. If a + header appears more than once, only the last value is returned." + [http-agnt] + (reduce (fn [m [^String k v]] + (assoc m (when k (keyword (.toLowerCase k))) (last v))) + {} (.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 [^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)))) + + +;;; RESPONSE STATUS CODE ACCESSORS + +(defn success? + "Returns true if the HTTP response code was in the 200-299 range." + [http-agnt] + (status-in-range? 2 http-agnt)) + +(defn redirect? + "Returns true if the HTTP response code was in the 300-399 range. + + Note: if the :follow-redirects option was true (the default), + redirects will be followed automatically and a the agent will never + return a 3xx response code." + [http-agnt] + (status-in-range? 3 http-agnt)) + +(defn client-error? + "Returns true if the HTTP response code was in the 400-499 range." + [http-agnt] + (status-in-range? 4 http-agnt)) + +(defn server-error? + "Returns true if the HTTP response code was in the 500-599 range." + [http-agnt] + (status-in-range? 5 http-agnt)) + +(defn error? + "Returns true if the HTTP response code was in the 400-499 range OR + the 500-599 range." + [http-agnt] + (or (client-error? http-agnt) + (server-error? http-agnt))) diff --git a/modules/http-connection/pom.xml b/modules/http-connection/pom.xml new file mode 100644 index 00000000..74aaa0b0 --- /dev/null +++ b/modules/http-connection/pom.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.clojure.contrib</groupId> + <artifactId>parent</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../parent</relativePath> + </parent> + <artifactId>http-connection</artifactId> + <dependencies> + <dependency> + <groupId>org.clojure.contrib</groupId> + <artifactId>io</artifactId> + <version>1.3.0-SNAPSHOT</version> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/modules/http-connection/src/main/clojure/clojure/contrib/http/connection.clj b/modules/http-connection/src/main/clojure/clojure/contrib/http/connection.clj new file mode 100644 index 00000000..c6cf162a --- /dev/null +++ b/modules/http-connection/src/main/clojure/clojure/contrib/http/connection.clj @@ -0,0 +1,62 @@ +;;; http/connection.clj: low-level HTTP client API around HttpURLConnection + +;; by Stuart Sierra, http://stuartsierra.com/ +;; June 8, 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. + +;; DEPRECATED IN 1.2. Use direct Java bits, or take a look at +;; http://github.com/technomancy/clojure-http-client + +(ns ^{:deprecated "1.2" + :doc "Low-level HTTP client API around HttpURLConnection"} + clojure.contrib.http.connection + (:require [clojure.contrib.io :as duck]) + (:import (java.net URI URL HttpURLConnection) + (java.io File InputStream Reader))) + +(defn http-connection + "Opens an HttpURLConnection at the URL, handled by as-url." + [url] + (.openConnection (duck/as-url url))) + +(defmulti + ^{:doc "Transmits a request entity body."} + send-request-entity (fn [conn entity] (type entity))) + +(defmethod send-request-entity duck/*byte-array-type* [^HttpURLConnection conn entity] + (.setFixedLengthStreamingMode conn (count entity)) + (.connect conn) + (duck/copy entity (.getOutputStream conn))) + +(defmethod send-request-entity String [conn ^String entity] + (send-request-entity conn (.getBytes entity duck/*default-encoding*))) + +(defmethod send-request-entity File [^HttpURLConnection conn ^File entity] + (.setFixedLengthStreamingMode conn (.length entity)) + (.connect conn) + (duck/copy entity (.getOutputStream conn))) + +(defmethod send-request-entity InputStream [^HttpURLConnection conn entity] + (.setChunkedStreamingMode conn -1) + (.connect conn) + (duck/copy entity (.getOutputStream conn))) + +(defmethod send-request-entity Reader [^HttpURLConnection conn entity] + (.setChunkedStreamingMode conn -1) + (.connect conn) + (duck/copy entity (.getOutputStream conn))) + +(defn start-http-connection + ([^HttpURLConnection conn] (.connect conn)) + ([^HttpURLConnection conn request-entity-body] + (if request-entity-body + (do (.setDoOutput conn true) + (send-request-entity conn request-entity-body)) + (.connect conn)))) diff --git a/modules/javadoc/pom.xml b/modules/javadoc/pom.xml new file mode 100644 index 00000000..4479bb97 --- /dev/null +++ b/modules/javadoc/pom.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.clojure.contrib</groupId> + <artifactId>parent</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../parent</relativePath> + </parent> + <artifactId>javadoc</artifactId> + <dependencies> + <dependency> + <groupId>org.clojure.contrib</groupId> + <artifactId>shell</artifactId> + <version>1.3.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.clojure.contrib</groupId> + <artifactId>def</artifactId> + <version>1.3.0-SNAPSHOT</version> + </dependency> + </dependencies> +</project> diff --git a/modules/javadoc/src/main/clojure/clojure/contrib/javadoc.clj b/modules/javadoc/src/main/clojure/clojure/contrib/javadoc.clj new file mode 100644 index 00000000..7ac30a4e --- /dev/null +++ b/modules/javadoc/src/main/clojure/clojure/contrib/javadoc.clj @@ -0,0 +1,4 @@ +(ns ^{:deprecated "1.2"} + clojure.contrib.javadoc) + +(throw (Exception. "clojure.contrib.javadoc/javadoc can now be found in clojure.java.javadoc")) diff --git a/modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse.clj b/modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse.clj new file mode 100644 index 00000000..a47fc0cd --- /dev/null +++ b/modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse.clj @@ -0,0 +1,51 @@ +;;; browse.clj -- start a web browser from Clojure + +; Copyright (c) Christophe Grand, December 2008. 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 + ^{:author "Christophe Grand", + :deprecated "1.2" + :doc "Start a web browser from Clojure"} + clojure.contrib.javadoc.browse + (:require [clojure.contrib.shell :as sh]) + (:import (java.net URI))) + +(defn- macosx? [] + (-> "os.name" System/getProperty .toLowerCase + (.startsWith "mac os x"))) + +(def *open-url-script* (when (macosx?) "/usr/bin/open")) + +(defn open-url-in-browser + "Opens url (a string) in the default system web browser. May not + work on all platforms. Returns url on success, nil if not + supported." + [url] + (try + (when (clojure.lang.Reflector/invokeStaticMethod "java.awt.Desktop" + "isDesktopSupported" (to-array nil)) + (-> (clojure.lang.Reflector/invokeStaticMethod "java.awt.Desktop" + "getDesktop" (to-array nil)) + (.browse (URI. url))) + url) + (catch ClassNotFoundException e + nil))) + +(defn open-url-in-swing + "Opens url (a string) in a Swing window." + [url] + ; the implementation of this function resides in another namespace to be loaded "on demand" + ; this fixes a bug on mac os x where requiring repl-utils turns the process into a GUI app + ; see http://code.google.com/p/clojure-contrib/issues/detail?id=32 + (require 'clojure.contrib.javadoc.browse-ui) + ((find-var 'clojure.contrib.javadoc.browse-ui/open-url-in-swing) url)) + +(defn browse-url [url] + (or (open-url-in-browser url) (when *open-url-script* (sh/sh *open-url-script* (str url)) true) (open-url-in-swing url))) diff --git a/modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse_ui.clj b/modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse_ui.clj new file mode 100644 index 00000000..388c76d5 --- /dev/null +++ b/modules/javadoc/src/main/clojure/clojure/contrib/javadoc/browse_ui.clj @@ -0,0 +1,31 @@ +;;; browse_ui.clj -- starts a swing web browser :-( + +; Copyright (c) Christophe Grand, December 2008. 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 ^{:deprecated "1.2"} + clojure.contrib.javadoc.browse-ui) + +(defn open-url-in-swing + "Opens url (a string) in a Swing window." + [url] + (let [htmlpane (javax.swing.JEditorPane. url)] + (.setEditable htmlpane false) + (.addHyperlinkListener htmlpane + (proxy [javax.swing.event.HyperlinkListener] [] + (hyperlinkUpdate [^javax.swing.event.HyperlinkEvent e] + (when (= (.getEventType e) (. javax.swing.event.HyperlinkEvent$EventType ACTIVATED)) + (if (instance? javax.swing.text.html.HTMLFrameHyperlinkEvent e) + (-> htmlpane .getDocument (.processHTMLFrameHyperlinkEvent e)) + (.setPage htmlpane (.getURL e))))))) + (doto (javax.swing.JFrame.) + (.setContentPane (javax.swing.JScrollPane. htmlpane)) + (.setBounds 32 32 700 900) + (.show)))) + diff --git a/modules/properties/pom.xml b/modules/properties/pom.xml new file mode 100644 index 00000000..c0cbca7a --- /dev/null +++ b/modules/properties/pom.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.clojure.contrib</groupId> + <artifactId>parent</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../parent</relativePath> + </parent> + <artifactId>properties</artifactId> + <dependencies> + <dependency> + <groupId>org.clojure.contrib</groupId> + <artifactId>io</artifactId> + <version>1.3.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.clojure.contrib</groupId> + <artifactId>string</artifactId> + <version>1.3.0-SNAPSHOT</version> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/modules/properties/src/main/clojure/clojure/contrib/properties.clj b/modules/properties/src/main/clojure/clojure/contrib/properties.clj new file mode 100644 index 00000000..0e210206 --- /dev/null +++ b/modules/properties/src/main/clojure/clojure/contrib/properties.clj @@ -0,0 +1,77 @@ +; Copyright (c) Stuart Halloway & Contributors, 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. + +;; DEPRECATED in 1.2. Moved to c.c.java-utils + +(ns ^{:deprecated "1.2"} + clojure.contrib.properties + (:use [clojure.contrib.string :only (as-str)] + [clojure.contrib.io :only (file)]) + (:import (java.util Properties) + (java.io FileInputStream FileOutputStream))) + +(defn get-system-property + "Get a system property." + ([stringable] + (System/getProperty (as-str stringable))) + ([stringable default] + (System/getProperty (as-str stringable) default))) + +(defn set-system-properties + "Set some system properties. Nil clears a property." + [settings] + (doseq [[name val] settings] + (if val + (System/setProperty (as-str name) (as-str val)) + (System/clearProperty (as-str name))))) + +(defmacro with-system-properties + "setting => property-name value + + Sets the system properties to the supplied values, executes the body, and + sets the properties back to their original values. Values of nil are + translated to a clearing of the property." + [settings & body] + `(let [settings# ~settings + current# (reduce (fn [coll# k#] + (assoc coll# k# (get-system-property k#))) + {} + (keys settings#))] + (set-system-properties settings#) + (try + ~@body + (finally + (set-system-properties current#))))) + + +; Not there is no corresponding props->map. Just destructure! +(defn ^Properties as-properties + "Convert any seq of pairs to a java.utils.Properties instance. + Uses as-str to convert both keys and values into strings." + {:tag Properties} + [m] + (let [p (Properties.)] + (doseq [[k v] m] + (.setProperty p (as-str k) (as-str v))) + p)) + +(defn read-properties + "Read properties from file-able." + [file-able] + (with-open [f (java.io.FileInputStream. (file file-able))] + (doto (Properties.) + (.load f)))) + +(defn write-properties + "Write properties to file-able." + {:tag Properties} + ([m file-able] (write-properties m file-able nil)) + ([m file-able comments] + (with-open [^FileOutputStream f (FileOutputStream. (file file-able))] + (doto (as-properties m) + (.store f ^String comments))))) diff --git a/modules/properties/src/test/clojure/clojure/contrib/test_properties.clj b/modules/properties/src/test/clojure/clojure/contrib/test_properties.clj new file mode 100644 index 00000000..65b1371f --- /dev/null +++ b/modules/properties/src/test/clojure/clojure/contrib/test_properties.clj @@ -0,0 +1,63 @@ +(ns clojure.contrib.test-properties + (:refer-clojure :exclude (spit)) + (:use clojure.test clojure.contrib.properties + [clojure.contrib.io :only (spit)]) + (:import (java.util Properties) + (java.io File))) + +(deftest test-get-system-property + (testing "works the same with keywords, symbols, and strings" + (is (= (get-system-property "java.home") (get-system-property 'java.home))) + (is (= (get-system-property "java.home") (get-system-property :java.home)))) + (testing "treats second arg as default" + (is (= "default" (get-system-property "testing.test-system-property" "default")))) + (testing "returns nil for missing properties" + (is (nil? (get-system-property "testing.test-system-property"))))) + +(deftest test-set-system-properties + (testing "set and then unset a property using keywords" + (let [propname :clojure.contrib.java.test-set-system-properties] + (is (nil? (get-system-property propname))) + (set-system-properties {propname :foo}) + (is (= "foo") (get-system-property propname)) + (set-system-properties {propname nil}) + (is (nil? (get-system-property propname)))))) + +(deftest test-with-system-properties + (let [propname :clojure.contrib.java.test-with-system-properties] + (testing "sets a property only for the duration of a block" + (is (= "foo" + (with-system-properties {propname "foo"} + (get-system-property propname)))) + (is (nil? (get-system-property propname))))) + (testing "leaves other properties alone" + ; TODO: write this test better, using a properties -> map function + (let [propname :clojure.contrib.java.test-with-system-properties + propcount (count (System/getProperties))] + (with-system-properties {propname "foo"} + (is (= (inc propcount) (count (System/getProperties))))) + (is (= propcount (count (System/getProperties))))))) + +(deftest test-as-properties + (let [expected (doto (Properties.) + (.setProperty "a" "b") + (.setProperty "c" "d"))] + (testing "with a map" + (is (= expected + (as-properties {:a "b" :c "d"})))) + (testing "with a sequence of pairs" + (is (= expected + (as-properties [[:a :b] [:c :d]])))))) + +(deftest test-read-properties + (let [f (File/createTempFile "test" "properties")] + (spit f "a=b\nc=d") + (is (= {"a" "b" "c" "d"} + (read-properties f))))) + +(deftest test-write-properties + (let [f (File/createTempFile "test" "properties")] + (write-properties [['a 'b] ['c 'd]] f) + (is (= {"a" "b" "c" "d"} + (read-properties f))))) + diff --git a/modules/test-is/pom.xml b/modules/test-is/pom.xml new file mode 100644 index 00000000..c0fb8a47 --- /dev/null +++ b/modules/test-is/pom.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http//www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.clojure.contrib</groupId> + <artifactId>parent</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../parent</relativePath> + </parent> + <artifactId>test-is</artifactId> + <dependencies> + </dependencies> +</project>
\ No newline at end of file diff --git a/modules/test-is/src/main/clojure/clojure/contrib/test_is.clj b/modules/test-is/src/main/clojure/clojure/contrib/test_is.clj new file mode 100644 index 00000000..a1b0d8f9 --- /dev/null +++ b/modules/test-is/src/main/clojure/clojure/contrib/test_is.clj @@ -0,0 +1,119 @@ +;;; test_is.clj: Compatibility layer for old clojure.contrib.test-is + +;; by Stuart Sierra, http://stuartsierra.com/ +;; August 28, 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. + +;; DEPRECATED in 1.2: Moved to clojure.test + +(ns ^{:deprecated "1.2" + :doc "Backwards-compatibility for clojure.contrib.test-is + + The clojure.contrib.test-is library moved from Contrib into the + Clojure distribution as clojure.test. + + This happened on or around clojure-contrib Git commit + 82cf0409d0fcb71be477ebfc4da18ee2128a2ad1 on June 25, 2009. + + This file makes the clojure.test interface available under the old + namespace clojure.contrib.test-is. + + This includes support for the old syntax of the 'are' macro. + + This was suggested by Howard Lewis Ship in ticket #26, + http://www.assembla.com/spaces/clojure-contrib/tickets/26" + :author "Stuart Sierra"} + clojure.contrib.test-is + (:require clojure.test + [clojure.walk :as walk])) + + +;;; COPY INTERNED VARS (EXCEPT are) FROM clojure.test + +(doseq [v (disj (set (vals (ns-interns 'clojure.test))) + #'clojure.test/are)] + (intern *ns* (with-meta (:name (meta v)) (meta v)) (var-get v))) + + +;;; REDEFINE OLD clojure.contrib.template + +(defn find-symbols + "Recursively finds all symbols in form." + [form] + (distinct (filter symbol? (tree-seq coll? seq form)))) + +(defn find-holes + "Recursively finds all symbols starting with _ in form." + [form] + (sort (distinct (filter #(.startsWith (name %) "_") + (find-symbols form))))) + +(defn find-pure-exprs + "Recursively finds all sub-expressions in form that do not contain + any symbols starting with _" + [form] + (filter #(and (list? %) + (empty? (find-holes %))) + (tree-seq seq? seq form))) + +(defn flatten-map + "Transforms a map into a vector like [key value key value]." + [m] + (reduce (fn [coll [k v]] (conj coll k v)) + [] m)) + +(defn template? + "Returns true if form is a valid template expression." + [form] + (if (seq (find-holes form)) true false)) + +(defn apply-template + "Replaces _1, _2, _3, etc. in expr with corresponding elements of + values. Returns the modified expression. For use in macros." + [expr values] + (when-not (template? expr) + (throw (IllegalArgumentException. (str (pr-str expr) " is not a valid template.")))) + (let [expr (walk/postwalk-replace {'_ '_1} expr) + holes (find-holes expr) + smap (zipmap holes values)] + (walk/prewalk-replace smap expr))) + +(defmacro do-template + "Repeatedly evaluates template expr (in a do block) using values in + args. args are grouped by the number of holes in the template. + Example: (do-template (check _1 _2) :a :b :c :d) + expands to (do (check :a :b) (check :c :d))" + [expr & args] + (when-not (template? expr) + (throw (IllegalArgumentException. (str (pr-str expr) " is not a valid template.")))) + (let [expr (walk/postwalk-replace {'_ '_1} expr) + argcount (count (find-holes expr))] + `(do ~@(map (fn [a] (apply-template expr a)) + (partition argcount args))))) + + + +;;; REDEFINE are MACRO TO MATCH OLD TEMPLATE BEHAVIOR + +(defmacro are + "Checks multiple assertions with a template expression. + See clojure.contrib.template/do-template for an explanation of + templates. + + Example: (are (= _1 _2) + 2 (+ 1 1) + 4 (* 2 2)) + Expands to: + (do (is (= 2 (+ 1 1))) + (is (= 4 (* 2 2)))) + + Note: This breaks some reporting features, such as line numbers." + [expr & args] + `(do-template (is ~expr) ~@args)) @@ -24,6 +24,7 @@ <module>modules/accumulators</module> <module>modules/agent-utils</module> + <module>modules/apply-macro</module> <module>modules/base64</module> <module>modules/classpath</module> <module>modules/combinatorics</module> @@ -45,10 +46,13 @@ <module>modules/generic</module> <module>modules/graph</module> <module>modules/greatest-least</module> + <module>modules/http-agent</module> + <module>modules/http-connection</module> <module>modules/import-static</module> <module>modules/io</module> <module>modules/jar</module> <module>modules/java-utils</module> + <module>modules/javadoc</module> <module>modules/jmx</module> <module>modules/json</module> <module>modules/lazy-seqs</module> @@ -68,6 +72,7 @@ <module>modules/priority-map</module> <module>modules/probabilities</module> <module>modules/profile</module> + <module>modules/properties</module> <module>modules/prxml</module> <module>modules/reflect</module> <module>modules/repl-ln</module> @@ -86,6 +91,7 @@ <module>modules/string</module> <module>modules/strint</module> <module>modules/swing-utils</module> + <module>modules/test-is</module> <module>modules/trace</module> <module>modules/types</module> <module>modules/with-ns</module> |