(defun unzip-symbol-map (symbol-map) (loop for (symbol . string) in symbol-map collect symbol into symbols collect string into strings finally (return (list symbols strings)))) (defmacro posts-div ((&key params ids data-extractor symbol-map) &body body) (destructuring-bind (symbols strings) (unzip-symbol-map symbol-map) `(labels ((get-full-url (x) x) (make-entry (id response) (let* ((post-data (jonathan:parse response :as :alist)) (values (mapcar (lambda (x) (funcall ,data-extractor x post-data)) ',strings))) (destructuring-bind ,symbols values (let ((post-url (get-full-url (format nil "posts/~a" id)))) (spinneret:with-html ,@body)))))) (spinneret:with-html (:div ,@params (dolist (id ,ids) (let ((response "{\"file_url\": \"aaa\", \"artist_name\": \"cccc\", \"id\": \"bbb\"}")) (make-entry id response)))))))) (posts-div (:params (:id "id" :class "class") :ids '(1 2 3) :data-extractor (lambda (v post-data) (cdr (assoc v post-data :test #'equalp))) :symbol-map ((file-url . "file_url") (artist-name . "artist_name") (post . "id"))) (let ((post-url (get-full-url (format nil "posts/~a" post)))) (:div :class "tile is-ancestor box" (:div :class "tile is-parent is-vertical box" (:div :class "tile is-child" (:p "Post : " (:a :href post post)) (:p "Post URL : " (:a :href post-url post-url))) (:article :class "title is-child" (:figure :class "image" (:img :src file-url)))))))