93a579ec |
(in-package #:data-class)
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun get-channel-element (xml-dom el)
($ (inline xml-dom) el (text) (node))))
(defun element-name-from-symbol (sym)
(let* ((base (string-downcase sym))
(split (split-sequence:split-sequence #\~ base))
(capit (cons (car split) (map 'list #'nstring-capitalize (cdr split)))))
(apply #'concatenate 'string capit)))
(defmacro ensure-slot (sym &body or-else)
`(handler-case
,sym
(unbound-slot (c)
(declare (ignore c))
,@or-else)))
(defmacro lazy-load-slot (class-name doc-slot root-el name tag-name &key transform value)
`(defmethod ,name :before ((self ,class-name))
(with-slots (,name ,doc-slot) self
(ensure-slot ,name
(alet ,(or value
`(get-channel-element ,doc-slot
,(format nil "~a > ~a" root-el tag-name)))
,(if transform
`(setf ,name (when it (,transform it)))
`(setf ,name it)))))))
|
58a15352 |
(defgeneric %all-slots (self format))
(defun all-slots (self &optional format)
(%all-slots self format))
(defgeneric slot-tags (self))
(defun process-slots-for-data-class (slots)
|
5dc30073 |
(mapcar (fw.lu::destructuring-lambda ((slot tag . rest))
(let ((tag (etypecase tag
(symbol (string-downcase tag))
(string tag))))
(list* slot (make-keyword slot) tag rest)))
(fw.lu:ensure-mapping slots)))
|
58a15352 |
(deftest process-slots-for-data-class ()
(let ((tc-1 '(a))
(tc-2 '((a b)))
(tc-3 '((a "b")))
(tc-4 '((a b c)))
(tc-5 '((a "b" c)))
(tc-6 '((a "bC")))
(tc-7 '((a "bC" d))))
(should be equal '((a :a "a")) (process-slots-for-data-class tc-1))
(should be equal '((a :a "b")) (process-slots-for-data-class tc-2))
(should be equal '((a :a "b")) (process-slots-for-data-class tc-3))
(should be equal '((a :a "b" c)) (process-slots-for-data-class tc-4))
(should be equal '((a :a "b" c)) (process-slots-for-data-class tc-5))
(should be equal '((a :a "bC")) (process-slots-for-data-class tc-6))
(should be equal '((a :a "bC" d)) (process-slots-for-data-class tc-7))))
|
93a579ec |
(defmacro define-data-class (name (doc-slot root-el) (&rest superclasses) &body slots)
|
58a15352 |
(declare (optimize (debug 3)))
(flet ((make-slot-spec (slot slot-keyword)
`(,slot :initarg ,slot-keyword :accessor ,slot)))
(let ((slots (process-slots-for-data-class slots)))
`(progn
(defclass ,name ,superclasses
((slot-tags :allocation :class :initform
',(loop for (_ slot-keyword tag) in slots
collect (cons slot-keyword tag)))
,@(mapcar (fw.lu::destructuring-lambda ((slot slot-keyword . r))
(declare (ignore r))
(make-slot-spec slot slot-keyword))
slots)))
,@(loop for (slot _ tag-name . rest) in slots
collect `(lazy-load-slot ,name ,doc-slot ,root-el ,slot ,tag-name ,@rest))
(defmethod %all-slots ((self ,name) format)
|
aafdf70e |
(pairlis (list ,@(mapcar (fw.lu::alambda (cadr fw.lu::it)) slots))
|
58a15352 |
(list ,@(loop for (slot) in slots collect `(,slot self)))))))))
|