Fork me on GitHub
#malli
<
2021-08-02
>
Ben Sless18:08:26

Is it integrated with kondo as well?

ikitommi19:08:59

malli.dev is, the red underline & bump are from kondo. The pretty printer is currently just for runtime errors.

🎉 2
ikitommi13:08:46

the error formatters use fipp, look like this:

(defmethod v/-format ::m/invalid-input [_ _ {:keys [args input]} printer]
  {:body
   [:group
    (-block "Invalid function arguments:" (v/-visit args printer) printer) :break :break
    (-block "Input Schema:" (v/-visit input printer) printer) :break :break
    (-block "Errors:" (-errors input args printer) printer) :break :break
    (-block "More information:" (v/-color :link "" printer) printer)]})

ikitommi13:08:01

there will be pretty/reporter to just prints the errors and pretty/thrower to throw ’em.

Noah Bogart13:08:20

that looks great

Noah Bogart13:08:36

is there a better idiom for this?

(defn Step? [step]
  (if (m/validate Step step)
    step
    (throw (Exception.
             (->> step
                  (m/explain Step)
                  (me/humanize))))))

danielneal13:08:37

haha I literally wrote that exact function 5 mins ago and was wondering the same thing

2
🗃️ 2
ikitommi13:08:47

• you could create a validator & explainer before, if perf matters • I recommend throwing ex-imfo with :type , easier to catalog the errors • humanize can fail in some corner cases, should be robust, fixes welcome • there could be a helper for this in the future in malli, using m/-fail! which works well with the upcoming pretty printer

👍 2
ikitommi14:08:16

Malli internal errors just throw the minimum set of data (to be fast), to be post-processed when rendering the error. e.g. explain and humanize are pure, can be done on rendering, if the value & schema are present at ex-data. Might not be relevant on actual projects.

ikitommi14:08:05

I haven't heard of a robust way to override the repl default exception handler (from the repl) - would allow pretty errors for all Clojure: just throw data and add custom renderers for all :types & exception classes

Noah Bogart14:08:05

so something like this?

(defn SimpleStep? [step]
  (if (validate-step @step)
    step
    (throw (ex-info "Step isn't valid" {:type (explain-step @step)}))))

Noah Bogart14:08:50

good point about the validator and explainer, thanks

Ben Sless18:08:31

I'm leaning towards this form:

(defn needs-a-good-name
  [s]
  (let [s (m/schema s)
        v (m/validator s)
        d (m/decoder s ,,,) ;; optional?
        e (m/explainer s)]
    (fn [x]
      (let [x (d x)]
        (if (v x)
          x
          (throw (ex-info "invalid something" (e x))))))))
More generally, you can pass two functions, on-success and on-fail, then you can decide if you want to throw or drop or invalid data

👏 3
Ben Sless18:08:12

Something like

(defn needs-a-good-name
  [s respond raise]
  (let [s (m/schema s)
        v (m/validator s)
        d (m/decoder s ,,,) ;; optional?
        e (m/explainer s)]
    (fn [x]
      (let [x (d x)]
        (if (v x)
          (respond x)
          (raise e x))))))

👏 3
greg11:08:16

I think these two examples could be posted somewhere

Ben Sless11:08:23

I'll clean it up a bit and PR it to the tips? Maybe we should add a cookbook

ikitommi19:08:10

coercer? did you mean (raise (e x))? Look good anyway 👍 👍 👍

Ben Sless20:08:56

coercer is probably good. Wasn't sure about passing the original value or just the report to raise