(in-package :lisp-on-lines) (define-description description ()) (defgeneric find-description-class (name &optional errorp) (:method ((name (eql t)) &optional errorp) (declare (ignore errorp)) (find-class 'description t)) (:method ((name symbol) &optional errorp) (or (find-class (defining-description name) errorp) (find-description-class t))) (:method ((description description) &optional errorp) (declare (ignore errorp)) (class-of description))) (defun find-description (name) (slot-value (find-description-class name) 'instance)) (defun description-attributes (description) (closer-mop:class-slots (find-description-class description))) (define-layered-function attributes (description)) (define-layered-method attributes (description) (description-attributes description)) ;;;!-- TODO: This is a prime candidate for optimization (defun find-attribute (description attribute-name) (find attribute-name (description-attributes description) :key #'attribute-name)) (define-display ((description description)) (format *display* "~{~A~%~}" (mapcar (lambda (attribute) (with-output-to-string (*display*) (display-attribute attribute))) (attributes description)))) (define-layered-method description-of (object) (find-description 't)) (define-layered-method description-of ((symbol symbol)) (find-description 'symbol)) (define-description symbol () ((identity :label "Symbol:") (name :function #'symbol-name :label "Name:") (value :label "Value:" :function (lambda (symbol) (if (boundp symbol) (symbol-value symbol) ""))) (package :function #'symbol-package :label "Package:") (function :label "Function:" :function (lambda (symbol) (if (fboundp symbol) (symbol-function symbol) "")))))