Now that we have our new option class, we need to implement the
so-called value check protocol. This protocol is used to make sure
that values provided for options of your new type actually comply with
the type in question. Values going through this protocol are fallback
values, default values, and values provided from a debugger restart
(see Error Management in The Clon End-User Manual). In the case of fallback and default
values (which, by the way, are provided by you, the Clon
user), the check is performed only once, when the option object is
created. Values provided from a debugger restart come from the
application end-user, and hence are checked every time.
The value check protocol is implemented through a check
generic
function for which you must provide a method.
Check that VALUE is valid for OPTION. If VALUE is
valid, return it. Otherwise, raise an invalid-value
error.
As you can see, you need to provide a method with the first argument
specialized to your new option type. This method must return VALUE
if it is okay, and raise an invalid-value
error otherwise.
Clon
maintains a hierarchy of error conditions. The
invalid-value
error condition is defined like this:
(define-condition invalid-value (option-error) ((value :documentation "The invalid value." :initarg :value :reader value) (comment :documentation "An additional comment about the error." :type string :initarg :comment :reader comment)) (:report (lambda (error stream) (format stream "Option ~A: invalid value ~S.~@[~%~A~]" (option error) (value error) (comment error)))) (:documentation "An invalid value error.")) |
When the error is raised, you must fill in the value
and
comment
slots appropriately.
The super-condition option-error
provides an additional
option
slot that you must also fill in when the error is raised.
Let’s look at the enumeration example now.
(defmethod check ((enum enum) value) "Check that VALUE is a valid ENUM." (unless (member value (enum enum)) (error 'invalid-value :option enum :value value :comment (format nil "Valid values are: ~A." (list-to-string (enum enum) :key #'prin1-to-string)))) value) |
This code should be self-explanatory. We check that the value we got
belongs to the enumeration. list-to-string
is a utility function
that will separate every element with comas in the resulting string.