1
0
Fork
You've already forked goblins-utils
0
misc utilities for spritely goblins
  • Scheme 100%
2025年11月30日 01:07:57 +00:00
winter/goblins-utils fix a bunch of stuff and rename modules 2025年11月30日 01:07:57 +00:00
README.md fix a bunch of stuff and rename modules 2025年11月30日 01:07:57 +00:00

winter's goblins utils

some assorted utilities i wrote for use with spritely goblins!

(winter goblins-utils signals)

this lets you use a "signals and slots" mechanism in goblins, much like the one found in qt. in this case, the "signals" are events raised by an actor, and the "slots" are just regular invocations of any other actor. the only requirement for an actor to implement signals is that it provides a method 'connect-signal, which can be invoked like this:

(<- actor 'connect-signal signal params target slot)
;; for example:
(<- button 'connect-signal 'clicked '() form '('submit))
;; or:
(<- word-provider 'connect-signal 'word '(the-word)
 log '('notice "Got word ~a" the-word))

it also provides a convenient macro that makes the above invocation neater:

(connect-signal (button 'clicked)
 (form 'submit))
(connect-signal (word-provider 'word the-word)
 (log 'notice "Got word ~a" the-word))

for example, when the word-provider from above triggers the signal 'word with the argument "meow", it will invoke log as such: (run-$/<- log 'notice "Got word ~a" "meow")

to add support for signals to an actor, you can use call-with-signals:

(define (^test bcom)
 (call-with-signals
 (lambda (add-handler trigger-signal)
 (methods
 [connect-signal add-handler]
 ;; ... whatever other methods you want ...
 ;; here you can use (trigger-signal) to do just that:
 [(trigger-the-test some-arg)
 (trigger-signal 'test some-arg)]))))

or more conveniently using the macro methods-with-signals, which automatically defines the 'connect-signal method for you:

(define (^test bcom)
 (methods-with-signals trigger
 [(trigger-the-test some-arg)
 (trigger 'test some-arg)]))

(winter goblins-utils logger)

this provides some simple logging utility actors. most likely you just want to log messages in text format to some output port, in which case:

(define log (spawn ^logger (current-error-port)))
($ log 'info "some message, which can use formatting: ~a" 'yippee)
;;=> [timestamp] (info) some message, which can use formatting: yippee

in general, loggers are invoked as (log-level message-format . format-args). the available log levels, in increasing order of significance, are:

  • debug
  • notice
  • info
  • warning
  • error
  • fatal

when spawning a logger you can also provide a minimum log level like this: (spawn ^logger port level), e.g. (spawn ^logger (current-output-port) 'warning). then it will ignore any messages at a lower level.

you can also create sub-loggers that could be used inside individual subsystems or actors in your program to automatically make their messages more specific:

(define ctx-log (spawn ^context-logger log "the context"))
($ ctx-log 'info "hello from context logger")
;;=> [timestamp] (info) [the context] hello from context logger

these can also be nested (by making a context-logger and passing it another existing context-logger), in which case the contexts will show up next to each other, with the most specific on the right.

if you need to send your log messages somewhere other than a text output port, you can also use a generic-logger, which just passes them to a procedure:

(define pk-log (spawn ^generic-logger pk))
($ pk-log 'warning "hello! ~a" "yeah")
;; (warning () "hello! yeah")
(define ctx-pk-log (spawn ^context-logger pk-log "wow"))
($ ctx-pk-log 'info "this also works")
;; (info ("wow") "this also works")