Open christophejunke opened 9 months ago
Usage example for completeness:
CL-USER> (use-package :yaml.parser.extensions)
T
CL-USER> (defstruct (tag (:constructor make-tag (name value))) name value)
TAG
CL-USER> (let ((*yaml-tag-converter* #'make-tag))
(yaml:parse "!id 123456"))
#S(TAG :NAME "!id" :VALUE "123456")
More realistic example:
(defpackage :example.tags (:use) (:export #:uri #:date #:vec))
(defpackage :example (:use :cl :example.tags))
(in-package :example)
(defun intern-tag (name)
(assert (char= #\! (char name 0)))
(or (find-symbol (string-upcase (subseq name 1))
(load-time-value (find-package :example.tags)))
(error "Unknown tag ~s" name)))
(defgeneric convert (tag value)
(:method ((tag string) value)
(restart-case (convert (intern-tag tag) value)
(use-value (other) :report "Use alternative value" other)
(ignore () :report "Use untagged value" value))))
(defmethod convert ((_ (eql 'uri)) (s string))
(quri:uri s))
(defmethod convert ((_ (eql 'date)) (s string))
(local-time:parse-rfc3339-timestring s))
(defmethod convert ((_ (eql 'vec)) (v sequence))
(coerce v 'vector))
(let ((yaml.parser.extensions:*yaml-tag-converter* #'convert))
(yaml:parse "!vec [!uri https://example.com, !date 1937-01-01T12:00:27.87+00:20]"))
#(#<QURI.URI.HTTP:URI-HTTPS https://example.com> @1937-01-01T11:40:27.870000Z)
The code looks fine, but I feel like this project (which I have not maintained in years, and I have no interesting in maintaining CL projects) should be forked by someone who wants to fix the bugs/extend the features, and the Quicklisp distribution updated.
I can manage to find some time each month to maintain it if you want.
How does xach/quicklisp know which version to take? is it the master branch? Is there anything else I need to know?
Thanks
How does xach/quicklisp know which version to take? is it the master branch? Is there anything else I need to know?
I believe just raising an issue in the repo: https://github.com/quicklisp/quicklisp-projects
Add a new package
yaml.parser.extensions
that exports a new special variable*yaml-tag-converter*
, to use as a generic tag converter in case the tag is not already registered in conversion tables.I need to handle tags but the existing mechanism is not very satisfactory to me: I'm writing a library on top of cl-yaml and would prefer not to make global changes to hashtables (for an application this would not be a problem but a library should try to avoid doing that). There is no unregistration or scoped registration mechanism. I could temporarily rebind the tables but the symbols are not exported. Less importantly I do not care in my case if the tag is applied to a scalar, a sequence or a mapping, so I find it easier to rely on a special variable bound to a function that works on all tags (possibly dispatching on the type of value).
I believe this change to be reasonably backward-compatible, given that I do not change the set of exported symbols of existing packages. There is a new package named
yaml.parser.extensions
which could break user code if some user also defines the same package, which is unlikely. Also the behavior is the same as before as long as the special variable is NIL. When it is non-NIL, the existing conversion tables are prioritary.