r0man/validation-clj

hygenic defvalidator

Opened this issue · 1 comments

Any interest in making the defvalidator more hygenic? This also allows you to use functions created outside the scope of the macro for predicate and error fns.

(defmacro defvalidator
  [fn-name fn-doc args predicate-fn error-fn]
  `(defn ~fn-name ~fn-doc [attribute# ~@args & {:as options#}]
     (fn [record#]
       (let [value# (extract-value record# attribute#)]
         (if (and (or (nil? (:if options#)) ((:if options#) record#))
                  (or (nil? (:unless options#)) (not ((:unless options#) record#))))
           (if (~predicate-fn record# attribute# value#)
             record#
             (add-error-message-on record# attribute#
                                   (~error-fn record# attribute# value#)))
           record#)))))

; Examples
(defvalidator confirmation-of
  "Validates that the record's attribute is the same as the
confirmation attribute."
  []
  (fn [record attribute value]
    (= value ((confirmation-keyword attribute) record)))
  (constantly "doesn't match confirmation."))

(defvalidator is-email
  "Validates that the record's attribute is a valid email address."
  []
  #(email? %3)
  (constantly "is not a valid email address."))

yes, patch and working tests welcome