Use with-slots for initializers, readers only please!

This commit is contained in:
Brit Butler 2014-08-27 11:51:12 -04:00
parent ed886b57e7
commit ab34400307
7 changed files with 30 additions and 56 deletions

View file

@ -243,27 +243,6 @@ or other purposes. We should be able to build the paths at instance
creation time and scrap the slugs altogether. Note that this will
require changes to how we sort `NUMERIC-INDEX`.
### Immutable Data
Currently, most of our content classes (and the config class) have
*accessor* slots in addition to *reader* slots. There should be no
need for accessors as our data doesn't change after
initialization. They are computed from the git repo, dumped into
templates, and that's it. This is really a question of how we
initialize things. I settled on the current `load-content` scheme,
flawed as it is, because it is simple and lightweight.
Content files in the git repo have a file extension denoting the
content type, a header section with metadata and a text body. That
gets transformed into a `construct` call (and ultimately
`make-instance`) to the class matching the file extension, and a bunch
of initargs. We avoid code duplication for lots of unique
constructors, but we lose out some in error handling, separation of
interface and implementation, etc.
Keene's Object Oriented Programming in CL has good advice on this
situation, specifically on page 162, Separation of Initargs and Slot Names.
### Finish up Basic Deploy
The deploy method has been simplified and a git-hook plugin added.

View file

@ -20,8 +20,9 @@
(defmethod initialize-instance :after ((object page) &key)
;; Expect all static-pages to be written in Markdown for now.
(with-accessors ((text content-text)) object
(setf text (render-text text :md))))
(with-slots (url text) object
(setf url (make-pathname :defaults url)
text (render-text text :md))))
(defmethod render ((object page) &key next prev)
;; For the time being, we'll re-use the normal post theme.

View file

@ -31,16 +31,15 @@
;; Content Types
(defclass content ()
((file :initarg :file :reader content-file)
((url :initarg :url :reader page-url)
(date :initarg :date :reader content-date)
(path :initarg :path :accessor path-of)
(slug :initarg :slug :accessor slug-of)
(tags :initarg :tags :accessor content-tags)
(text :initarg :text :accessor content-text))
(:default-initargs :tags nil :date nil :slug nil))
(file :initarg :file :reader content-file)
(tags :initarg :tags :reader content-tags)
(text :initarg :text :reader content-text))
(:default-initargs :tags nil :date nil))
(defmethod initialize-instance :after ((object content) &key)
(with-accessors ((tags content-tags)) object
(with-slots (tags) object
(when (stringp tags)
(setf tags (mapcar #'make-tag (cl-ppcre:split "," tags))))))

View file

@ -26,18 +26,17 @@
;; Instance Methods
(defgeneric page-url (document)
(:documentation "The url to the DOCUMENT without the domain.")
(:method (document)
(let* ((class-name (class-name (class-of document)))
(route (get-route class-name)))
(if route
(format nil route (slug-of document))
(error "No routing method found for: ~A" class-name)))))
(:documentation "The relative URL to the DOCUMENT."))
(defmethod page-url :around ((document t))
(let* ((result (call-next-method))
(type (or (pathname-type result) (page-ext *config*))))
(make-pathname :type type :defaults result)))
(defun compute-url (document unique-id)
"Compute the relative URL for a DOCUMENT based on its UNIQUE-ID."
(let* ((class-name (class-name (class-of document)))
(route (get-route class-name)))
(unless route
(error "No routing method found for: ~A" class-name))
(let* ((result (format nil route unique-id))
(type (or (pathname-type result) (page-ext *config*))))
(make-pathname :type type :defaults result))))
(defgeneric render (document &key &allow-other-keys)
(:documentation "Render the given DOCUMENT to HTML."))

View file

@ -3,7 +3,7 @@
;;; Atom and RSS Feeds
(defclass feed (index)
((format :initform nil :initarg :format :accessor feed-format)))
((format :initform nil :initarg :format :reader feed-format)))
(defclass standard-feed (feed) ())

View file

@ -6,13 +6,13 @@
"The list of tags which content has been tagged with.")
(defclass index ()
((path :initarg :path :accessor path-of)
(slug :initarg :slug :reader slug-of)
(title :initarg :title :reader title-of)
((url :initarg :url :reader page-url)
(title :initarg :title :reader title-of)
(content :initarg :content :reader index-content)))
(defmethod initialize-instance :after ((object index) &key)
(setf (path-of object) (page-url object)))
(defmethod initialize-instance :after ((object index) &key slug)
(with-slots (url) object
(setf url (compute-url object slug))))
(defmethod render ((object index) &key prev next)
(funcall (theme-fn 'index) (list :tags (find-all 'tag-index)

View file

@ -1,18 +1,14 @@
(in-package :coleslaw)
(defclass post (content)
((title :initarg :title :reader title-of)
(author :initarg :author :accessor author-of)
(format :initarg :format :accessor post-format))
((title :initarg :title :reader title-of)
(author :initarg :author :reader author-of)
(format :initarg :format :reader post-format))
(:default-initargs :author nil))
(defmethod initialize-instance :after ((object post) &key)
(with-accessors ((title title-of)
(author author-of)
(format post-format)
(text content-text)) object
(setf (slug-of object) (slugify title)
(path-of object) (page-url object)
(with-slots (url title author format text) object
(setf url (compute-url object (slugify title))
format (make-keyword (string-upcase format))
text (render-text text format)
author (or author (author *config*)))))