Fork me on GitHub

Cross-posting from #announcements : Announcing org.passen/malapropism. A small library for configuration data backed by malli

🎉 1
Alexander Moskvichev04:06:16

Is there an easy way to change default date format in malli.transofm? I've read several discussions about custom registry, etc, but just started with malli, it's too hard for now to understand. I use malli with reitit, just need to change outgoing date format


Does malli support custom function predicates? I noticed some functions seem to be supported but most of them give an "invalid schema" error and I don't know if there's another way of doing this


actually, what I need is define a schema for a map that contains a core.async channel. I can always use :any but it would've been nice to use something like #(instance? ManyToManyChannel %)


Also, unrelated question 😄 I'm pretty curious about this: In particular, in this snippet:

(defn plus1
  "Adds one to the number"
  {:malli/schema [:=> [:cat :int] :int]}
  [x] (inc x))
What's this way of using metadata to define the schema of the function via defn? Is this a defn-like macro defined somewhere?


@jsanchezf if I understand, it's the normal Clojure defn and that's the attr-map? argument which becomes metadata


@craigy But then, how does it work? Malli has no way of knowing when a function is redefined. Simply defining some metadata does not lead to instrumentation happening


(dev/start! {:report (pretty/reporter)})
check the source of that call for the answer 🙂


> Without instrumentation turned on, there is no schema enforcement:


> defn schemas can be defined with standard Var metadata. It allows defn schema documentation and instrumentation without dependencies to malli itself from the functions. It's just data.


I see, so looking at the source ( it walks all the namespaces at the time where you call dev/start! , then looks for instrumented functions. But how will it know when I create a new function or define a new namespace? Do I need to call start! again for it to pick it up?


yes, you need to call start! again when you annotate new functions. Tried to hook Var-watching for already defined schematized defns, but the Clojure core doesn’t support that easily. Calling start! makes the collecting explicit.


I’m using malli to instrument functions and print results using the pretty printer. Some functions accept and return huge maps, so huge that it makes the output of the pretty printer unusable. Any hints on how to improve this?

👍 2
eskos06:06:17 can make pretty prints even more prettier; sometimes just adding color helps a lot • (or can be used to diff the content; with a bit of trickery you can print only the interesting parts


@U8SFC8HLP Puget in nice, but Malli uses a custom pretty printer directly on top of fipp - different opinions about colors & works with CLJS too. About the huge maps, currently there is no omitting of valid values (, would have needed that too, but have had no time to implement. PR would be welcome on this. Also, I think it’s the final piece before extracting the pretty printing from reitit & malli into a clean and minimal lib (


I think showing valid values is useful to get the full picture. It also makes the report easier to parse sometimes. If there are 4 args to the fn, and 1 is wrong, it can be easier on the eyes to navigate to the wrong one when you use the valid ones as guides.


ok, I’m all ears on how to make it better then.


In my case, I have a re-frame app-db. The number of keys in the map is not huge, but the number of nested keys is. So some way of sniffing out the approximate size of the map and deciding to print the first 500 chars or something would be nice. That was what I was looking for in my question. Would be nice if fipp had that option.


From reading the code, it looks like we just pass the map to fipp for printing?


but virhe isn’t currently used in malli, is it? I suppose maybe I can use it to implement an alternative to the default pretty printer?


virhe is… inlined 🙂

  "initial code for "


so… what I’m asking for is already available?


actual virhe-repo is just a README, “copy code here when it’s ok”


you can either swap the EDNPrinter or pass options to it to work differently


all code is in malli repo.


awesome, thanks! I just didn’t notice that part of the API. Will have a go at this 🙂


In case it’s useful for anyone, here’s the change I needed. I wanted to avoid printing the re-frame app-db. Both because the contents are usually not interesting, and because it’s way too large to be printed effectively. In the case of a value not matching the schema of our app db, it would usually be something that does not match the check here so it would be printed anyway.

(extend-type v/EdnPrinter
  (visit-map [this x]
    (if (:some-key-always-in-our-db x)
      ;; Avoid printing app db to console, as it is way too large
      (v/-color :text "{... app db ...}" x)
      ;; Inlining original implementation from EdnPrinter
      (let [xs (sort-by identity (fn [a b] (arr/rank (first a) (first b))) x)]
        (fe/pretty-coll this (v/-color :text "{" this) xs [:span (v/-color :text "," this) :line] (v/-color :text "}" this)
                        (fn [printer [k v]]
                          [:span (fv/visit printer k) " " (fv/visit printer v)]))))))

👍 3

Sadly, the same cannot be applied to the CLJ side because the .virhe.EdnPrinter record type directly implements the fipp.visit/IVisitor protocol-generated interface & extend-type doesn’t allow reimplementations when that is the case. eg.

(defprotocol MyProto
  (action [this]))
(defrecord MyRecord []
  (action [this]  this))
(extend-type MyRecord
  (action [this] ::NEW))
;; Execution error (IllegalArgumentException) at user/eval651681 (...)
;; class user.MyRecord already directly implements user.MyProto for protocol:#'user/MyProto
I don’t see much of a way around this other than reimplementing the printer and ensuring that gets passed along through whatever printing call chain of interests. 😞


maybe #portal?