5.1.3 Argument Conversion Protocol

The next protocol we need to implement is the so-called argument conversion protocol. This protocol is used to convert option arguments (that is, strings) to an actual value of the proper type. Arguments going through this protocol come from the command-line, the value of an environment variable or a debugger restart (see Error Management in The Clon End-User Manual). Also, note that Clon assumes that you implement this protocol correctly, so no value check is performed on values coming from the conversion of an argument.

The conversion protocol is implemented through a convert generic function for which you must provide a method.

Generic Function: convert OPTION ARGUMENT

Convert ARGUMENT to OPTION’s value. If ARGUMENT is invalid, raise an invalid-argument 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 the conversion of ARGUMENT to the appropriate type if it is valid, and raise an invalid-argument error otherwise.

The invalid-argument error condition is defined like this:

(define-condition invalid-argument (option-error)
  ((argument :documentation "The invalid argument."
             :type string
             :initarg :argument
             :reader argument)
   (comment :documentation "An additional comment about the error."
            :type string
            :initarg :comment
            :reader comment))
  (:report (lambda (error stream)
             (format stream "Option ~A: invalid argument ~S.~@[~%~A~]"
               (option error) (argument error) (comment error))))
  (:documentation "An invalid argument error."))

When the error is raised, you must fill in the argument and comment slots appropriately. As before, 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 convert ((enum enum) argument)
  "Convert ARGUMENT to an ENUM value."
  (or (closest-match argument (enum enum) :ignore-case t :key #'symbol-name)
      (error 'invalid-argument
             :option enum
             :argument argument
             :comment (format nil "Valid arguments are: ~A."
                        (list-to-string (enum enum)
                                        :key (lambda (value)
                                               (stringify enum value)))))))

Since enumerations allow their arguments to be abbreviated, a utility function named closest-match is used to find the closest match between an argument and the possible values. Otherwise, an invalid-argument error is raised. For an explanation of stringify, See Value Stringification Protocol.