Fork me on GitHub
#clojure
<
2021-09-06
>
Jakub Holý (HolyJak)14:09:13

Is there a way to check that a string is valid as a keyword? Currently I can do (keyword "a,b") which creates a keyword that cannot be represented as literal, i.e. :a,b is not accepted (rightly so). Before I call keyword on a string, how can I check / ensure it only contains valid characters? 🙏 https://clojure.org/reference/data_structures#Keywords says little... I guess I could write a manual check for the rules described under https://clojure.org/reference/reader#_symbols and Literals / Keywords little more down?

delaguardo14:09:19

are you serializing data to edn?

Jakub Holý (HolyJak)14:09:30

No, generating Datomic attributes from customer-defined "custom fields" with a string name

p-himik14:09:38

The reader pattern is defined at clojure.lang.LispReader#symbolPat.

p-himik14:09:46

static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^/]].*/)?(/|[\\D&&[^/]][^/]*)");

🙏 2
Jakub Holý (HolyJak)14:09:29

I have tried it, but

(def p (java.util.regex.Pattern/compile "[:]?([\\D&&[^/]].*/)?(/|[\\D&&[^/]][^/]*)"))
(-> p (.matcher "abc,b") .matches)
; => true
x I expect false

vemv14:09:13

tools.reader is more strict about keywords (among other things), you can either use it or inspect its source for inspiration

👍 2
p-himik14:09:42

Ah, it reads tokens. And commas are treated as whitespace that, of course, separates tokens. Also a few other chars are important, but you wanna check the implementation for that yourself - it's not that easy to describe succinctly.

Jakub Holý (HolyJak)14:09:45

Thank you. For the time being I will be very strict and follow what https://clojure.org/reference/reader#_symbols describes and check for (re-matches #"[\w*+!-'?<>=]+" name)

Ed15:09:32

you could always round trip it and see if it changes ...

(let [x (keyword "a,b")]
    (= (clojure.edn/read-string (str x)) x))

👍 2
mpenet15:09:36

it still allows "illegal" kws like :a.b

p-himik15:09:20

Why would :a.b be illegal?

mpenet15:09:54

> Keywords - Keywords are like symbols, except: > They cannot contain '.' in the name part, or name classes. > Like symbols, they can contain a namespace, :person/name, which may contain '.'s.

mpenet15:09:27

from my understanding that would mean :a.b is not ok

p-himik16:09:55

Huh! Found this: https://ask.clojure.org/index.php/2808/specifically-allow-inside-keywords And yeah, I've been seeing them for years, both in CLJ and in CLJS. Would never have guessed the docs explicitly disallow it for some reason.

❤️ 2
noisesmith17:09:37

user=> :
:
at least one widely used clojure lib uses keyword literals like this, I wouldn't expect a change to the clojure reader that prevents it working

noisesmith17:09:00

(like any normal person I find that painful to see)

🙏 2
p-himik17:09:24

Oh wow. :) I was thinking about plain keywords like :user.id (which a user of HoneySQL, at least v1, might use) or :div.login-form (when using Hiccup).

roklenarcic15:09:40

Is there some blocking function for pulling values from async channel into a collection that’s supplied with the library? I haven’t spotted one. I can <!! in a loop, I know, but I am wonder if there’s one already.

p-himik15:09:32

Not sure what you mean by "a collection that’s supplied with the library". But maybe a/into?

roklenarcic19:09:25

but that isn’t what I was looking for, it returns a channel

roklenarcic19:09:01

but I can <!! on that

👍 2
sneakypeet17:09:01

Given the following code

(defmacro reg-fn [k f] ...)

(defn some-fn [] ...)

(reg-fn :my-fn some-fn)
Is there a way to get to the name of f passed into the macro (`some-fn` in this case). I want to check if the name conforms to a certain convention, and throw an exception if it does not. I’d also be happy with some-namespace$some-fn or even better the metadata of some-fn Thanks

p-himik17:09:21

Inside the macro, f is bound to the symbol that you pass to it. Just use (name f) somewhere in the unquoted part of the macro.

sneakypeet17:09:06

facepalm thanks. should have asked sooner. 😄

👍 4
2