|
237 | 237 |
|
238 | 238 | (def ^{:private true} spec-keys |
239 | 239 | [:id :short-opt :long-opt :required :desc :default :default-desc :default-fn |
240 | | - :parse-fn :assoc-fn :update-fn :multi :validate-fn :validate-msg :missing]) |
| 240 | + :parse-fn :assoc-fn :update-fn :multi :post-validation |
| 241 | + :validate-fn :validate-msg :missing]) |
241 | 242 |
|
242 | 243 | (defn- select-spec-keys |
243 | 244 | "Select only known spec entries from map and warn the user about unknown |
|
306 | 307 | :validate-msg [String] ; [\"Must be an IPv4 host\" |
307 | 308 | ; \"Must not be a multicast address\"] |
308 | 309 | ; can also be a function (of the invalid argument) |
| 310 | + :post-validation Boolean ; default false |
309 | 311 | :missing String ; \"server must be specified\" |
310 | 312 | } |
311 | 313 |
|
|
382 | 384 | (defn- parse-error [opt optarg msg] |
383 | 385 | (str "Error while parsing option " (pr-join opt optarg) ": " msg)) |
384 | 386 |
|
385 | | -(defn- validation-error [opt optarg msg] |
| 387 | +(defn- validation-error [value opt optarg msg] |
386 | 388 | (str "Failed to validate " (pr-join opt optarg) |
387 | | - (if msg (str ": " (if (string? msg) msg (msg optarg))) ""))) |
| 389 | + (if msg (str ": " (if (string? msg) msg (msg value))) ""))) |
388 | 390 |
|
389 | 391 | (defn- validate [value spec opt optarg] |
390 | 392 | (let [{:keys [validate-fn validate-msg]} spec] |
391 | 393 | (or (loop [[vfn & vfns] validate-fn [msg & msgs] validate-msg] |
392 | 394 | (when vfn |
393 | 395 | (if (try (vfn value) (catch #?(:clj Throwable :cljs :default) _)) |
394 | 396 | (recur vfns msgs) |
395 | | - [::error (validation-error opt optarg msg)]))) |
| 397 | + [::error (validation-error value opt optarg msg)]))) |
396 | 398 | [value nil]))) |
397 | 399 |
|
398 | 400 | (defn- parse-value [value spec opt optarg] |
|
403 | 405 | (catch #?(:clj Throwable :cljs :default) e |
404 | 406 | [nil (parse-error opt optarg (str e))])) |
405 | 407 | [value nil])] |
406 | | - (if error |
407 | | - [::error error] |
408 | | - (validate value spec opt optarg)))) |
| 408 | + (cond error |
| 409 | + [::error error] |
| 410 | + (:post-validation spec) |
| 411 | + [value nil] |
| 412 | + :else |
| 413 | + (validate value spec opt optarg)))) |
409 | 414 |
|
410 | 415 | (defn- neg-flag? [spec opt] |
411 | 416 | (and (:long-opt spec) |
|
452 | 457 | (or (find-spec specs :short-opt optarg) |
453 | 458 | (find-spec specs :long-opt optarg))) |
454 | 459 | [m ids (conj errors (missing-required-error opt (:required spec)))] |
455 | | - [(if-let [update-fn (:update-fn spec)] |
456 | | - (if (:multi spec) |
457 | | - (update m id update-fn value) |
458 | | - (update m id update-fn)) |
459 | | - ((:assoc-fn spec assoc) m id value)) |
460 | | - (conj ids id) |
461 | | - errors]) |
| 460 | + (let [m' (if-let [update-fn (:update-fn spec)] |
| 461 | + (if (:multi spec) |
| 462 | + (update m id update-fn value) |
| 463 | + (update m id update-fn)) |
| 464 | + ((:assoc-fn spec assoc) m id value))] |
| 465 | + (if (:post-validation spec) |
| 466 | + (let [[value error] (validate (get m' id) spec opt optarg)] |
| 467 | + (if (= value ::error) |
| 468 | + [m ids (conj errors error)] |
| 469 | + [m' (conj ids id) errors])) |
| 470 | + [m' (conj ids id) errors]))) |
462 | 471 | [m ids (conj errors error)])) |
463 | 472 | [m ids (conj errors (str "Unknown option: " (pr-str opt)))])) |
464 | 473 | [defaults [] []] tokens) |
|
0 commit comments