Fork me on GitHub
#clojure
<
2024-04-25
>
Leena Hyvönen10:04:54

Hi, what is the simplest way to list allowed values in a Malli schema? Like not to validate any object but simply to inform the user what values are allowed? By referring directly to the schema object it also returns the error message part. #CLDK6MFMK

p-himik10:04:45

Do you mean :enum? Note also that the hashtag you entered is highlighted - it means there's a designated channel for Malli.

Leena Hyvönen11:04:01

Ah, ok. Yes, the contents of :enum

p-himik11:04:20

Well, if you have (def s [:enum :x :y :z]), you can just do (malli.core/children s) to see what's in there. Plain (next ...) won't suffice because a schema vector is similar to Hiccup in that it can have an optional attr map instead of its first child. If that doesn't work for you, please give an example of your schema and the corresponding expected output.

Leena Hyvönen11:04:01

malli.core/children gives us this:

[[:enum "cat" "dog"] [:fn #:error{:message "value should be a valid kebab-case string"} #object[our_malli.enum$kebab_case_QMARK_ 0x316f30d6 "our_malli.enum$kebab_case_QMARK_@316f30d6"]]]
We would want to have a list with “cat” and “dog”

Leena Hyvönen11:04:01

Without using first etc.

p-himik11:04:34

How is the original schema defined?

Leena Hyvönen11:04:21

It is like this:

(defn- kebab-case? [s]
  (if (config/strict-enums?)
    false
    (= s (csk/->kebab-case-string s))))

(defn kebab-case [& enums]
  [:or
   (vec (concat [:enum] enums))
   [:fn
    {:error/message "value should be a valid kebab-case string"}
    kebab-case?]])

(def Animal
  (enum/kebab-case "cat" "dog"))
csk being [camel-snake-kebab.core :as csk]

p-himik11:04:48

Given that it's :or and not a plain :enum, there's no way to do it that would work in a general case. Even if you walk the schema with Malli's walker, you still can't do it. IMO the best way to handle it is to create a schema factory function (just like kebab-case in your case) that also attaches the right attr to the schema that you can extract with a separate function. It won't help if you then nest that Animal in some other schema though.

Leena Hyvönen11:04:42

Thank you. I don't quite follow what exactly would the factory function do?

Leena Hyvönen12:04:23

Animal is nested but in the use case present it could be referred directly without the schema it is in.

p-himik12:04:11

Something like this:

(defn kebab-case [& enums]
  [:or {:my-proj/allowed-values enums}
   (into [:enum] enums)
   [:fn {:error/message "value should be a valid kebab-case string"}
    kebab-case?]])

(defn allowed-enum-values [schema]
  (if (= :enum (malli.core/type schema))
    (malli.core/children schema)
    (:my-proj/allowed-values (malli.core/properties schema))))

Leena Hyvönen12:04:15

Thank you! That would make sense

Diego12:04:48

Hello! Anyone using H2 with clojure? I want to store JSON, but it's returned as a binary blob

({:data [34, 123, 125, 34]}
 {:data [123, 125]}
 {:data [123, 125]}
 {:data [123, 34, 116, 101, 115, 116, 34, 58, 49, 125]})

thomas13:04:58

How would you like your JSON to look like? Maybe then you can have a look at map that calls a function that transforms it as to what you require

Ludger Solbach13:04:49

What is the current YAML library of choice for parsing and writing? Still clj-yaml?

lread17:04:21

I think clj-yaml is what most folks use, and it is built into babashka, which is nice. I'm not sure, but @U05H8N9V0HZ might have other YAML developments/solutions he might want to share with you. If you decide to use clj-yaml, you can drop by #C042XAQFCCU with any questions, and we'll try to help you.

👍 1
Ingy döt Net02:04:14

https://clojars.org/org.yamlscript/clj-yamlscript is a YAML 1.2 loader (what you call parser) but has no dumper (what you call writer) component. So currently clj-yaml (YAML 1.1) is the best choice I know of for using YAML as a serialization tool. YAMLScript might be a better loader, if you are using YAML for loading human written YAML.

Ludger Solbach09:04:06

My use case is a schema converter (e.g. OData -> AVRO), so writing/dumping YAML is essential, as is loading. So I will try clj-yaml for now. Thanks for the insights.

👍 1
Noah Bogart14:04:50

does anyone actively use seesaw? i know it's in clj-commons but it doesn't seem to be in active development. related, is it still worthwhile to use swing compared to javafx (cljfx)?

Nundrum15:04:57

I have an old project using it, and Seesaw is better suited to it than JavaFX. But that's probably not the case for most desktop apps these days.

👍 1
Jason Bullers15:04:01

Interested in people's answers to this one too. If I had to guess, I'd imagine seesaw isn't active because swing isn't active. It was basically mothballed years ago when javafx arrived on the scene, so I'd think at a certain point, a Clojure wrapper around it would be "done"

👍 1
Nundrum15:04:10

Indeed. And I believe JavaFX still uses Swing under the hood for desktop.

deep-symmetry17:05:11

I still use Seesaw for my Clojure desktop application. And yes, Swing isn’t changing so Seesaw doesn’t need to change. It’s a bit clunky but it does what I need.

👍 2
Jason Bullers17:05:21

Clunky in what way?

deep-symmetry21:05:26

I guess the most concise way to boil it down is that it’s not how I would design a Clojure wrapper around Swing if I were doing it at my current level of familiarity with Clojure idioms. There is an overenthusiastic amount of multi-arity functions, and code to cope with whatever you throw at it (an individual item, a sequence of items, etc.) in places that make it harder to understand how to call things when you aren’t using it daily. The plethora of variant ways to do things can lead to code that is harder to figure out because you don’t remember the way you did it before, so now you have multiple patterns to recognize (again, exacerbated by the long time intervals between when I add new UI elements to my application). It encouraged me to sprinkle mutable state around my application in a way I now regret since I know better (but that is perhaps hard to fault given its close relationship with the mutable Java world). The most convenient layout manger it wraps (MIG Layout) is getting harder to find the documentation for as sites fall offline. Having to use the Swing event dispatch thread to call the developer helper methods (which list the available arguments for various synthetic builder functions) makes me stumble from time to time. That said, it is still vastly preferable to using Java Interop directly, and I am not likely to find the time and motivation to write something better, so I won’t stop using it!

👍 1
deep-symmetry21:05:51

And if you are curious, this is the desktop app I am talking about; there are some screen shots further down the page, and more in the user guide that is linked to from there: https://github.com/Deep-Symmetry/beat-link-trigger/

👀 1
Jason Bullers22:05:13

@U0EHA00G1 thanks for the rundown 👍:skin-tone-2:

😄 1
1
Craig Brozefsky20:04:38

so extend with metadata for protocols just brings us back to Perl OO right? https://perldoc.perl.org/functions/bless

hiredman20:04:05

the #1 thing I use metadata implemented protocols for is when creating components (https://github.com/stuartsierra/component/) it is great not to have to create lots of different defrecords. I have no idea what #2 is.

hiredman20:04:16

maybe I've used it to make testing mocking less obnoxious too?

phronmophobic20:04:01

Clojure has had support for OO features like single dispatch from the beginning. I think one of the main differences between clojure and perl is that idiomatic clojure primarily uses immutable data and pure functions which I don't think is typical for perl programs.

Nundrum21:04:59

And then you cycle back to CljPerl https://metacpan.org/pod/CljPerl

Noah Bogart21:04:58

we use protocols as pseudo interfaces at my job in combination with component so only certain services get access to various sets of functions