Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 384 lines (292 sloc) 9.752 kb
7c720fe @cemerick dump of REPL interactions and other inline code snippets
cemerick authored
1 ;-----
2 {:remote-addr "127.0.0.1",
3 :scheme :http,
4 :request-method :get,
5 :query-string "q=Acme",
6 :content-type nil,
7 :uri "/accounts",
8 :server-name "company.com",
9 :content-length nil,
10 :server-port 8080,
11 :body #<ByteArrayInputStream java.io.ByteArrayInputStream@604fd0e9>,
12 :headers
13 {"user-agent" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6) Firefox/8.0.1",
14 "accept-charset" "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
15 "accept" "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
16 "accept-encoding" "gzip, deflate",
17 "accept-language" "en-us,en;q=0.5",
18 "connection" "keep-alive"}}
19
20
21 ;-----
22 {:status 200
23 :headers {"Content-Type" "text/html"}
24 :body "<html>...</html>"}
25
26
27 ;-----
28 {:status 200
29 :headers {"Content-Type" "image/png"}
30 :body (java.io.File. "/path/to/file.png")}
31
32
33 ;-----
34 {:status 201 :headers {}}
35
36
37 ;-----
38 [ring "1.0.0"]
39
40
41 ;-----
42 (use '[ring.adapter.jetty :only (run-jetty)])
43 ;= nil
44 (defn app
45 [{:keys [uri]}]
46 {:body (format "You requested %s" uri)})
47 ;= #'user/app
48 (def server (run-jetty #'app {:port 8080 :join? false}))
49 ;= #'user/server
50
51
52 ;-----
53 (defn app
54 [{:keys [uri query-string]}]
55 {:body (format "You requested %s with query %s" uri query-string)})
56 ;= #'user/app
57
58
59 ;-----
60 (use '[ring.middleware.params :only (wrap-params)])
61 ;= nil
62 (defn app*
63 [{:keys [uri params]}]
64 {:body (format "You requested %s with query %s" uri params)})
65 ;= #'user/app*
66 (def app (wrap-params app*))
67 ;= #'user/app
68
69
70 ;-----
71 [compojure "1.0.0"]
72 [ring "1.0.0"]
73
74
75 ;-----
76 (def ^:private counter (atom 0))
77
78 (def ^:private mappings (ref {}))
79
80
81 ;-----
82 (defn url-for
83 [id]
84 (@mappings id))
85
86 (defn shorten!
87 "Stores the given URL under a new unique identifier, or the given identifier
88 if provided. Returns the identifier as a string.
89 Modifies the global mapping accordingly."
90 ([url]
91 (let [id (swap! counter inc)
92 id (Long/toString id 36)]
93 (or (shorten! url id)
94 (recur url))))
95 ([url id]
96 (dosync
97 (when-not (@mappings id)
98 (alter mappings assoc id url)
99 id))))
100
101
102 ;-----
103 (shorten! "http://clojurebook.com")
104 ;= "1"
105 (shorten! "http://clojure.org" "clj")
106 ;= "clj"
107 (shorten! "http://id-already-exists.com" "clj")
108 ;= nil
109 @mappings
110 ;= {"clj" "http://clojure.org", "1" "http://clojurebook.com"}
111
112
113 ;-----
114 (defn retain
115 [& [url id :as args]]
116 (if-let [id (apply shorten! args)]
117 {:status 201
118 :headers {"Location" id}
119 :body (list "URL " url " assigned the short identifier " id)}
120 {:status 409 :body (format "Short URL %s is already taken" id)}))
121
122
123 ;-----
124 (require 'ring.util.response)
125
126 (defn redirect
127 [id]
128 (if-let [url (url-for id)]
129 (ring.util.response/redirect url)
130 {:status 404 :body (str "No such short URL: " id)}))
131
132
133 ;-----
134 (use '[compojure.core :only (GET PUT POST defroutes)])
135 (require 'compojure.route)
136
137 (defroutes app*
138 (GET "/" request "Welcome!")
139 (PUT "/:id" [id url] (retain url id))
140 (POST "/" [url] (retain url))
141 (GET "/:id" [id] (redirect id))
142 (GET "/list/" [] (interpose "\n" (keys @mappings)))
143 (compojure.route/not-found "Sorry, there's nothing here."))
144
145
146 ;-----
147 (PUT "/:id" [id url] (retain url id))
148
149
150 ;-----
151 ((PUT "/:id"
152 [id url]
153 (list "You requested that " url " be assigned id " id))
154 {:uri "/some-id" :params {:url "http://clojurebook.com"} :request-method :put})
155 ;= {:status 200, :headers {"Content-Type" "text/html"},
156 ;= :body ("You requested that " "http://clojurebook.com" " be assigned id " "some-id")}
157
158
159 ;-----
160 ((PUT ["/*/*/:id/:id"]
161 [* id]
162 (str * id))
163 {:uri "/abc/xyz/foo/bar" :request-method :put})
164 ;= {:status 200, :headers {"Content-Type" "text/html"},
165 ;= :body "[\"abc\" \"xyz\"][\"foo\" \"bar\"]"}
166
167
168 ;-----
169 ((PUT ["/:id" :id #"\d+"]
170 [id url]
171 (list "You requested that " url " be assigned id " id))
172 {:uri "/some-id" :params {:url "http://clojurebook.com"} :request-method :put})
173 ;= nil
174 ((PUT ["/:id" :id #"\d+"]
175 [id url]
176 (list "You requested that " url " be assigned id " id))
177 {:uri "/590" :params {:url "http://clojurebook.com"} :request-method :put})
178 ;= {:status 200, :headers {"Content-Type" "text/html"},
179 ;= :body "You requested that http://clojurebook.com be assigned id 590"}
180
181
182 ;-----
183 ((PUT "/:id" req (str "You requested: " (:uri req)))
184 {:uri "/foo" :request-method :put})
185 ;= {:status 200, :headers {"Content-Type" "text/html"}, :body "You requested: /foo"}
186 ((PUT "/:id" {:keys [uri]} (str "You requested: " uri))
187 {:uri "/foo" :request-method :put})
188 ;= {:status 200, :headers {"Content-Type" "text/html"}, :body "You requested: /foo"}
189
190
191 ;-----
192 (require 'compojure.handler)
193
194 (def app (compojure.handler/api app*))
195
196
197 ;-----
198 (use '[ring.adapter.jetty :only (run-jetty)])
199 ;= nil
200 (def server (run-jetty #'app {:port 8080 :join? false}))
201 ;= #'user/server
202
203
204
205 ;-----
206 (defroutes app+admin
207 (GET "/admin/" request ...)
208 (POST "/admin/some-admin-action" request ...)
209 app*)
210
211
212
213 ;-----
214 (require '[net.cgrand.enlive-html :as h])
215 ;= nil
216 (h/sniptest "<h1>Lorem Ipsum</h1>")
217 ;= "<h1>Lorem Ipsum</h1>"
218
219
220 ;-----
221 (h/sniptest "<h1>Lorem Ipsum</h1>"
222 [:h1] (h/content "Hello Reader!"))
223 ;= "<h1>Hello Reader!</h1>"
224
225
226 ;-----
227 (h/html-snippet "<p>x, <a id=\"home\" href=\"/\">y</a>, <a href=\"..\">z</a></p>")
228 ;= ({:tag :p,
229 ;= :attrs nil,
230 ;= :content
231 ;= ("x, "
232 ;= {:tag :a, :attrs {:href "/", :id "home"}, :content ("y")}
233 ;= ", "
234 ;= {:tag :a, :attrs {:href ".."}, :content ("z")})})
235
236
237 ;-----
238 (h/sniptest "<p>x, <a id=\"home\" href=\"/\">y</a>, <a href=\"..\">z</a></p>"
239 [:a#home] (h/set-attr :href "http://clojurebook.com")
240 [[:a (h/attr= :href "..")]] (h/content "go up"))
241 ;= "<p>x, <a href=\"http://clojurebook.com\" id=\"home\">y</a>, <a href=\"..\">go up</a></p>"
242
243
244 ;-----
245 (h/sniptest "<p class=\"\"><a href=\"\" class=\"\"></a></p>"
246 [[:p (h/attr? :class)]] (h/content "XXX"))
247 ;= "<p class=\"\">XXX</p>"
248
249 (h/sniptest "<p class=\"\"><a href=\"\" class=\"\"></a></p>"
250 [:p (h/attr? :class)] (h/content "XXX"))
251 ;= "<p class=\"\"><a class=\"\" href=\"\">XXX</a></p>"
252
253
254 ;-----
255 (defn some-attr=
256 "Selector step, matches elements where at least one attribute
257 has the specified value."
258 [value]
259 (h/pred (fn [node]
260 (some #{value} (vals (:attrs node))))))
261
262
263 ;-----
264 (h/sniptest "<ul><li id=\"foo\">A<li>B<li name=\"foo\">C</li></ul>"
265 [(some-attr= "foo")] (h/set-attr :found "yes"))
266 ;= "<ul>
267 ;= <li found=\"yes\" id=\"foo\">A</li>
268 ;= <li>B</li>
269 ;= <li found=\"yes\" name=\"foo\">C</li>
270 ;= </ul>"
271
272
273 ;-----
274 (defn display
275 [msg]
276 (h/sniptest "<div><span class=\"msg\"></span></div>"
277 [:.msg] (when msg (h/content msg))))
278 ;= #'user/display
279 (display "Welcome back!")
280 ;= "<div><span class=\"msg\">Welcome back!</span></div>"
281 (display nil)
282 ;= "<div></div>"
283
284
285 ;-----
286 (defn display
287 [msg]
288 (h/sniptest "<div><span class=\"msg\"></span></div>"
289 [:.msg] (if msg
290 (h/content msg)
291 (h/add-class "hidden"))))
292 ;= #'user/display
293 (display nil)
294 ;= "<div><span class=\"msg hidden\"></span></div>"
295
296
297 ;-----
298 (defn countdown
299 [n]
300 (h/sniptest "<ul><li></li></ul>"
301 [:li] (h/clone-for [i (range n 0 -1)]
302 (h/content (str i)))))
303 ;= #'user/countdown
304 (countdown 0)
305 ;= "<ul></ul>"
306 (countdown 3)
307 ;= "<ul><li>3</li><li>2</li><li>1</li></ul>"
308
309
310 ;-----
311 (defn countdown
312 [n]
313 (h/sniptest "<ul><li id=\"foo\"></li></ul>"
314 [:#foo] (h/do->
315 (h/remove-attr :id)
316 (h/clone-for [i (range n 0 -1)]
317 (h/content (str i))))))
318 ;= #'user/countdown
319 (countdown 3)
320 ;= "<ul><li>3</li><li>2</li><li>1</li></ul>"
321
322
323
324 ;-----
325 (h/defsnippet footer "footer.html" [:.footer]
326 [message]
327 [:.footer] (h/content message))
328
329
330 ;-----
331 (footer "hello")
332 ;= ({:tag :div, :attrs {:class "footer"}, :content ("hello")})
333
334
335
336 ;-----
337 (h/deftemplate friends-list "friends.html"
338 [username friends]
339 [:.username] (h/content username)
340 [:ul.friends :li] (h/clone-for [f friends]
341 (h/content f)))
342
343 (friends-list "Chas" ["Christophe" "Brian"])
344 ;= ("<html>" "<body>" "<h1>" "Hello, " "<span class=\"username\">"
345 ;= "Chas" "</span>" "</h1>" "\n" "<p>These are your friends:</p>"
346 ;= "\n" "<ul class=\"friends\">" "<li>" "Christophe" "</li>" "<li>"
347 ;= "Brian" "</li>" "</ul>" "\n" "</body>" "</html>")
348
349
350 ;-----
351 (h/deftemplate friends-list "friends.html"
352 [username friends friend-class]
353 [:.username] (h/content username)
354 [:ul.friends :li] (h/clone-for [f friends]
355 (h/do-> (h/content f)
356 (h/add-class friend-class))))
357
358 (friends-list "Chas" ["Christophe" "Brian"] "programmer")
359 ;= ("<html>" "<body>" "<h1>" "Hello, " "<span class=\"username\">" "Chas"
360 ;= "</span>" "</h1>" "\n" "<p>These are your friends:</p>" "\n"
361 ;= "<ul class=\"friends\">" "<" "li" " " "class" "=\"" "programmer" "\""
362 ;= ">" "Christophe" "</" "li" ">" "<" "li" " " "class" "=\"" "programmer"
363 ;= "\"" ">" "Brian" "</" "li" ">" "</ul>" "\n" "</body>" "</html>")
364
365
366 ;-----
367 (h/deftemplate friends-list "friends.html"
368 [username friends friend-class]
369 [:.username] (h/content username)
370 [:ul.friends :li] (h/clone-for [f friends]
371 (h/do-> (h/content f)
372 (h/add-class friend-class)))
373 [:body] (h/append (footer (str "Goodbye, " username))))
374
375 (friends-list "Chas" ["Christophe" "Brian"] "programmer")
376 ;= ("<html>" "<body>" "<h1>" "Hello, " "<span class=\"username\">" "Chas"
377 ;= "</span>" "</h1>" "\n" "<p>These are your friends:</p>" "\n"
378 ;= "<ul class=\"friends\">" "<" "li" " " "class" "=\"" "programmer" "\""
379 ;= ">" "Christophe" "</" "li" ">" "<" "li" " " "class" "=\"" "programmer"
380 ;= "\"" ">" "Brian" "</" "li" ">" "</ul>" "\n" "<div class=\"footer\">"
381 ;= "Goodbye, Chas" "</div>" "</body>" "</html>")
382
383
Something went wrong with that request. Please try again.