Last active
September 20, 2019 22:33
-
-
Save wobh/7b7d205ba80cdeb707b5c97096f856c7 to your computer and use it in GitHub Desktop.
Figured out `print-object :around`, per https://twitter.com/wobher/status/1144821786485432320
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defclass being () | |
((health :accessor health :initarg :health) | |
(injury :accessor injury :initarg :injury))) | |
(defmethod make-load-form ((being being) &optional environment) | |
(declare (ignore environment)) | |
`(make-instance ',(class-name (class-of being)) | |
:health ,(health being) | |
:injury ,(injury being))) | |
(defmethod print-object ((being being) stream) | |
(if *print-readably* | |
(multiple-value-bind (make-form setup-form) | |
(make-load-form being) | |
(format stream "~W~@[~&~W~]" make-form setup-form)) | |
(if *print-escape* | |
(print-unreadable-object (being stream :type t :identity t) | |
(format stream | |
(if *print-pretty* | |
"~<~@{~S ~S~^ ~@_~}~:>" | |
"~{~S ~S~^ ~}") | |
(cddr (make-load-form being)))) | |
(format stream | |
"~(~A~)" | |
(class-name (class-of being)))))) | |
(defclass hunter (being) | |
((quiver :accessor quiver :initarg :quiver)) | |
(:default-initargs | |
:quiver 5 | |
:health 2 | |
:injury 0)) | |
(defmethod make-load-form :around ((being hunter) &optional environment) | |
(declare (ignore environment)) | |
(append (call-next-method) | |
(list :quiver (quiver being)))) | |
(defmethod print-object :around ((being hunter) stream) | |
(cond ((null *print-escape*) | |
(format stream "A bold ") | |
(call-next-method) | |
(format stream ", keen of ear and eye")) | |
(t | |
(call-next-method)))) | |
(defclass wumpus (being) | |
((psyche :accessor psyche :initarg :psyche)) | |
(:default-initargs | |
:psyche :asleep | |
:health 3 | |
:injury 0)) | |
(defmethod make-load-form :around ((being wumpus) &optional environment) | |
(declare (ignore environment)) | |
(append (call-next-method) | |
(list :psyche (psyche being)))) | |
(defmethod print-object :around ((being wumpus) stream) | |
(cond ((null *print-escape*) | |
(format stream | |
"A ~A " | |
(ecase (psyche being) | |
(:asleep "sleeping") | |
(:enraged "raging"))) | |
(call-next-method)) | |
(t | |
(call-next-method)))) | |
;;;; Tests | |
(let* ((object (make-instance 'wumpus :health 3 :injury 1 :psyche :enraged)) | |
(subject (eval (read-from-string (write-to-string object :readably t))))) | |
(check-type subject wumpus) | |
(assert (= 3 (health subject))) | |
(assert (= 1 (injury subject))) | |
(assert (eql :enraged (psyche subject)))) | |
(let* ((object (make-instance 'hunter :quiver 1 :health 2 :injury 1)) | |
(subject (write-to-string object :escape t :pretty nil))) | |
(assert (= 2 (search "HUNTER" subject))) | |
(assert (search ":QUIVER 1" subject)) | |
(assert (search ":HEALTH 2" subject)) | |
(assert (search ":INJURY 1" subject))) | |
(let* ((object (make-instance 'wumpus)) | |
(subject (write-to-string object :escape nil))) | |
(assert (string= "A sleeping wumpus" | |
subject))) | |
(let* ((object (make-instance 'hunter)) | |
(subject (write-to-string object :escape nil))) | |
(assert (string= "A bold hunter, keen of ear and eye" | |
subject))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A few ideas I've been trying to explore in this gist, most of which have puzzled me for quite a while:
:around
methods effectively, especially for providing specialized contents forprint-unreadable-object
.print-object
methods that make appropriate uses of the Common Lisp print system, especially the print variables.On that last one, I had already thought about writing
properties
methods for extracting the key parameters formake-instance
, stuffing them intoprint-unreadable-object
s and writing a parser for that. I thought I would have to use a MOP library just to get at them. But then I stumbled onmake-load-form
, and I realized, for the price of a little extra object infrastructure, I could do it with a standard method. I cobbled up the demo model, and progressively refactored it. Thanks to everyone who suggested something.TODO: I could include some tests to specify my assumptions.TODO: A more thorough search for examples of solutions to these questions.
TODO:
*print-pretty*
format string could probably be prettier.