malli

https://github.com/metosin/malli :malli:
rutledgepaulv 2020-11-23T03:58:29.118500Z

I personally do not mind the more verbose version. I am wary of adding too many syntactic shortcuts since sometimes they begin to collide in unfortunate ways that make it more difficult to write correct tooling. But maybe you already have easy ways to quickly convert them into a normal form?

👍 2
ikitommi 2020-11-23T06:51:36.119100Z

no tools to convert, totally agree that there should not be extra syntaxes in malli core.

ikitommi 2020-11-23T06:53:25.120400Z

playing with :=> generators. also good peek at the syntax options (using children vs properties):

(def Age
  [:int {:min 18, :max 100}])

(def User
  [:map
   [:name string?]
   [:age Age]
   [:skills [:set [:enum "clj" "cljs" "rust" "go" "cobol"]]]])

;; option1: childs
(def create-user
  [:=> {:gen/=> '(fn [[age] user] (assoc user :age age))}
   [:tuple Age] User])

;; option2: properties
(def create-user
  [:=> {:gen/=> '(fn [[age] user] (assoc user :age age))
        :input [:tuple Age]
        :output User}])

(mg/generate User {:size 10})
; => {:name "Szf5sN", :age 21, :skills #{"cobol" "rust" "cljs" "clj" "go"}}

(def create-user-gen (mg/generate create-user {:size 10}))

(create-user-gen 46)
; => {:name "Itu96", :age 46, :skills #{"cobol" "rust" "cljs" "clj" "go"}}

👏 1
2020-11-23T07:08:09.120500Z

I like the 3rd version best, seems easier to read than the other ones.

👍 1
ikitommi 2020-11-23T07:17:54.120700Z

@martin887 that is basically Ghostwheel (spec) / Aave (malli) do:

(>defn bad-return-val
  [x y]
  [int? int? => string?]
  (+ x y))

ikitommi 2020-11-23T07:19:47.120900Z

one more:

;; 4: via properties
[:=> {:input [:tuple int? int?]
      :outut int?}]
[:=> {:input [:tuple int?]
      :output int?}]
[:=> {:output int?}]
:=>

2020-11-23T07:20:42.121100Z

I haven't used those, but it does seem more readable than the alternatives (I guess this is a very subjective thing, anyway). I guess I'm also with @rutledgepaulv in not minding a bit more verbosity

2020-11-23T07:20:58.121300Z

terse is really cool, until it isn't... 🙂

☝️ 1
ikitommi 2020-11-23T07:23:38.121600Z

data-specs for spec-tools for a great idea for really simple things. But as soon as one needed something non-trivial, it became a burden. Same with spec2, s/select syntax is awesome, until you need something inlined specs in it.

2020-11-23T07:23:56.121800Z

BTW, is the idea to provide the full power of malli for these? If I think of my use cases, the most likely ones would probably be rather complicated crap data (nested, with constraints, etc..), so it'd be cool to be able to use a registry or similar

2020-11-23T07:24:53.122Z

they may become rather unreadable very fast, if inlined as such

ikitommi 2020-11-23T07:25:05.122200Z

:=> is just a normal Schema, so generators, validators etc. work normally

2020-11-23T07:25:10.122400Z

ok

2020-11-23T07:31:22.122600Z

Not entirely unrelated to this, the other day, while trying to figure out that reitit issue, I thought the problem was that reitit wasn't picking up the registry, so I ended up writing a bit of meander term rewriting code that allows you to define schemas based on other schemas (where you'd normally use a registry), and compile those to malli "primitives". So you get both the concision and explicitness, in a way.

ikitommi 2020-11-23T21:31:26.126Z

also, validating functions against :malli:definitions:

(def Age
  [:int {:min 18, :max 100}])

(def User
  [:map
   [:name string?]
   [:age Age]
   [:skills [:set [:enum "clj" "cljs" "rust" "go" "cobol"]]]])

(mg/generate User {:size 10})
; => {:name "Szf5sN", :age 21, :skills #{"cobol" "rust" "cljs" "clj" "go"}}

(def create-user [:=> [:tuple Age] User])

(m/validate
  create-user
  (fn [age] {:name "elephant", :age age, :skills #{"cobol"}})
  {::m/=>validator mg/=>validator})
; => true

;; invalid return
(m/validate
  create-user
  (fn [age] {:name "elephant", :age age, :skills #{"PERL"}})
  {::m/=>validator mg/=>validator})
; => false

;; invalid arity
(m/validate
  create-user
  (fn [age _extra] {:name "elephant", :age age, :skills #{"cobol"}})
  {::m/=>validator mg/=>validator})
; => false

🔥 1