Q: can I use Malli inside a babashka script? (i.e. does it run inside sci?)
there is https://github.com/metosin/malli/issues/302. Help most welcome
I think it will be quite a lot of work to port malli to bb compatible code. @ikitommi What is the API stability of malli? At one point we could add it to bb proper perhaps. I want to consider this, but also want some feedback from the "bb community" on this
Very stable. the named-schemas will change, but won’t change after release.
public api has been immutable for 6+ months, no plans on breaking.
thanks guys. since it’s only tools.cli in CI (i.e. almost never changes), I can write a custom vaildator instead
@steveb8n OK. This lib https://github.com/green-coder/minimallist also works with bb btw
cool. I’ll give it a try. thx
I like that it explicitely does not try to be fast. probably means they can deliver features faster
unlike Malli where I’m getting value out of the perf vs spec. perf is a feature
perf is a feature and the style of writing code (reifying Java classes) isn't well supported by bb from source for any Java class :)
Well, it is supported for records, etc, but definitely not fast
malli reifies just protocols, does that work ok?
is there something that we could do on malli side to make it work?
it’s all tradeoffs. I’m glad Tommi likes fast things 🙂
it does work:
$ bb -e '(defprotocol Foo) (instance? Foo (reify Foo))'
true
@ikitommi Maybe using reader conditionals helps, #?(:bb :foo :clj :bar)
for the parts that bb doesn't support
sure, happy to add. which parts? 🙂
try and you will find out :) happy to comment on those parts
the protocol cache thing at least? (hacking over dead slow satisfies?
)
just write a bb script of some malli code and see what breaks?
yes. in the malli repo, write a script like:
(require '[babashka.classpath :as cp])
(cp/add-classpath "src")
and then
(require '[malli.core :as m])
example/test-bed most welcome :)
that simple. cool.
will add that to our next tech/hack-friday, which is… tomorrow.
so, does the :bb
conditional work already?
@ikitommi Actually, this is better:
(ns bb-script)
(require '[babashka.deps :as deps]
'[clojure.edn :as edn])
(deps/add-deps (edn/read-string (slurp "deps.edn")))
(require '[malli.core :as m])
@ikitommi Yes, :bb
is prioritized over :clj
it's order dependent
@ikitommi So the first hack I did:
(ns malli.sci
#?@(:bb [] :clj [(:require [borkdude.dynaload :as dynaload])]))
(defn evaluator [options fail!]
#?(:bb fail! :clj
(let [eval-string* (dynaload/dynaload 'sci.core/eval-string* {:default nil})
init (dynaload/dynaload 'sci.core/init {:default nil})
fork (dynaload/dynaload 'sci.core/fork {:default nil})]
(fn [] (if (and @eval-string* @init @fork)
(let [ctx (init options)]
(fn eval [s] (eval-string* (fork ctx) (str s))))
fail!)))))
The nest error:
----- Error --------------------------------------------------------------------
Type: java.lang.Exception
Message: Unable to resolve classname: java.util.ArrayDeque
Location: /private/tmp/malli/src/malli/impl/regex.cljc:35:3
----- Context ------------------------------------------------------------------
31: recognition for `validate`."
32:
33: (:refer-clojure :exclude [+ * repeat cat])
34: (:require [malli.impl.util :as miu])
35: #?(:clj (:import [java.util ArrayDeque])))
^--- Unable to resolve classname: java.util.ArrayDeque
So we don't have that class in bb (yet)
I see that for cljs you didn't use it
I guess for bb you can take the :cljs
branches there
Then after doing that, I run into:
(deftype ^:private CacheEntry [^long hash f ^long pos regs])
There are other deftypes
in regex.cljc
what would be a good workaround for those?
or, will bb support those at some point?
good to understand how to create bb-compatible code for the future.
So these are the types of things that are not supported yet. Classes can be added, but deftype
isn't supported.
I don't know what to do with deftype yet. Records are "faked" using normal maps + metadata.
I have seen a similar thing with meander vs matchete. Matchete is written in a "simple" Clojure style so it just works with bb out of the box. https://github.com/xapix-io/matchete Where meander focuses on performance and this results in incompatible code.
Meander now has an "interpreter" which is compatible with bb which also more flexible than the macro style enforced in the main lib
this would be useful for validating tools.cli parsed options
Not yet, but feel free to post an issue, so we can gather community feedback. Meanwhile there are two options: spartan.spec and minimallist both work
Is there a way to get the humanized string for a schema, without any input?
(prn (me/humanize [:< 100]))
;;=> "should be smaller than 100"
you can either:
[:int {:max 100}]
or:
[:< {:error/message "should be smaller than 100"} 100]
there are set of "type" schemas, which read properties: :int,
:string
, ...
might map all predicates schemas into these internally, which would make things like JSON Schema transformations & normal transformations simpler, need just to be defined for the base type, not to all predicates.
pos-int?
-> [:int {:min 1}]
...
oh, with nil value you mean?
with no value at all
it seems that the returned string doesn't depend on the input
@ikitommi What I mean is: you can get a string from humanize
but this needs some input too which you first have to validate. However, the resulting string doesn't seem to be related to the input at all. This made me wonder: is it possible to get some "model" error message from a schema only, without validating anything
This can then be passed to the second arg of the :validate
tuple in tools.cli
Not that important, I can make the string itself manually or by validating some dummy input
malli supports both fixed error messages and functions generating error messages, the two examples here: https://github.com/metosin/malli/blob/master/src/malli/error.cljc#L62-L68
... and messages can be localized. So, no simple way to do without value.
there are helpers in malli.error
to pull out the error message/fn out of a schema, but value is needed for the fn case
also, one schema can emit many different errors, humanized by the error type. Maps emit extra-keys, missing-keys, missspelled-keys, etc.