-
-
Save alexanderjamesking/5caca087e6243943419693d93f70437d to your computer and use it in GitHub Desktop.
An example of functional error handling in clojure.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns example.errors) | |
(defn clean-address [params] | |
"Ensure (params :address) is present" | |
(if (empty? (params :address)) | |
[nil "Please enter your address"] | |
[params nil])) | |
(defn clean-email [params] | |
"Ensure (params :email) matches *@*.*" | |
(if (and (params :email) (re-find #".*@.*\..*" (params :email))) | |
[params nil] | |
[nil "Please enter an email address"])) | |
(defn clean-phone [params] | |
"Ensure phone number matches (555) 555-5555" | |
(if (and (params :phone) (re-find #"\([0-9]{3}\) [0-9]{3}-[0-9]{4}" (params :phone))) | |
[params nil] | |
[nil "Please enter your phone number in (555) 555-5555 format."])) | |
(defn clean-state [params] | |
"Ensure state is one of OR or WA. Cascadians unite!" | |
(case (params :state) | |
"WA" [params nil] | |
"OR" [params nil] | |
[nil "We only want people from Oregon or Washington, for some reason."])) | |
; And our examples | |
(defn clean-contact-bad [params] | |
(let [[params err] (clean-email params) | |
[params err] (if (nil? err) (clean-address params) [nil err]) | |
[params err] (if (nil? err) (clean-phone params) [nil err]) | |
[params err] (if (nil? err) (clean-state params) [nil err])] | |
[params err])) | |
(defn apply-or-error [f [val err]] | |
(if (nil? err) | |
(f val) | |
[nil err])) | |
(defn clean-contact-ok [params] | |
(let [result (clean-email params) | |
result (apply-or-error clean-address result) | |
result (apply-or-error clean-phone result) | |
result (apply-or-error clean-state result)] | |
result)) | |
(defn clean-contact-good [params] | |
(->> (clean-email params) | |
(apply-or-error clean-address) | |
(apply-or-error clean-phone) | |
(apply-or-error clean-state))) | |
(defmacro err->> [val & fns] | |
(let [fns (for [f fns] `(apply-or-error ~f))] | |
`(->> [~val nil] | |
~@fns))) | |
(defn clean-contact [params] | |
(err->> params | |
clean-email | |
clean-address | |
clean-phone | |
clean-state)) | |
(comment | |
(use 'clojure.test) | |
(is (= (clean-address {}) | |
[nil "Please enter your address"])) | |
(is (= (clean-address {:address "123 Fake St."}) | |
[{:address "123 Fake St."} nil])) | |
(is (= (clean-email {:email "test"}) | |
[nil "Please enter an email address"])) | |
(is (= (clean-email {}) | |
[nil "Please enter an email address"])) | |
(is (= (clean-email {:email "[email protected]"}) | |
[{:email "[email protected]"} nil])) | |
(is (= (clean-phone {}) | |
[nil "Please enter your phone number in (555) 555-5555 format."])) | |
(is (= (clean-phone {:phone "1-800-555-1234"}) | |
[nil "Please enter your phone number in (555) 555-5555 format."])) | |
(is (= (clean-phone {:phone "(800) 555-1234"}) | |
[{:phone "(800) 555-1234"} nil])) | |
(is (= (clean-state {:state "CA"}) | |
[nil "We only want people from Oregon or Washington, for some reason."])) | |
(is (= (clean-state {:state "WA"}) | |
[{:state "WA"} nil])) | |
(is (= (clean-contact {}) | |
[nil "Please enter an email address"])) | |
(is (= (clean-contact {:email "[email protected]"}) | |
[nil "Please enter your address"])) | |
(is (= (clean-contact {:email "[email protected]" :address "123 Fake St."}) | |
[nil "Please enter your phone number in (555) 555-5555 format."])) | |
(is (= (clean-contact {:email "[email protected]" :address "123 Fake St." :phone "(800) 555-1234"}) | |
[nil "We only want people from Oregon or Washington, for some reason."])) | |
(is (= (clean-contact {:email "[email protected]" :address "123 Fake St." :phone "(800) 555-1234"}) | |
[nil "We only want people from Oregon or Washington, for some reason."])) | |
(is (= (clean-contact {:email "[email protected]" :address "123 Fake St." :phone "(800) 555-1234" :state "WA"}) | |
[{:email "[email protected]" :address "123 Fake St." :phone "(800) 555-1234" :state "WA"} nil])) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment