diff options
author | Colin Okay <okay@toyful.space> | 2021-05-13 21:50:52 -0500 |
---|---|---|
committer | Colin Okay <okay@toyful.space> | 2021-05-13 21:50:52 -0500 |
commit | f4a607f7efc457f7afe299b721487f348bbf7ace (patch) | |
tree | 19413a475c89c1eadf626e4f6682539301982067 | |
parent | 747acf957ef1542cee64298148ed2a4960408390 (diff) |
filling out
-rw-r--r-- | flexo.lisp | 147 |
1 files changed, 129 insertions, 18 deletions
@@ -2,27 +2,138 @@ (in-package #:flexo) -;;; CONTENT CLASSES +;;; CONTENT -(defclass content () ()) +(defvar *content* nil + "Dynamic hash-table, bound before building a site. All instances of + subclasses of content are automatically inserted into this index.") -(defclass local-file-content (content) +(defclass content () + ((keywords + :reader content-keywords + :initarg :keywords + :initform nil + :documentation "A list of content keywords that may be used to + look up this piece of content.")) + (:documentation + "The base class for all raw content. CONTENT instances represent + unprocessed, unadorned files, database queries, or any source of + content data that FLEXO can import and use to create and publish + site artifacts.")) + +(defmethod initialize-instance :after ((content content) &key) + (dolist (key (content-keywords content)) + (when *content* + (if (gethash key *content*) + (pushnew content (gethash key *content*)) + (setf (gethash key *content*) + (list content)))))) + +(defclass file (content) ((filepath - :reader local-filepath + :reader filepath :initarg :filepath - :initform (error "LOCAL-FILE-CONTENT must have a FILEPATH slot value.")))) - -(defclass plaintext-content (content) - ((encoding - :reader encoding - :initarg :encoding - :initform :utf8))) - -(defclass markdown-content (plaintext-content) ()) -(defclass org-content (plaintext-content) ()) -(defclass pdf-content (content) ()) -(defclass image-content (content) ()) -(defclass audio-content (content) ()) -(defclass video-content (content) ()) + :initform (error "FILE must have a FILEPATH slot value.")))) + +(defmethod initialize-instance :after ((content file) &key) + (when *content* + (setf (gethash (filepath content) *content*) + content))) + +(defun content-with-tags (&rest tags) + "Content utility function to locate all content with all of the + supplied keyword tags" + (when *content* + (let ((tagged (gethash (first tags) *content*))) + (dolist (tag (rest tags) tagged) + (setf tagged + (intersection tagged (gethash tag *content*))))))) + +(defun find-content (pred) + "Generic content query. PRED is a preedicate of one argument, and is + passed a CONTENT instance. Returns a list of instances for which + PRED returns non NIL." + (when *content* + (loop :for instance :being :the :hash-value :of *content* + :when (funcall pred instance) + :collect instance))) + +(defun lookup-content (key) + "Looks up KEY in *CONTENT*." + (when *content* + (gethash key *content*))) + +(defun content-with-filepath-like (regex) + "Returns all FILE content instances whose filepath matches the + supplied regular expression." + (find-content + (lambda (content) + (and (typep content 'file) + (ppcre:scan regex (namestring (filepath content))))))) + +;;; ARTIFACTS + +(defvar *artifacts* nil + "Dynamic hash-table, bound before building a site. A collection of + artifacts, indexed by the url path of the artifact.") + +(defun find-artifacts (pred) + "Generic artifact query. PRED is a preedicate of one argument, and is + passed an ARTIFACT instance. Returns a list of instances for which + PRED returns non NIL." + (when *artifacts* + (loop :for instance :being :the :hash-value :of *artifacts* + :when (funcall pred instance) + :collect instance))) + +(defun artifacts-with-class (class) + "Returns a list of instances of CLASS from the *ARTIFACT* store." + (find-artifacts + (lambda (artifact) (typep artifact class)))) + +(defun artifacts-with-urlpath-like (regex) + "Returns a list of instances of artifacts whose url path matches the + supplied regex." + (find-artifacts + (lambda (artifact) + (ppcre:scan regex (url-path artifact))))) + +(defclass artifact () + ((url + :accessor url-path + :initarg :url + :initform (error "An artifact needs a url") + :documentation "A URL path, relative to the site root, from where + this artifact is to be served.")) + (:documentation + "ARTIFACT instances represent what flexo publishes: i.e. pages and + files to be served from some web root.")) + +(defmethod initialize-instance :after ((artifact artifact) &key) + (when *artifacts* + (setf (gethash (url-path artifact) *site*) + artifact))) + +(defclass page (artifact) + ((html + :accessor page-html + :initarg :html + :initform (error "A PAGE must have some HTML") + :documentation + "A utf8 encoded string holding the html content of this page artifact."))) + +(defmacro page (url &body body) + "Creates a page instance with the given url path and expdning the +spinneret template in BODY." + `(make-instance + 'page + :url ,url + :html (with-html-string ,@body))) + +(defmacro define-page-template (template-name (url-arg &rest lambda-list-def) &body template-body) + "Defines a function that creates an instance of PAGE from a reusable template." + `(defun ,template-name (,url-arg ,@lambda-list-def) + (page ,url-arg + ,@template-body))) ;;; |