nuke more cruft
[clinton/lisp-on-lines.git] / src / mewa.lisp
CommitLineData
5dea194e 1(in-package :lisp-on-lines)
13ebe12f 2
15bc66bd 3;;;; * Occurences
1d51a2ee 4;;;; Occurences can be thought of as the class of a description.
5;;;; Most of the occurence stuff is depreciated now.
15bc66bd 6
15bc66bd 7 "an occurence holds the attributes like a class holds slot-definitions.
1d51a2ee 8Attributes are the yetadata used to display, validate, and otherwise manipulate actual values stored in lisp objects."
15bc66bd
DC
9
10(defun find-or-create-occurence (name)
11 "Returns the occurence associated with this name."
1d51a2ee 12 (let ((description (find-description name)))
13 (if description
14 (class-of description)
15 (class-of (ensure-description name)))))
15bc66bd
DC
16
17(defun clear-occurence (occurence)
18 "removes all attributes from the occurence"
19 (setf (attribute-map occurence) (make-hash-table)))
20
21(defgeneric find-occurence (name)
bf12489a
DC
22 (:method (thing)
23 nil)
15bc66bd
DC
24 (:method ((name symbol))
25 (find-or-create-occurence name))
bf12489a 26 (:method ((instance standard-object))
1cc831d4 27 (multiple-value-bind (occ new?)
28 (find-or-create-occurence (class-name-of instance))
29 (if new?
30 (initialize-occurence-for-instance occ instance)
31 occ))))
32
33(defun list-attributes (occurence)
34 (let (res)
35 (maphash (lambda (k v)
36 (declare (ignore v))
37 (push k res))
38 (attribute-map occurence))
39 res))
15bc66bd
DC
40
41
1d51a2ee 42(defmethod make-attribute-using-slot-definition (slotd)
43 (make-attribute
44 :name (closer-mop:slot-definition-name slotd)
45 :type-spec (closer-mop:slot-definition-type slotd)
46 :type (first (remove-if (lambda (item)
47 (or
48 (eql item 'or)
49 (eql item 'null)
50 (eql item nil)))
51 (ensure-list (closer-mop:slot-definition-type slotd))))))
52
53(defmethod initialize-occurence-for-instance (occurence instance)
54 (let ((slots (closer-mop:class-slots (class-of instance))))
55 (dolist (s slots)
56 (let ((att (make-attribute-using-slot-definition s)))
57 (setf (find-attribute occurence (attribute-name att)) att)))
58 occurence))
59
60
61
62
63;;;; * Attributes
64
2b0fd9c8
DC
65(define-layered-class
66 attribute (description)
1cc831d4 67 ((attribute-name :layered-accessor attribute-name
2b0fd9c8
DC
68 :initarg :name
69 :initform (gensym "ATTRIBUTE-")
70 :special t)
71 (occurence :accessor occurence :initarg :occurence :initform nil)
0386c736 72 (label :initarg :label :layered-accessor label :initform nil :special t)))
2b0fd9c8 73
fb04c0a8 74
2b0fd9c8
DC
75(defmethod print-object ((self attribute) stream)
76 (print-unreadable-object (self stream :type t)
ebabbd23 77 (with-slots (attribute-name description-type) self
78 (format stream "~A ~A" description-type attribute-name))))
15bc66bd
DC
79
80(define-layered-class
2b0fd9c8
DC
81 standard-attribute (attribute)
82 ((setter :accessor setter :initarg :setter :special t :initform nil)
83 (getter :accessor getter :initarg :getter :special t :initform nil)
ebabbd23 84 (value :accessor value :initarg :value :special t)
1cc831d4 85 (slot-name :accessor slot-name :initarg :slot-name :special t :initform nil)
86 (typespec :accessor type-spec :initarg :type-spec :initform nil))
15bc66bd
DC
87 (:documentation "Attributes are used to display a part of a thing, such as a slot of an object, a text label, the car of a list, etc."))
88
fb04c0a8 89(define-layered-method label :around ((attribute standard-attribute))
1cc831d4 90 (or (call-next-method) (attribute-name attribute)))
fb04c0a8 91
6f63d3a4 92(defmacro defattribute (name supers slots &rest args)
0386c736 93 (let* (
94 (type-provided-p (second (assoc :type-name args)))
95 (type (or type-provided-p name))
2b0fd9c8
DC
96 (layer (or (second (assoc :in-layer args)) nil))
97 (properties (cdr (assoc :default-properties args)))
ebabbd23 98 (cargs (remove-if #'(lambda (key)
2b0fd9c8
DC
99 (or (eql key :type-name)
100 (eql key :default-properties)
101 (eql key :default-initargs)
102 (eql key :in-layer)))
103 args
104 :key #'car)))
105
6f63d3a4 106 `(progn
6f63d3a4 107 (define-layered-class
91f2ab7b 108 ;;;; TODO: fix the naive way of making sure s-a is a superclass
2b0fd9c8
DC
109 ;;;; Need some MOPey goodness.
110 ,name ,@ (when layer `(:in-layer ,layer)),(or supers '(standard-attribute))
111 ,(append slots (properties-as-slots properties))
112 #+ (or) ,@ (cdr cargs)
113 ,@cargs
114 (:default-initargs :properties (list ,@properties)
115 ,@ (cdr (assoc :default-initargs args))))
116
ebabbd23 117 ,(when (or
118 type-provided-p
119 (not (find-attribute-class-for-type name)))
120 `(defmethod find-attribute-class-for-type ((type (eql ',type)))
0386c736 121 ',name)))))
15bc66bd
DC
122
123(defun clear-attributes (name)
124 "removes all attributes from an occurance"
125 (clear-occurence (find-occurence name)))
126
6f63d3a4
DC
127(defmethod find-attribute-class-for-type (type)
128 nil)
129
ebabbd23 130(defun make-attribute (&rest args &key type &allow-other-keys)
2b0fd9c8
DC
131 (apply #'make-instance
132 (or (find-attribute-class-for-type type)
ebabbd23 133 'standard-attribute)
134 :properties args
2b0fd9c8 135 args))
6f63d3a4 136
1d51a2ee 137(defmethod ensure-attribute ((occurence description) &rest args &key name &allow-other-keys)
15bc66bd 138 "Creates an attribute in the given occurence"
2b0fd9c8 139 (let ((attribute (apply #'make-attribute :occurence occurence args)))
ebabbd23 140 (setf (find-attribute occurence name) attribute)))
141
142(defmethod find-attribute ((occurence null) name)
143 nil)
15bc66bd 144
1d51a2ee 145(defmethod find-attribute ((occurence description) name)
ebabbd23 146 (or (gethash name (attribute-map occurence))
147 (let* ((class (ignore-errors (find-class (name occurence))))
148 (class-direct-superclasses
149 (when class
150 (closer-mop:class-direct-superclasses
151 class))))
152 (when class-direct-superclasses
153 (let ((attribute
154 (find-attribute
155 (find-occurence (class-name
156 (car
157 class-direct-superclasses)))
158 name)))
159 attribute)))))
15bc66bd 160
1d51a2ee 161(defmethod find-all-attributes ((occurence description))
15bc66bd 162 (loop for att being the hash-values of (attribute-map occurence)
fb04c0a8 163 collect att))
15bc66bd 164
2b0fd9c8
DC
165(defmethod ensure-attribute (occurence-name &rest args &key name type &allow-other-keys)
166 (declare (ignore name type))
167 (apply #'ensure-attribute
15bc66bd 168 (find-occurence occurence-name)
2b0fd9c8 169 args))
15bc66bd
DC
170
171;;;; The following functions make up the public interface to the
172;;;; MEWA Attribute Occurence system.
173
174(defmethod find-all-attributes (occurence-name)
175 (find-all-attributes (find-occurence occurence-name)))
176
177(defmethod find-attribute (occurence-name attribute-name)
2b0fd9c8 178 "Return the ATTRIBUTE named by ATTRIBUTE-NAME in OCCURANCE-name"
15bc66bd
DC
179 (find-attribute (find-occurence occurence-name) attribute-name))
180
2b0fd9c8
DC
181(defmethod (setf find-attribute) ((attribute-spec list) occurence-name attribute-name)
182 "Create a new attribute in the occurence.
183ATTRIBUTE-SPEC: a list of (type name &rest initargs)"
184 (apply #'ensure-attribute occurence-name :name attribute-name :type (first attribute-spec) (rest attribute-spec)))
15bc66bd 185
ebabbd23 186(defmethod (setf find-attribute) ((attribute standard-attribute) occurence attribute-name)
187 "Create a new attribute in the occurence.
188ATTRIBUTE-SPEC: a list of (type name &rest initargs)"
189 (setf (gethash attribute-name (attribute-map occurence))
190 attribute))
191
192(defmethod (setf find-attribute) ((attribute null) occurence attribute-name)
193 "Create a new attribute in the occurence.
194ATTRIBUTE-SPEC: a list of (type name &rest initargs)"
195 (setf (gethash attribute-name (attribute-map occurence))
196 attribute))
197
2b0fd9c8
DC
198(defmethod find-attribute ((attribute-with-occurence attribute) attribute-name)
199 (find-attribute (occurence attribute-with-occurence) attribute-name))
579597e3 200
15bc66bd 201(defmethod set-attribute-properties ((occurence-name t) attribute properties)
1cc831d4 202 (setf (description-properties attribute) (plist-nunion
2b0fd9c8 203 properties
1cc831d4 204 (description-properties attribute)))
205 (loop for (initarg value) on (description-properties attribute)
2b0fd9c8
DC
206 by #'cddr
207 with map = (initargs.slot-names attribute)
208 do (let ((s-n (assoc-if #'(lambda (x) (member initarg x)) map)))
209
210 (if s-n
211 (progn
212 (setf (slot-value attribute
213 (cdr s-n))
214 value))
215 (warn "Cannot find initarg ~A in attribute ~S" initarg attribute)))
216 finally (return attribute)))
217
218(defmethod set-attribute (occurence-name attribute-name attribute-spec &key (inherit t))
219 "If inherit is T, sets the properties of the attribute only, unless the type has changed.
220otherwise, (setf find-attribute)"
221 (let ((att (find-attribute occurence-name attribute-name)))
222 (if (and att inherit (or (eql (car attribute-spec)
1cc831d4 223 (description-type att))
2b0fd9c8
DC
224 (eq (car attribute-spec) t)))
225 (set-attribute-properties occurence-name att (cdr attribute-spec))
226 (setf (find-attribute occurence-name attribute-name)
227 (cons (car attribute-spec)
228 (plist-nunion
229 (cdr attribute-spec)
1cc831d4 230 (when att (description-properties att))))))))
fc3e754f 231
15bc66bd 232(defmethod perform-define-attributes ((occurence-name t) attributes)
fc3e754f
DC
233 (loop for attribute in attributes
234 do (destructuring-bind (name type &rest args)
235 attribute
2b0fd9c8
DC
236 (cond ((not (null type))
237 ;;set the type as well
238 (set-attribute occurence-name name (cons type args)))))))
fc3e754f 239
15bc66bd 240(defmacro define-attributes (occurence-names &body attribute-definitions)
fc3e754f 241 `(progn
15bc66bd
DC
242 ,@(loop for occurence-name in occurence-names
243 collect `(perform-define-attributes (quote ,occurence-name) (quote ,attribute-definitions)))))
244
2b0fd9c8 245
1d51a2ee 246
15bc66bd 247
ebabbd23 248;;"Unused???"
15bc66bd 249(defmethod setter (attribute)
6f63d3a4 250 (warn "Setting ~A in ~A" attribute *context*)
1cc831d4 251 (let ((setter (getf (description-properties attribute) :setter))
252 (slot-name (getf (description-properties attribute) :slot-name)))
15bc66bd
DC
253 (cond (setter
254 setter)
255 (slot-name
256 #'(lambda (value object)
257 (setf (slot-value object slot-name) value)))
258 (t
259 #'(lambda (value object)
2b0fd9c8 260 (warn "Can't find anywere to set ~A in ~A using ~A" value object attribute))))))
15bc66bd 261
d5e996b3 262
6f63d3a4
DC
263(define-layered-function attribute-value (instance attribute)
264 (:documentation " Like SLOT-VALUE for instances, the base method calls GETTER."))
265
ebabbd23 266(defmethod attribute-slot-value (instance attribute)
7553e5e8 267 "Return (VALUES slot-value-or-nil existsp boundp
268
269If this attribute, in its current context, refers to a slot,
270we return slot-value-or nil either boundp or not."
ebabbd23 271 (let (existsp boundp slot-value-or-nil)
272 (cond
273 ((and (slot-boundp attribute 'slot-name) (slot-name attribute))
274 (when (slot-exists-p instance (slot-name attribute))
275 (setf existsp t)
276 (when (slot-boundp instance (slot-name attribute))
277 (setf boundp t
278 slot-value-or-nil (slot-value
279 instance
280 (slot-name attribute))))))
1cc831d4 281 ((and (slot-exists-p instance (attribute-name attribute)))
ebabbd23 282 (setf existsp t)
1cc831d4 283 (when (slot-boundp instance (attribute-name attribute))
ebabbd23 284 (setf boundp t
285 slot-value-or-nil (slot-value
286 instance
1cc831d4 287 (attribute-name attribute))))))
ebabbd23 288 (VALUES slot-value-or-nil existsp boundp)))
289
6f63d3a4 290(define-layered-method attribute-value (instance (attribute standard-attribute))
ebabbd23 291 "return the attribute value or NIL if it cannot be found"
292 (with-slots (getter value) attribute
293 (when (slot-boundp attribute 'value)
294 (setf getter (constantly value)))
295 (if (and (slot-boundp attribute 'getter) getter)
296 ;;;; call the getter
297 (funcall getter instance)
298 ;;;; or default to the attribute-slot-value
299 (attribute-slot-value instance attribute))))
6f63d3a4 300
a4e6154d 301(define-layered-function (setf attribute-value) (value instance attribute))
6f63d3a4 302
2b0fd9c8
DC
303(define-layered-method
304 (setf attribute-value) (value instance (attribute standard-attribute))
2b0fd9c8
DC
305 (with-slots (setter slot-name) attribute
306 (cond ((and (slot-boundp attribute 'setter) setter)
2b0fd9c8
DC
307 (funcall setter value instance))
308 ((and (slot-boundp attribute 'slot-name) slot-name)
309 (setf (slot-value instance slot-name) value))
1cc831d4 310 ((and (slot-exists-p instance (attribute-name attribute)))
311 (setf (slot-value instance (attribute-name attribute)) value))
2b0fd9c8
DC
312 (t
313 (error "Cannot set ~A in ~A" attribute instance)))))
d5e996b3
DC
314
315
a4e6154d 316
d5e996b3 317;;;; ** Default Attributes
fb04c0a8 318;;;; TODO: This is mosty an ugly hack and should be reworked.
319;;;;
d5e996b3
DC
320;;;; The default mewa class contains the types use as defaults.
321;;;; maps meta-model slot-types to slot-presentation
322
323(defvar *default-attributes-class-name* 'default)
324
15bc66bd
DC
325(defmacro with-default-attributes ((occurence-name) &body body)
326 `(let ((*default-attributes-class-name* ',occurence-name))
327 ,@body))
328
d5e996b3 329(define-attributes (default)
ebabbd23 330 (boolean boolean)
331 (string string)
332 (number currency)
333 (integer integer)
334 (currency currency)
335 (clsql:generalized-boolean boolean)
fb04c0a8 336 (foreign-key has-a))
d5e996b3 337
15bc66bd 338(defun attribute-to-definition (attribute)
1cc831d4 339 (nconc (list (attribute-name attribute)
340 (description-type attribute))
341 (description-properties attribute)))
d5e996b3 342
15bc66bd 343(defun find-default-presentation-attribute-definitions ()
fb04c0a8 344 nil)
345
d5e996b3 346(defun gen-ptype (type)
15bc66bd
DC
347 (let* ((type (if (consp type) (car type) type))
348 (possible-default (find-attribute *default-attributes-class-name* type))
349 (real-default (find-attribute 'default type)))
350 (cond
351 (possible-default
1cc831d4 352 (description-type possible-default))
15bc66bd 353 (real-default
1cc831d4 354 (description-type real-default))
15bc66bd 355 (t type))))
d5e996b3
DC
356
357(defun gen-presentation-slots (instance)
358 (mapcar #'(lambda (x) (gen-pslot (cadr x)
359 (string (car x))
360 (car x)))
361 (meta-model:list-slot-types instance)))
362
34e8e2d6 363
d5e996b3
DC
364(defun gen-pslot (type label slot-name)
365 (copy-list `(,(gen-ptype type)
366 :label ,label
367 :slot-name ,slot-name)))
368
233380f7 369;; This software is Copyright (c) Drew Crampsie, 2004-2005.