diff options
| author | ckonstanski <carlos.konstanski@olo.com> | 2021-05-30 21:55:33 -0600 |
|---|---|---|
| committer | ckonstanski <carlos.konstanski@olo.com> | 2021-05-30 21:55:33 -0600 |
| commit | d962df92112e30c723b6e9206a18060e340f7649 (patch) | |
| tree | 592e67da55e8d798f2074e2bdd635af511c9277e | |
initial commit
| -rw-r--r-- | org-ckons-serializable.asd | 37 | ||||
| -rw-r--r-- | src/generics.lisp | 16 | ||||
| -rw-r--r-- | src/package.lisp | 7 | ||||
| -rw-r--r-- | src/serializable.lisp | 38 |
4 files changed, 98 insertions, 0 deletions
diff --git a/org-ckons-serializable.asd b/org-ckons-serializable.asd new file mode 100644 index 0000000..071b560 --- /dev/null +++ b/org-ckons-serializable.asd @@ -0,0 +1,37 @@ +;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- +(declaim (optimize (speed 0) (safety 3) (debug 3))) + +(in-package :cl) + +(defpackage :org-ckons-serializable-system (:use :cl :asdf)) +(in-package :org-ckons-serializable-system) + +(defmacro do-defsystem (&key name version maintainer author description long-description depends-on components) + `(defsystem ,name + :name ,name + :version ,version + :maintainer ,maintainer + :author ,author + :description ,description + :long-description ,long-description + :depends-on ,(eval depends-on) + :components ,components)) + +(defparameter *quicklisp-packages* '()) +(defparameter *asdf-packages* '(org-ckons-core)) +(defparameter *all-packages* (append *quicklisp-packages* *asdf-packages*)) + +(loop for pkg in *quicklisp-packages* do + (ql:quickload (symbol-name pkg))) + +(do-defsystem :name "org-ckons-serializable" + :version "1" + :maintainer "Carlos Konstanski <me@ckons.org>" + :author "Carlos Konstanski <me@ckons.org>" + :description "org-ckons-serializable" + :long-description "org-ckons-serializable is a library which provides HTML rendering functionality and a drakma HTTP client wrapper." + :depends-on *all-packages* + :components ((:module src + :components ((:file "package") + (:file "generics" :depends-on ("package")) + (:file "serializable" :depends-on ("generics")))))) diff --git a/src/generics.lisp b/src/generics.lisp new file mode 100644 index 0000000..3c3bb8a --- /dev/null +++ b/src/generics.lisp @@ -0,0 +1,16 @@ +;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- +(declaim (optimize (speed 0) (safety 3) (debug 3))) + +(in-package :org-ckons-serializable) + +(defgeneric all-slots-value-list-no-nulls (serializable) + (:documentation "Returns all slots of `record' as an alist. Not + limited to field slots.")) + +(defgeneric all-slots-plist-no-nulls (serializable) + (:documentation "Returns all slots of `record' as a plist. Not +limited to field slots.")) + +(defgeneric serialize (serializable &key package-name) + (:documentation "Returns a string that, when read with +`read-from-string', will instantiate the `seializable' object.")) diff --git a/src/package.lisp b/src/package.lisp new file mode 100644 index 0000000..a7b0170 --- /dev/null +++ b/src/package.lisp @@ -0,0 +1,7 @@ +;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- +(declaim (optimize (speed 0) (safety 3) (debug 3))) + +(defpackage :org-ckons-serializable + (:use :cl)) + +(in-package :org-ckons-serializable) diff --git a/src/serializable.lisp b/src/serializable.lisp new file mode 100644 index 0000000..0de2d3c --- /dev/null +++ b/src/serializable.lisp @@ -0,0 +1,38 @@ +;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- +(declaim (optimize (speed 0) (safety 3) (debug 3))) + +(in-package :org-ckons-serializable) + +(defclass serializable () + () + (:documentation "Provides class serialization and deserialization.")) + +(defmacro with-all-slots-to-list (serializable &body body) + "Iterates over all the slots of `serializable' and builds an alist +based on those slots." + `(remove-if 'null (mapcar (lambda (slot) + ,@body) + (org-ckons-core::map-slot-names ,serializable)))) + +(defmethod all-slots-value-list-no-nulls ((serializable serializable)) + (with-all-slots-to-list serializable + (when (slot-value serializable slot) + `(,slot . ,(slot-value serializable slot))))) + +(defmethod all-slots-plist-no-nulls ((serializable serializable)) + (let ((slot-plist ())) + (loop for slot in (all-slots-value-list-no-nulls serializable) do + (setf slot-plist (append slot-plist `(,(intern (format nil "~a" (car slot)) :keyword) ,(cdr slot))))) + slot-plist)) + +(defmethod serialize ((serializable serializable) &key (package-name (package-name #.*package*))) + (let ((output (make-array '(0) :element-type 'character :fill-pointer 0 :adjustable t))) + (with-output-to-string (stream output) + (loop for field in (all-slots-plist-no-nulls serializable) do + (princ " " stream) + (prin1 field stream))) + (format nil "(make-instance '~a::~a~a)" (string-upcase package-name) (type-of serializable) output))) + +(defun deserialize (form) + "`form' is a string representation of a `make-instance' form." + (eval (read-from-string form))) |
