Created
June 16, 2019 20:29
-
-
Save metametadata/2936244374fbd11d3f62b62490591b1b to your computer and use it in GitHub Desktop.
Multimethod helpers
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 multi-plus.core) | |
(defn multimethod-map | |
"Converts multimethod into a map. :default dispatch value will be omitted. | |
Expected multimethod signature: (defmulti mm (fn [v] v)). It should be pure." | |
[mm] | |
(into {} | |
(for [[dispatch-value method] (methods mm) | |
:when (not= dispatch-value :default)] | |
[dispatch-value (method dispatch-value)]))) | |
(defmacro with-method | |
"Temporarily adds multimethods for multifn. dispatch-map = {dispatch-val method}." | |
[multifn dispatch-map & body] | |
`(let [; Eager "evaluation" of arg is needed because it may contain side effects. | |
; E.g. for case when `(f/fake ...)` is passed in, clj-fakes self-tests will fail more times than expected. | |
evaluated-dispatch-map# ~dispatch-map] | |
; Race condition detection | |
(doseq [dispatch-val# (keys evaluated-dispatch-map#)] | |
(assert (not (contains? (methods ~multifn) dispatch-val#)) | |
(str "with-method cannot add a method because there's already a method defined for dispatch-val " | |
(pr-str dispatch-val#)))) | |
(try | |
(doseq [[dispatch-val# method#] evaluated-dispatch-map#] | |
(let [evaluated-method# method#] | |
(defmethod ~multifn dispatch-val# | |
[& args#] | |
(apply evaluated-method# args#)))) | |
~@body | |
(finally | |
(doseq [dispatch-val# (keys evaluated-dispatch-map#)] | |
(remove-method ~multifn dispatch-val#)))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment