Browse code
Initial commit of web library
fiddlerwoaroof authored on 09/02/2016 05:15:43
Showing 5 changed files
Showing 5 changed files
0 | 2 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,15 @@ |
1 |
+;;;; araneus.asd |
|
2 |
+ |
|
3 |
+(asdf:defsystem #:araneus |
|
4 |
+ :description "Describe araneus here" |
|
5 |
+ :author "Your Name <your.name@example.com>" |
|
6 |
+ :license "Specify license here" |
|
7 |
+ :depends-on (#:anaphora |
|
8 |
+ #:alexandria |
|
9 |
+ #:serapeum |
|
10 |
+ #:cl-mustache) |
|
11 |
+ :serial t |
|
12 |
+ :components ((:file "package") |
|
13 |
+ (:file "araneus"))) |
|
14 |
+ |
|
15 |
+;; vim: ft=lisp: |
0 | 16 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,61 @@ |
1 |
+;; This is a minimal web-framework built on ningle that attempts to decouple |
|
2 |
+;; views from controllers and make life more interesting. |
|
3 |
+(in-package :araneus) |
|
4 |
+ |
|
5 |
+(defgeneric controller (name params &key)) |
|
6 |
+(defgeneric view (name model)) |
|
7 |
+(defgeneric run-route (name params &rest r)) |
|
8 |
+ |
|
9 |
+(defmacro setf1 (&body body) |
|
10 |
+ "Make setf a bit nicer" |
|
11 |
+ (list* 'setf (apply #'append body))) |
|
12 |
+ |
|
13 |
+(defmacro defroutes (app &body routes) |
|
14 |
+ (alexandria:once-only (app) |
|
15 |
+ (list* 'setf1 |
|
16 |
+ (loop for ((target &key method) callback) in routes |
|
17 |
+ collect `((ningle:route ,app ,target :method ,(or method :GET)) ,callback))))) |
|
18 |
+ |
|
19 |
+ |
|
20 |
+(defmacro as-route (name &rest r &key &allow-other-keys) |
|
21 |
+ `(lambda (params) (run-route ,name params ,@r))) |
|
22 |
+ |
|
23 |
+ |
|
24 |
+(defmethod run-route (name params &rest r) |
|
25 |
+ (view name (apply #'controller (list* name params r)))) |
|
26 |
+ |
|
27 |
+(defmethod controller (name params &key) |
|
28 |
+ params) |
|
29 |
+ |
|
30 |
+(defmacro define-controller (name (params &rest r &key &allow-other-keys) &body body) |
|
31 |
+ `(defmethod controller ((name (eql ',name)) ,params &key ,@r) |
|
32 |
+ ,@body)) |
|
33 |
+ |
|
34 |
+(defmacro define-view (name (model) &body body) |
|
35 |
+ `(defmethod view ((name (eql ',name)) ,model) |
|
36 |
+ ,@body)) |
|
37 |
+ |
|
38 |
+(defun render-mustache (fn data) |
|
39 |
+ (with-open-file (s (truename fn)) |
|
40 |
+ (let ((template (make-string (file-length s)))) |
|
41 |
+ (read-sequence template s) |
|
42 |
+ (mustache:render* template data)))) |
|
43 |
+ |
|
44 |
+ |
|
45 |
+(defmacro mustache ((template lambda-list data) &body body) |
|
46 |
+ "Template specifies the template to be render, lambda-list is used to destructure data |
|
47 |
+ and body transforms the destructured data into an alist for use in the template" |
|
48 |
+ (alexandria:once-only (template) |
|
49 |
+ `(destructuring-bind ,lambda-list ,data |
|
50 |
+ (render-mustache ,template |
|
51 |
+ (list |
|
52 |
+ ,@(loop for (k v) on body by #'cddr |
|
53 |
+ if (or k v) |
|
54 |
+ collect `(cons ,k ,v))))))) |
|
55 |
+ |
|
56 |
+(defmacro mustache-view (name lambda-list template &body body) |
|
57 |
+ (alexandria:with-gensyms (model) |
|
58 |
+ `(define-view ,name (,model) |
|
59 |
+ (mustache (,template ,lambda-list ,model) |
|
60 |
+ ,@body)))) |
|
61 |
+ |