Fork me on GitHub
#clojure
<
2020-01-04
>
noisesmith00:01:48

looks like the :name key might do the trick- weirdly that doesn't change the artifactId in the generated pom, but it creates the right jar and installs / uploads to the right location...

pinkfrog15:01:54

skimming through the code, I see something like: (defmacro ^:private defcurried “Builds another arity of the fn that returns a fn awaiting the last param” [name doc meta args & body] (do-curried name doc meta args body))

pinkfrog15:01:23

does the ^:private really have any effect other than a hint to others reading the code?

Lennart Buit15:01:41

the actual macro is private and cannot be used (without trickery) from another namespace

Lennart Buit15:01:07

(ns a)
=> nil
(in-ns 'a)
=> #object[clojure.lang.Namespace 0x16544144 "a"]
(defmacro ^:private echo [v] ~v)
=> #'a/echo
(ns b)
=> nil
(in-ns 'b)
=> #object[clojure.lang.Namespace 0x7a9a3c2f "b"]
(a/echo 1)
Execution error (IllegalStateException) at nrepl.middleware.interruptible-eval/evaluate (interruptible_eval.clj:79).
var: #'a/echo is not public

Lennart Buit15:01:44

(here I create a private macro in ns a and try to use it in another ns b)

Lennart Buit18:01:16

Regex question: I am trying to match a quoted string, but only capture the actual contents of the string. I tried with non-capture groups:

(def ^:private any-ws "\\s")

(def ^:private quoted-str
  (str "(?:\")" "[^" any-ws "\\\"]*" "(?:\")"))

(re-matches (re-pattern quoted-str) "\"abc\"")
=> "\"abc\""
But that also seems to be capturing the quotes. The suggestion here: https://stackoverflow.com/questions/3926451/how-to-match-but-not-capture-part-of-a-regex/29498342 suggests to use lookaround assertions like this:
(def ^:private quoted-str
  (str "(?<=\")" "[^" any-ws "\\\"]*" "(?=\")"))
Which does work in regex101 (https://regex101.com/r/yhf0E0/3), but I cannot get it to work in Clojure, is this just impossible?

Lennart Buit18:01:47

this is probably one of those ‘don’t do this with regex’ things, but oh well here I am

p-himik18:01:26

(re-matches #"\"([^\s]*)\""
            "\"abc\"")
=> ["\"abc\"" "abc"]

p-himik18:01:53

You actually need a capturing group, on everything but the quotes.

p-himik18:01:11

And it's a perfectly fine thing to do with RegEx.

andy.fingerhut18:01:03

You need to be cautious whether the *ed expression matches double quote chars, too, and whether that is what you want

andy.fingerhut18:01:27

Also whether you care about ignoring escaped double quotes

Lennart Buit18:01:39

Thanks @U2FRKM4TW, but if I reuse that fragment somewhere else, it still captures the quotes. For example here where I use your regex in one of the alt branches of a named capture group:

(def ^:private quoted-str "\"([^\\s]*)\"")

(def thing-or-quoted-string (re-pattern (str "(?<group>thing|" quoted-str ")")))

(let [match (re-matcher thing-or-quoted-string "\"abc\"")]
  (.matches match)
  (.group match "group"))
=> "\"abc\""

p-himik18:01:29

Well, that's because you created a named capturing group that captures those quotes.

p-himik18:01:47

In my example above, if you get the second group you'll get the string without the quotes.

p-himik18:01:57

And as andy.fingerhut mentioned, note that I changed your RegEx inside [] - the new IDEA does something funky with backslashes, so I just skipped that part to avoid messing it any further.

Lennart Buit19:01:39

right, I understand that, but I cannot push the named capture group ‘inwards’ right? I want to capture either a ‘bare’ token or a quoted token with the quotes stripped in a named capture group This is not allowed:

#"((?<group>thing)|\"(?<group>([^\\s]*))\")"

Lennart Buit19:01:28

(sorry for my somewhat sloppy problem statement)

p-himik19:01:29

Why do you have to use such a convoluted solution? Why do you even need a named group?

andy.fingerhut19:01:13

If you want a capture group for the thing you want to match that is not inside double quotes, and a capture group for a quoted string, but that does not include the double quotes, the only way to do that with a regex that I can imagine right now is two have two separate capture groups, one for each case.

andy.fingerhut19:01:19

If the other thing you want to match cannot have double quotes around it, then you could have a single capture group that is "other thing" or "double quoted thing", with the double-quotes in the captured string, then remove the double quotes after capturing with separate code that checks for that case.

andy.fingerhut19:01:55

I would recommend avoiding using the context-sensitive parts of regexes if you can -- they are hard to reason about and get correct.

Lennart Buit19:01:51

Right ^^! It is part of a larger regex, which is why I was using named capture groups — I am also wondering what I am doing.

andy.fingerhut19:01:00

I mean, regexes can be difficult to reason about and get correct even if you do not use those features. Perhaps I am simply describing my own limitations here -- context-sensitive special stuff in regexes are just that much harder to get right, in my experience.

Lennart Buit19:01:21

I was already doing your second suggestion @U0CMVHBL2 but was wondering whether it was possible ^^

Lennart Buit19:01:33

with context sensitive you mean lookahead/lookbehind?

Lennart Buit19:01:04

yeah, the dark arts of regex, a great way to confuse coworkers 😉

andy.fingerhut19:01:13

In my opinion, if you want context-sensitive stuff, you should at least consider using a more general parser, like the Instaparse library provides, if for no other reason than the clarity you can get when writing the grammar.

andy.fingerhut19:01:30

That is not a one-line thing, though, so not to take on lightly.

andy.fingerhut19:01:10

Possible: probably. Easy to read and understand? I doubt it.

theeternalpulse20:01:59

I'm making a data-driven mock server that serves up response data based on template data stored for a specific request. The can be static {:simple-response: "hello"} or templated : {:data {:some-data (query-ref :x-query-value "default")}} where query-ref returns a function that retrieves the key :x-query-value from the request query (just a request parsed to an object) or defaults it to "default". There will be other functionality like this to retrieve the header to the response, return sequences of data (say based off paging headers/queries) etc. I was thinking that this does allow the user to just create template files in edn and pass them in. But is there something akin to hiccup for maps that i can utilize rather than having functions, just for the stake of serializing the data eventually?

p-himik20:01:13

Not sure what "hiccup for maps" means. Do you want to just get rid of the functions? So that your template becomes something like {:data {:some-data #query-ref [:x-query-value "default"]}}.

theeternalpulse20:01:20

I suppose, but wouldn't #query-ref just be the same function call just for edn?

p-himik20:01:46

It will be in the reader, not in the data. What is the problem that you're trying to solve?

p-himik20:01:05

#query-ref is not a function, if that's what you're saying. It's a reader tag.

theeternalpulse20:01:58

ah yes, I took a look at integrant and it would be something like

(let [readers {'parrot/query-ref query-ref}
      template (edn/read-string {:readers readers} "{:test #parrot/query-ref :test}")]
  (resolved-template template {:query {:test 1}}))

theeternalpulse20:01:32

did you wrap the args in an array for a particular reason?

p-himik20:01:27

Integrant uses tags, yes. But you don't have to use Integrant to use tags. You can attach a reader tag only to a particular form. Without the vector (list, map, etc), you cannot pass the default value.

theeternalpulse20:01:28

ah I see, the map has to have even arts, so you put all the parameters in the array

theeternalpulse20:01:20

I'd just have to change my implementation to take an array instead. I wasn't using integrant, just wanted to copy their style

p-himik20:01:04

An alternative to reader tags, if you for some reason don't want to use them, is to e.g. use some "private" keywords from some namespace, and then transform their values with a specific function.

theeternalpulse20:01:34

that was another thing I was thinking, that way I could at least guard it in some way, though I don't think I have too much issue with users passing in custom functions that accept the request as an argument

theeternalpulse20:01:43

but I like the reader aspect