This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-05-21
Channels
- # calva (11)
- # cider (4)
- # clojure (15)
- # clojure-europe (20)
- # clojurescript (14)
- # clr (45)
- # conjure (2)
- # cursive (1)
- # fulcro (10)
- # helix (4)
- # honeysql (7)
- # hoplon (21)
- # humbleui (2)
- # hyperfiddle (23)
- # introduce-yourself (1)
- # malli (11)
- # matrix (3)
- # off-topic (6)
- # pathom (2)
- # practicalli (1)
- # re-frame (9)
- # releases (1)
- # specter (2)
- # sql (10)
- # xtdb (2)
Hey, I’m using function schemas and I’m wondering if it’s possible to include function name and schema name in the instrumentation error?
When you provide a custom report function to instrument!
, the function name will be included.
The schema is included by default.
Adding to the power
example at https://github.com/metosin/malli/blob/master/docs/function-schemas.md#defn-instrumentation:
(mi/instrument! {:report m/-fail!})
..instrumented #'dev/power
=> nil
(power 6)
Execution error (ExceptionInfo) at malli.core/-exception (core.cljc:138).
:malli.core/invalid-output
(ex-data *e)
=>
{:type :malli.core/invalid-output,
:message :malli.core/invalid-output,
:data {:output [:int {:max 6}], :value 36, :args [6], :schema [:=> [:cat :int] [:int {:max 6}]], :fn-name dev/power}}
Can it also return the schema name?
If you mean that in
(def my-schema [:map [:a int?]])
the my-schema
symbol names the schema, then no.
Schemas are just data (unless you have already called m/schema
on it), so the don't know the var that was used to store them.
You can, however, attach arbitrary data to a schema and it will be reported as well:
(m/explain [:map {::schema-name "An int under :a"} [:a int?]] {:a ""})
=>
{:schema [:map #:dev{:schema-name "An int under :a"} [:a int?]],
:value {:a ""},
:errors ({:path [:a], :in [:a], :schema int?, :value ""})}
It's mentioned in the documentation here https://github.com/metosin/malli#validation in the code block under "Schemas can have properties".
I did a little experiment to make a little pattern matching macro that works with malli multi-schemas. source in 🧵 Any thoughts?
(defmacro match-maker
"Return a function that takes 2 things:
a malli multi schema M,
pairs of multi schema dispatch values -> functions
And returns a function, that when given a value that adheres to the
multischema M, calls the dispatch function and calls the right value on it.
"
[schema & efp]
`(let [_# (#'clojure.core/assert-args (even? (count '~efp)) "an even number of forms in evp vector")
enum->fn-pairs# (mapv vec (partition 2 '~efp))
children# (m/children ~schema)
expected-branches# (mapv first children#)
found-branches# (mapv first enum->fn-pairs#)
dispatch-val->f# (into {} (eval enum->fn-pairs#))
dispatch-fn# (-> ~schema m/properties :dispatch)]
(when (not= expected-branches# found-branches#)
(throw (ex-info (str "Error: mismatched branches in match-maker."
"\nExpected: " (pr-str expected-branches#)
"\nReceived: " (pr-str found-branches#))
{:exptected expected-branches#
:found found-branches#})))
(fn [value#]
(let [branch# (dispatch-fn# value#)
branch-fn# (get dispatch-val->f# branch#)]
(branch-fn# value#)))))
;; Given a multi schema:
(def PetSchema
[:multi {:dispatch :type}
[:dog [:map [:good-dog? :boolean]]]
[:cat [:map [:temperment [:enum :nice :mean]]]]])
;; make a function that can dispatch on the keys
(def pet-noise
(match-maker PetSchema
:dog (fn [{:keys [good-dog?]}] (if good-dog? "good dog." "bad dog."))
:cat (fn [{:keys [temperment]}] (str "kitty is " (name temperment)))))
;; call the function
(mapv pet-noise
[{:type :dog :good-dog? true} {:type :dog :good-dog? false}
{:type :cat :temperment :nice} {:type :cat :temperment :mean}])
;; => ["good dog." "bad dog." "kitty is nice" "kitty is mean"]
update the schema with a new branch
(def PetSchema
[:multi {:dispatch :type}
[:dog [:map [:good-dog? :boolean]]]
[:cat [:map [:temperment [:enum :nice :mean]]]]
[:bird [:map]]])
And try to use match-maker on the updated schema, you’ll get an error because you didn’t handle :bird
!
(try (def pet-noise
(match-maker PetSchema
:dog (fn [{:keys [good-dog?]}] (if good-dog? "good dog." "bad dog."))
:cat (fn [{:keys [temperment]}] (str "kitty is " (name temperment)))))
(catch Exception e [(ex-message e) (ex-data e)]))
;; => ["Missing Branches.
;; Expected: [:dog :cat :bird]
;; Received: [:dog :cat]"
;; {:exptected [:dog :cat :bird], :found [:dog :cat]}]