blob: ea45c691eb6c834e1d9597d1828fe7b6215767c1 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
;; Copyright (c) James Reeves. 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 compojure.control
"Various macros for controling program flow."
(:use clojure.contrib.seq-utils))
(defmacro return
"A do block that will always return the argument 'x'."
[x & body]
`(let [x# ~x]
(do ~@body x#)))
(defmacro maybe
"Returns (f x & xs) if x is not nil, otherwise returns nil."
[f x & xs]
`(if (not (nil? ~x))
(~f ~x ~@xs)))
(defmacro domap
"Similar to doseq, but collects the results into a sequence."
[[item list] & body]
`(map (fn [~item] ~@body) (doall ~list)))
(defmacro redef
"Redefine an existing value, keeping the metadata intact."
[name value]
`(let [m# (meta #'~name)
v# (def ~name ~value)]
(alter-meta! v# merge m#)
v#))
(defmacro decorate
"Wrap a function in one or more decorators."
[func & decorators]
`(redef ~func (-> ~func ~@decorators)))
(defmacro decorate-with
"Wrap multiple functions in a decorator."
[decorator & funcs]
`(do ~@(for [f funcs]
`(redef ~f (~decorator ~f)))))
(defmacro decorate-bind
"Wrap named functions in a decorator for a bounded scope."
[decorator funcs & body]
`(binding
[~@(mapcat (fn [f] [f (list decorator f)]) funcs)]
~@body))
(defn apply-doc
"Return a symbol and body with an optional docstring applied."
[name doc? body]
(if (string? doc?)
(list* (with-meta name (assoc (meta name) :doc doc?)) body)
(list* name doc? body)))
(defmacro deftmpl
"Define a template function. Arguments are passed via key-value pairs.
e.g. (deftmpl foo [bar baz] (+ bar baz))
(foo :bar 1 :baz 2)"
[name doc? & body]
(let [[name params & body] (apply-doc name doc? body)]
`(defn ~name
~@doc?
[& param-map#]
(let [{:keys ~params} (apply hash-map param-map#)]
~@body))))
|