Created
January 27, 2017 08:28
-
-
Save luxbock/43e189db5e014a478820b19742319399 to your computer and use it in GitHub Desktop.
Handy helper for when it comes to playing around with :fn predicates at the REPL
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
(defn- get-fspec-attr | |
[sym attr] | |
(->> (s/form sym) | |
(rest) | |
(partition 2) | |
(keep (fn [[a b]] (when (= a attr) b))) | |
(first))) | |
(s/fdef conform-fn-call | |
:args (s/cat :fn-call (s/spec (s/cat :f symbol? :rs (s/* any?)))) | |
:ret (s/or :invalid s/invalid? | |
:conf-map (s/keys :req-un [::args ::ret]))) | |
(defmacro conform-fn-call | |
"Evaluates `form` and conforms its arguments and return value based | |
on the fspec of `f`, i.e. the return value is in the same shape as | |
what the specs/predicates of `:fn` expect." | |
[[f & args :as form]] | |
(let [f-res (-> f resolve str (subs 2) symbol) | |
ret (eval form) | |
args-spec (get-fspec-attr f-res :args) | |
ret-spec (get-fspec-attr f-res :ret) | |
args-conf (when args-spec `(s/conform ~args-spec ~(vec args))) | |
ret-conf (when ret-spec `(s/conform ~ret-spec ~ret))] | |
`(let [args# ~args-conf | |
ret# ~ret-conf] | |
(if (or (s/invalid? args#) (s/invalid? ret#)) | |
::s/invalid | |
{:args (or args# ~(vec args)) | |
:ret (or ret# ~ret)})))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment