This question is really about my lack of understanding of restarts.
In the encoder for cl-json
there exists a tempting macro I would like to use
with-substitute-printed-representation-restart
But alas I do not quite understand how.
This
(cl-json::encode-json-plist (list :boo "boo" :foo "foo"))
returns
{"boo":"boo","foo":"foo"}
This
(cl-json::encode-json-plist (list :boo "boo" :foo (lambda (a b) (+ a b))))
signals an UNENCODABLE-VALUE-ERROR
I would like to restart from that point where cl-json finds the function and have it return something of my choosing when it runs into that adding lambda I included in the list.
(defun my-func ()
(handler-bind ((cl-json::UNENCODABLE-VALUE-ERROR
#'(lambda (e) (invoke-restart 'return-default))))
(myencode (list :boo "boo" :foo (lambda (a b) (+ a b))))
)
)
(defun myencode (alist)
(restart-case
(cl-json::encode-json-plist-to-string alist)
(return-default () :report "Just return a default could not do this string" "barf")
)
)
returns "barf"
I want it to return
{"boo":"boo","foo":"barf"}
How do I use that macro do to this? In other words I want the restart to happen where the error was thrown not where the error was caught. Can I do that?
I don't understand if the doc is wrong or if I am reading the code badly, but there should already be a restart available whenever an object cannot be encoded. If you redefined cl-json
default method for encode-json
as follows, then you have a restart.
(defmethod encode-json (anything &optional (stream *json-output*))
"If OBJECT is not handled by any specialized encoder signal an error
which the user can correct by choosing to encode the string which is
the printed representation of the OBJECT."
(with-substitute-printed-representation-restart (anything stream)
(unencodable-value-error anything 'encode-json)))
By the way you could redefine so that the restart accepts an argument, the string to print instead:
(defmethod encode-json (anything &optional (stream *json-output*))
"If OBJECT is not handled by any specialized encoder signal an error
which the user can correct by choosing to encode the string which is
the printed representation of the OBJECT."
(with-substitute-printed-representation-restart (anything stream)
(restart-case (unencodable-value-error anything 'encode-json)
(use-value (v)
:report "Use a different encoding"
(check-type v string)
(write v :stream stream :escape t)))))
For example:
CL-USER> (handler-bind
((json:unencodable-value-error
(lambda (err)
(declare (ignore err))
(invoke-restart 'use-value "UNKNOWN"))))
(json:encode-json
`(((foo . ,#'print) (bar . "baz")))))
[{"foo":"UNKNOWN","bar":"baz"}]
You may want to ask directly the author of the library