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 creation time and scrap the slugs altogether. Note that this will
require changes to how we sort `NUMERIC-INDEX`. 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 ### Finish up Basic Deploy
The deploy method has been simplified and a git-hook plugin added. 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) (defmethod initialize-instance :after ((object page) &key)
;; Expect all static-pages to be written in Markdown for now. ;; Expect all static-pages to be written in Markdown for now.
(with-accessors ((text content-text)) object (with-slots (url text) object
(setf text (render-text text :md)))) (setf url (make-pathname :defaults url)
text (render-text text :md))))
(defmethod render ((object page) &key next prev) (defmethod render ((object page) &key next prev)
;; For the time being, we'll re-use the normal post theme. ;; For the time being, we'll re-use the normal post theme.

View file

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

View file

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

View file

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

View file

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

View file

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