git.fiddlerwoaroof.com
Browse code

Dynamic view changing + other goodness

Add a switch-view restart that is wrapped around the controller and
changes the view to be executed at runtime. Useful to deal with cases
where an exceptional circumstance makes the original route suboptimal

fiddlerwoaroof authored on 22/05/2016 08:06:40
Showing 4 changed files
... ...
@@ -8,6 +8,7 @@
8 8
                #:alexandria
9 9
                #:serapeum
10 10
                #:ningle
11
+               #:fwoar.lisputils
11 12
                #:cl-mustache)
12 13
   :serial t
13 14
   :components ((:file "package")
... ...
@@ -13,7 +13,7 @@
13 13
 
14 14
 (defgeneric view (name model)
15 15
   (:documentation "specialized on NAME with an EQL-specializer. This generic function
16
-                   renders the model picked out by the controller. Normally, this is 
16
+                   renders the model picked out by the controller. Normally, this is
17 17
                    specialized using the DEFINE-VIEW macr"))
18 18
 
19 19
 (defmacro setf1 (&body body)
... ...
@@ -29,18 +29,48 @@
29 29
            (loop for ((target &key method) callback) in routes
30 30
                  collect `((ningle:route ,app ,target :method ,(or method :GET)) ,callback)))))
31 31
 
32
- 
32
+
33
+(defvar *view-name*)
33 34
 (defmacro as-route (name &rest r &key &allow-other-keys)
34 35
   "Create a lambda directing requests to the route for NAME.  This uses the
35 36
    generic function RUN-ROUTE internally whose default implementation relies on
36 37
    appropriate implementations of CONTROLLER and VIEW. The RUN-ROUTE method receives
37 38
    the parameters ningle passes to other functions as a first parameter, and then it
38 39
    receives a bunch of arguments according to the arguments passed to this macro."
39
-  `(lambda (params) (run-route ,name params ,@r)))
40
-
40
+  (alexandria:once-only (name)
41
+    `(lambda (params)
42
+       (run-route ,name params ,@r))))
43
+
44
+(defun %compose-route (controller controller-args view)
45
+  (declare (optimize (debug 3) (speed 0) (space 0) (safety 3)))
46
+  (lambda (params)
47
+    (declare (optimize (debug 3) (speed 0) (space 0) (safety 3)))
48
+    (apply #'view
49
+           (list view
50
+                 (apply #'controller
51
+                        (list* controller
52
+                               params
53
+                               controller-args))))))
54
+
55
+(defmacro compose-route ((controller &rest controller-args) view)
56
+  `(%compose-route ',controller ,controller-args ',view))
57
+
58
+(defun switch-view (view-name)
59
+  (format t "~&Switching view to: ~a~&" view-name)
60
+  (alexandria:if-let ((switch-view-restart (find-restart 'switch-view)))
61
+    (invoke-restart switch-view-restart view-name)
62
+    (cerror "ignore this error"
63
+            "Can only call switch-view while the route is being processed")))
41 64
 
42 65
 (defmethod run-route (name params &rest r)
43
-  (view name (apply #'controller (list* name params r))))
66
+  (let ((*view-name* name))
67
+    (fw.lu:let-each (:be *)
68
+      (list* name params r)
69
+      (restart-bind ((switch-view (lambda (new-view)
70
+                                    (format t "~%SWITCHING VIEW: ~a" new-view)
71
+                                    (setf *view-name* new-view))))
72
+        (apply #'controller *))
73
+      (view *view-name* *))))
44 74
 
45 75
 ; The default controller just passes its parameters directly to the view
46 76
 (defmethod controller (name params &key)
47 77
new file mode 100644
... ...
@@ -0,0 +1,2 @@
1
+(in-package #:araneus.form)
2
+
... ...
@@ -6,4 +6,8 @@
6 6
            #:controller #:view #:run-route #:mustache-view #:render-mustache
7 7
            #:setf1))
8 8
 
9
+(defpackage #:araneus.form
10
+  (:use #:cl)
11
+  (:export ))
12
+
9 13