summaryrefslogtreecommitdiff
path: root/catbird/observer.scm
diff options
context:
space:
mode:
authorDavid Thompson <dthompson2@worcester.edu>2022-10-03 19:22:23 -0400
committerDavid Thompson <dthompson2@worcester.edu>2022-10-22 11:48:39 -0400
commit14464dee966fe415d4c8e1fb8b5205653b22003f (patch)
tree986a7b03a089a4545465901cadce4d671f3032c1 /catbird/observer.scm
parentdcf869ccd7ec9d33c937507fe96e9e09f517bded (diff)
Add prototype catbird modules.
Diffstat (limited to 'catbird/observer.scm')
-rw-r--r--catbird/observer.scm37
1 files changed, 37 insertions, 0 deletions
diff --git a/catbird/observer.scm b/catbird/observer.scm
new file mode 100644
index 0000000..0cf01c5
--- /dev/null
+++ b/catbird/observer.scm
@@ -0,0 +1,37 @@
+(define-module (catbird observer)
+ #:use-module (catbird config)
+ #:use-module (oop goops)
+ #:export (<observer>
+ on-change))
+
+;; This is a hack to deal with the fact that specializing GOOPS
+;; accessors does not compose with inheritance.
+;;
+;; See
+;; https://dthompson.us/issues-with-object-oriented-programming-in-guile.html
+;; for details.
+
+(define-class <observer-slot-class> (<catbird-metaclass>))
+
+(define-generic on-change)
+
+(define-method (observer-slot? (slot <slot>))
+ (get-keyword #:observe? (slot-definition-options slot)))
+
+(define-method (compute-setter-method (class <observer-slot-class>) slot)
+ (if (observer-slot? slot)
+ ;; Wrap the original setter procedure with a new procedure that
+ ;; calls the on-change method.
+ (make <method>
+ #:specializers (list class <top>)
+ #:procedure (let ((slot-name (slot-definition-name slot))
+ (proc (method-procedure (next-method))))
+ (lambda (obj new)
+ (let ((old (and (slot-bound? obj slot-name)
+ (slot-ref obj slot-name))))
+ (proc obj new)
+ (on-change obj slot-name old new)))))
+ (next-method)))
+
+(define-class <observer> ()
+ #:metaclass <observer-slot-class>)