annotate src/clojure/contrib/def.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 ;; Copyright (c) Stephen C. Gilardi. All rights reserved. The use and
rlm@10 2 ;; distribution terms for this software are covered by the Eclipse Public
rlm@10 3 ;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
rlm@10 4 ;; be found in the file epl-v10.html at the root of this distribution. By
rlm@10 5 ;; using this software in any fashion, you are agreeing to be bound by the
rlm@10 6 ;; terms of this license. You must not remove this notice, or any other,
rlm@10 7 ;; from this software.
rlm@10 8 ;;
rlm@10 9 ;; File: def.clj
rlm@10 10 ;;
rlm@10 11 ;; def.clj provides variants of def that make including doc strings and
rlm@10 12 ;; making private definitions more succinct.
rlm@10 13 ;;
rlm@10 14 ;; scgilardi (gmail)
rlm@10 15 ;; 17 May 2008
rlm@10 16
rlm@10 17 (ns
rlm@10 18 ^{:author "Stephen C. Gilardi",
rlm@10 19 :doc "def.clj provides variants of def that make including doc strings and
rlm@10 20 making private definitions more succinct."}
rlm@10 21 clojure.contrib.def)
rlm@10 22
rlm@10 23 (defmacro defvar
rlm@10 24 "Defines a var with an optional intializer and doc string"
rlm@10 25 ([name]
rlm@10 26 (list `def name))
rlm@10 27 ([name init]
rlm@10 28 (list `def name init))
rlm@10 29 ([name init doc]
rlm@10 30 (list `def (with-meta name (assoc (meta name) :doc doc)) init)))
rlm@10 31
rlm@10 32 (defmacro defunbound
rlm@10 33 "Defines an unbound var with optional doc string"
rlm@10 34 ([name]
rlm@10 35 (list `def name))
rlm@10 36 ([name doc]
rlm@10 37 (list `def (with-meta name (assoc (meta name) :doc doc)))))
rlm@10 38
rlm@10 39 (defmacro defmacro-
rlm@10 40 "Same as defmacro but yields a private definition"
rlm@10 41 [name & decls]
rlm@10 42 (list* `defmacro (with-meta name (assoc (meta name) :private true)) decls))
rlm@10 43
rlm@10 44 (defmacro defvar-
rlm@10 45 "Same as defvar but yields a private definition"
rlm@10 46 [name & decls]
rlm@10 47 (list* `defvar (with-meta name (assoc (meta name) :private true)) decls))
rlm@10 48
rlm@10 49 (defmacro defunbound-
rlm@10 50 "Same as defunbound but yields a private definition"
rlm@10 51 [name & decls]
rlm@10 52 (list* `defunbound (with-meta name (assoc (meta name) :private true)) decls))
rlm@10 53
rlm@10 54 (defmacro defstruct-
rlm@10 55 "Same as defstruct but yields a private definition"
rlm@10 56 [name & decls]
rlm@10 57 (list* `defstruct (with-meta name (assoc (meta name) :private true)) decls))
rlm@10 58
rlm@10 59 (defmacro defonce-
rlm@10 60 "Same as defonce but yields a private definition"
rlm@10 61 ([name expr]
rlm@10 62 (list `defonce (with-meta name (assoc (meta name) :private true)) expr))
rlm@10 63 ([name expr doc]
rlm@10 64 (list `defonce (with-meta name (assoc (meta name) :private true :doc doc)) expr)))
rlm@10 65
rlm@10 66 (defmacro defalias
rlm@10 67 "Defines an alias for a var: a new var with the same root binding (if
rlm@10 68 any) and similar metadata. The metadata of the alias is its initial
rlm@10 69 metadata (as provided by def) merged into the metadata of the original."
rlm@10 70 ([name orig]
rlm@10 71 `(do
rlm@10 72 (alter-meta!
rlm@10 73 (if (.hasRoot (var ~orig))
rlm@10 74 (def ~name (.getRoot (var ~orig)))
rlm@10 75 (def ~name))
rlm@10 76 ;; When copying metadata, disregard {:macro false}.
rlm@10 77 ;; Workaround for http://www.assembla.com/spaces/clojure/tickets/273
rlm@10 78 #(conj (dissoc % :macro)
rlm@10 79 (apply dissoc (meta (var ~orig)) (remove #{:macro} (keys %)))))
rlm@10 80 (var ~name)))
rlm@10 81 ([name orig doc]
rlm@10 82 (list `defalias (with-meta name (assoc (meta name) :doc doc)) orig)))
rlm@10 83
rlm@10 84 ; defhinted by Chouser:
rlm@10 85 (defmacro defhinted
rlm@10 86 "Defines a var with a type hint matching the class of the given
rlm@10 87 init. Be careful about using any form of 'def' or 'binding' to a
rlm@10 88 value of a different type. See http://paste.lisp.org/display/73344"
rlm@10 89 [sym init]
rlm@10 90 `(do
rlm@10 91 (def ~sym ~init)
rlm@10 92 (alter-meta! (var ~sym) assoc :tag (class ~sym))
rlm@10 93 (var ~sym)))
rlm@10 94
rlm@10 95 ; name-with-attributes by Konrad Hinsen:
rlm@10 96 (defn name-with-attributes
rlm@10 97 "To be used in macro definitions.
rlm@10 98 Handles optional docstrings and attribute maps for a name to be defined
rlm@10 99 in a list of macro arguments. If the first macro argument is a string,
rlm@10 100 it is added as a docstring to name and removed from the macro argument
rlm@10 101 list. If afterwards the first macro argument is a map, its entries are
rlm@10 102 added to the name's metadata map and the map is removed from the
rlm@10 103 macro argument list. The return value is a vector containing the name
rlm@10 104 with its extended metadata map and the list of unprocessed macro
rlm@10 105 arguments."
rlm@10 106 [name macro-args]
rlm@10 107 (let [[docstring macro-args] (if (string? (first macro-args))
rlm@10 108 [(first macro-args) (next macro-args)]
rlm@10 109 [nil macro-args])
rlm@10 110 [attr macro-args] (if (map? (first macro-args))
rlm@10 111 [(first macro-args) (next macro-args)]
rlm@10 112 [{} macro-args])
rlm@10 113 attr (if docstring
rlm@10 114 (assoc attr :doc docstring)
rlm@10 115 attr)
rlm@10 116 attr (if (meta name)
rlm@10 117 (conj (meta name) attr)
rlm@10 118 attr)]
rlm@10 119 [(with-meta name attr) macro-args]))
rlm@10 120
rlm@10 121 ; defnk by Meikel Brandmeyer:
rlm@10 122 (defmacro defnk
rlm@10 123 "Define a function accepting keyword arguments. Symbols up to the first
rlm@10 124 keyword in the parameter list are taken as positional arguments. Then
rlm@10 125 an alternating sequence of keywords and defaults values is expected. The
rlm@10 126 values of the keyword arguments are available in the function body by
rlm@10 127 virtue of the symbol corresponding to the keyword (cf. :keys destructuring).
rlm@10 128 defnk accepts an optional docstring as well as an optional metadata map."
rlm@10 129 [fn-name & fn-tail]
rlm@10 130 (let [[fn-name [args & body]] (name-with-attributes fn-name fn-tail)
rlm@10 131 [pos kw-vals] (split-with symbol? args)
rlm@10 132 syms (map #(-> % name symbol) (take-nth 2 kw-vals))
rlm@10 133 values (take-nth 2 (rest kw-vals))
rlm@10 134 sym-vals (apply hash-map (interleave syms values))
rlm@10 135 de-map {:keys (vec syms)
rlm@10 136 :or sym-vals}]
rlm@10 137 `(defn ~fn-name
rlm@10 138 [~@pos & options#]
rlm@10 139 (let [~de-map (apply hash-map options#)]
rlm@10 140 ~@body))))
rlm@10 141
rlm@10 142 ; defn-memo by Chouser:
rlm@10 143 (defmacro defn-memo
rlm@10 144 "Just like defn, but memoizes the function using clojure.core/memoize"
rlm@10 145 [fn-name & defn-stuff]
rlm@10 146 `(do
rlm@10 147 (defn ~fn-name ~@defn-stuff)
rlm@10 148 (alter-var-root (var ~fn-name) memoize)
rlm@10 149 (var ~fn-name)))