Christophe Weblog Wiki Code Publications Music
adapt content-negotiation method combination
authorChristophe Rhodes <csr21@cantab.net>
Tue, 17 Dec 2013 12:24:25 +0000 (12:24 +0000)
committerChristophe Rhodes <csr21@cantab.net>
Tue, 17 Dec 2013 12:24:25 +0000 (12:24 +0000)
Make CALL-NEXT-METHOD cause an irrevocable control transfer: returning
from any primary method returns from all of them.  (Because
media-types are basically disjoint, it doesn't really make sense to
have CALL-NEXT-METHOD return).

accept-specializer.lisp

index f8d55638432ac53f2acfd454b6290ce6aa41613c..97311c51fa7404b8cec01789d03fbf6d8a6c3d3e 100644 (file)
                    (let ((request-specializer (car (sb-mop:method-specializers ,method))))
                      (when (typep request-specializer 'accept-specializer)
                        (setf *actual-content-type* (media-type request-specializer))))
-                   (call-method ,method ,@(and nexts `((,(transform nexts)))))))))
+                   (throw 'content-negotiation (call-method ,method ,@(and nexts `((,(transform nexts))))))))))
            (wrap (form)
              `(let ((*actual-content-type*))
                 (multiple-value-prog1
     (let ((form (if (or before after (rest primary))
                     `(multiple-value-prog1
                          (progn ,@(call-methods before)
-                                (call-method ,(transform primary)))
+                                (catch 'content-negotiation (call-method ,(transform primary))))
                        ,@(call-methods (reverse after)))
-                    `(call-method ,(transform primary)))))
+                    `(catch 'content-negotiation (call-method ,(transform primary))))))
       (if around
           (wrap `(call-method ,(first around)
                               (,@(rest around) (make-method ,form))))
 (defmethod respond list ((s (accept "audio/mp3")))
   "audio/mp3")
 
+(defgeneric cn-test (request)
+  (:generic-function-class accept-generic-function)
+  (:method-combination content-negotiation))
+(defmethod cn-test ((request (accept "text/html")))
+  'html)
+(defmethod cn-test ((request (accept "text/plain")))
+  'plain)
+(defmethod cn-test ((request (accept "image/webp")))
+  'webp)
+(defmethod cn-test ((request (accept "audio/mp3")))
+  (call-next-method)
+  'mp3)
+(defmethod cn-test :after (request)
+  (print 'after))