Christophe Weblog Wiki Code Publications Music
content-negotiation is better described using OR method-combination
authorChristophe Rhodes <csr21@cantab.net>
Sun, 13 Apr 2014 19:50:21 +0000 (20:50 +0100)
committerChristophe Rhodes <csr21@cantab.net>
Sun, 13 Apr 2014 19:50:21 +0000 (20:50 +0100)
accept-specializer.lisp

index 3dd7ce7b164f56b0aa9cd043f81cf447ec3d145b..c08f5373a18d19b49ec1c8db18bfe9eb04c89978 100644 (file)
           (wrap `(call-method ,(first around)
                               (,@(rest around) (make-method ,form))))
           (wrap form)))))
+(define-method-combination content-negotiation/or ()
+  ((around (:around))
+   (primary () :required t))
+  (:arguments request)
+  (labels ((transform/1 (method)
+             `(make-method
+               (progn
+                 (let ((s (car (sb-mop:method-specializers ,method))))
+                   (when (typep s 'accept-specializer)
+                     (setf *actual-content-type* (media-type s))))
+                 (call-method ,method))))
+           (transform (primaries)
+             (mapcar #'(lambda (x) `(call-method ,(transform/1 x)))
+                     primaries))
+           (wrap (form)
+             `(let ((*actual-content-type*))
+                (multiple-value-prog1
+                    ,form
+                  (handle-content-type ,request)))))
+    (let ((form (if (rest primary)
+                    `(or ,@(transform primary))
+                    `(call-method ,(transform/1 (car primary))))))
+      (if around
+          (wrap `(call-method ,(first around)
+                              (,@(rest around) (make-method ,form))))
+          (wrap form)))))
 
 (defmethod generalizer-of-using-class ((gf accept-generic-function) (s string))
   (make-instance 'accept-generalizer
   'mp3)
 (defmethod cn-test :after (request)
   (print 'after))
+
+(defgeneric cn/or-test (request)
+  (:generic-function-class accept-generic-function)
+  (:method-combination content-negotiation/or))
+
+(defmethod cn/or-test or ((request (accept "audio/mp3")))
+  'mp3)
+(defmethod cn/or-test or ((request (accept "image/webp")))
+  'webp)
+(defmethod cn/or-test :around ((request t))
+  (print :around)
+  (call-next-method))