Volkan YAZICI yazicivo@ttnet.net.tr writes:
Sorry, above assertion is mistaken. Hunchentoot returns T for boolean in all cases whenever auth-res exists in the GET parameters list. Therefore, it's not possible to make a distinction between a NIL (which means false) boolean parameter that is supplied and a parameter that isn't even supplied. (Please correct me if I'm wrong.)
To clarify what I try to mean, here's an example:
(define-easy-handler (auth :uri "/auth") ((result :parameter-type 'boolean :request-type :get)) (with-html (if result (htm (:p "Authentication succeeded.")) (htm (:p "Authentication failed!"))) (:p "Welcome!")))
Try this handler with "/auth?result=", "/auth?result=nil" URIs. In each case, RESULT will return T. So how can I tell /auth that I tried to authenticate the client but it's failed? (You may say that, just don't pass the `result' argument to URI. But that's not same as passing a boolean type of argument with NIL/FALSE value.)
Here is my suggestion for this:
<patch> --- /tmp/easy-handlers.lisp 2007-04-28 20:56:57.000000000 +0300 +++ easy-handlers.lisp 2007-04-28 20:51:29.000000000 +0300 @@ -52,7 +52,8 @@ (char argument 0))) (integer (ignore-errors (parse-integer argument :junk-allowed t))) (keyword (make-keyword argument :destructivep nil)) - (boolean t) + (boolean (not (or (string= argument "") + (string= (string-upcase argument) "NIL")))) (otherwise (funcall type argument))))
(defun compute-simple-parameter (parameter-name type parameter-reader) </patch>
And, after that long discussion, I solved my problem again on my own:
(defmacro with-form-fields ((&key (default-parameter-type ''string) (default-request-type :both)) (&rest fields) &body body) "Process specified lambda list similar to DEFINE-EASY-HANDLER. You can also use :EXISTS-P keyword to specify an extra parameter to ensure that the value is supplied in the request URI." `(let ;; Collect appropriate LET bindings for supplied fields. ,(nconc (loop for field in fields collect (hunchentoot::make-defun-parameter (if (listp field) (cons (first field) (delf (rest field) :exists-p)) field) default-parameter-type default-request-type)) ;; Collect :exists-p keyword variables. (loop for field in fields when (and (listp field) (getf (rest field) :exists-p)) collect (getf (rest field) :exists-p))) ;; Process :exists-p keywords. ,(with-gensyms (get-params post-params both-params) `(let* ((,get-params (get-parameters)) (,post-params (post-parameters)) (,both-params (nconc ,get-params ,post-params))) (declare (ignorable ,get-params)) (declare (ignorable ,post-params)) (declare (ignorable ,both-params)) ,@(loop for field in fields when (and (listp field) (getf (rest field) :exists-p)) collect `(setq ,(getf (rest field) :exists-p) (if (rest (assoc (string-downcase (symbol-name (quote ,(first field)))) ,(ecase (or (getf (rest field) :request-type) default-request-type) (:get get-params) (:post post-params) (:both both-params)) :test #'string=)) t))))) ,@body))
Try to run above same handler example with below code.
(with-form-fields () ((result :parameter-type 'boolean :request-type :get :exists-p result-exists-p)) (with-html (when (and result-exists-p (not result)) (htm (:p "Authentication failed!"))) (when result (htm (:p "Authentication succeeded."))) (:p "Welcome!")))
Excuse me if I disturb you with my own problems. Looks like everyone is comfortable with undetermined boolean values.
Regards.