(in-package :fwoar.rss-reader) (defgeneric app (obj) (:documentation "the ningle app that is to be run")) (defgeneric handler (obj) (:documentation "the clack handler representing the currently running application")) (defclass+ rss-reader () ((%feeds :initarg :feeds :accessor feeds) (%app :initform (make-instance 'ningle:) :reader app) (%handler :accessor handler)) (:documentation "A simple wrapper that ties a ningle app to a clack handler")) (defgeneric add-feed (feed reader) (:method :around (_ reader) (call-next-method) reader) (:method ((feed feed-reference) (reader rss-reader)) (push feed (feeds reader)))) (defun redirect (target) (lambda (_) (declare (ignore _)) `(302 (:location ,target) ()))) (defmethod araneus:routes progn ((app rss-reader)) (araneus:defroutes (app app) (("/") (redirect (format nil "/f/~(~a~)" (feed-key (car (feeds app)))))) (("/f/:feed") (lambda (params) (optima:match params ((optima.extra:alist (:feed . feed)) (araneus:run-route (feed-page (feeds app) (find feed (feeds app) :key 'feed-key :test 'string-equal)) params))))) (("/f/:feed/:item") (lambda (params) (optima:match params ((optima.extra:alist (:feed . feed) (:item . item)) (araneus:run-route (feed-item-page (feeds app) (find feed (feeds app) :key 'feed-key :test 'string-equal) item) params))))))) (defun start (app) (prog1 app (setf (handler app) (clack:clackup (app app))))) (defvar *app*) (defun unboundp (symbol) (not (boundp symbol))) (defun main () (setf *app* (if (not (boundp '*app*)) (start (araneus:routes (rss-reader (list (feed-reference :techcrunch "https://techcrunch.com/feed/") (plump-cleaner :coding-horror "http://feeds.feedburner.com/codinghorror") (feed-reference :daring-fireball "https://daringfireball.net/feeds/main"))))) (araneus:routes *app*))))