Mercurial > lasercutter
view src/clojure/contrib/strint.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line source
1 ;;; strint.clj -- String interpolation for Clojure2 ;; originally proposed/published at http://muckandbrass.com/web/x/AgBP4 ;; by Chas Emerick <cemerick@snowtide.com>5 ;; December 4, 20097 ;; Copyright (c) Chas Emerick, 2009. All rights reserved. The use8 ;; and distribution terms for this software are covered by the Eclipse9 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)10 ;; which can be found in the file epl-v10.html at the root of this11 ;; distribution. By using this software in any fashion, you are12 ;; agreeing to be bound by the terms of this license. You must not13 ;; remove this notice, or any other, from this software.15 (ns16 ^{:author "Chas Emerick",17 :doc "String interpolation for Clojure."}18 clojure.contrib.strint)20 (defn- silent-read21 "Attempts to clojure.core/read a single form from the provided String, returning22 a vector containing the read form and a String containing the unread remainder23 of the provided String. Returns nil if no valid form can be read from the24 head of the String."25 [s]26 (try27 (let [r (-> s java.io.StringReader. java.io.PushbackReader.)]28 [(read r) (slurp r)])29 (catch Exception e))) ; this indicates an invalid form -- the head of s is just string data31 (defn- interpolate32 "Yields a seq of Strings and read forms."33 ([s atom?]34 (lazy-seq35 (if-let [[form rest] (silent-read (subs s (if atom? 2 1)))]36 (cons form (interpolate (if atom? (subs rest 1) rest)))37 (cons (subs s 0 2) (interpolate (subs s 2))))))38 ([^String s]39 (if-let [start (->> ["~{" "~("]40 (map #(.indexOf s %))41 (remove #(== -1 %))42 sort43 first)]44 (lazy-seq (cons45 (subs s 0 start)46 (interpolate (subs s start) (= \{ (.charAt s (inc start))))))47 [s])))49 (defmacro <<50 "Takes a single string argument and emits a str invocation that concatenates51 the string data and evaluated expressions contained within that argument.52 Evaluation is controlled using ~{} and ~() forms. The former is used for53 simple value replacement using clojure.core/str; the latter can be used to54 embed the results of arbitrary function invocation into the produced string.56 Examples:57 user=> (def v 30.5)58 #'user/v59 user=> (<< \"This trial required ~{v}ml of solution.\")60 \"This trial required 30.5ml of solution.\"61 user=> (<< \"There are ~(int v) days in November.\")62 \"There are 30 days in November.\"63 user=> (def m {:a [1 2 3]})64 #'user/m65 user=> (<< \"The total for your order is $~(->> m :a (apply +)).\")66 \"The total for your order is $6.\"68 Note that quotes surrounding string literals within ~() forms must be69 escaped."70 [string]71 `(str ~@(interpolate string)))