Fork me on GitHub
#beginners
<
2021-10-11
>
Lycheese09:10:52

Is there a good tutorial for parsing xml in an idiomatic way? I'm currently using data.xml/parse to get a map and a lot of nested for-loops and conds to get the tag and then dispatch tag-specific logic. It feels very clunky and only works because I know how many levels I need to drill down in this case. Would I need to write a macro to make this more generic? Is there a library that simplifies this? (I only need to get data out of the xml, not change or write it.)

flowthing10:10:04

XPath is also worth considering.

raspasov12:10:02

You shouldn’t need a macro. For most data extracting tasks, some combination of (comp …) and (get-in …) should be good enough.

raspasov12:10:31

There’s also Specter if you really need something advanced (or if you do need to “modify” the data, then it really shines, IMO) https://github.com/redplanetlabs/specter It has a bit of a learning curve.

Lycheese10:10:46

That looks very promising. I'll read up on them. Thanks 🙂

pez14:10:14

Do I have to do something to get a spec for a function to instrument the function? I have a function foo-fn and an f/def with only :args in it. I can do

(s/valid? (:args (s/get-spec `foo-fn))
          :break-please)
=> false
But calling (foo-fn :break-please) does not generate a spec error…

alexmiller14:10:07

function specs are only checked when the function is instrumented

🙏 1
pez16:10:02

Ah, makes sense. I have two functions which will be called very seldom. Does it make sense to leave instrumentation on in such a case you think? I guess it depends some on what the overhead is. Two two functions are called when the app initializes and I do not want to impose delays there…

alexmiller16:10:39

If you always want it, I'd call s/valid? I'm the function rather than use instrumentation

🙏 1
sheluchin14:10:19

I understand that isolating side-effects is pretty important, but how important is that when the effect is something very simple like a log statement? Still important so that lazy/eager consumption is no longer something that needs to be considered? As an example, I have a bunch of transformation fns where I've included a log/debug for troubleshooting. Is that a bad idea?

dpsutton14:10:53

one thing to consider is do you actually need laziness or are you using it by default because map and other core functions return lazy data structures?

dpsutton14:10:25

i doubt the log statement matters. I would just leave it. but worth considering in the future. especially when your log statements can be logged "later" due to laziness and make it quite hard to determine what is going on and when

noisesmith15:10:42

I think that's just a symptom of a deeper issue - if you log that an event happened you care about whether and when the event happens. If you care about whether something happens or not, or even more so if you care about the timing of the event happening, putting it inside any lazy context is a bad idea.

👍 2
introom14:10:54

why name the param as old form in if-let (https://clojuredocs.org/clojure.core/if-let) ?

alexmiller14:10:59

I think that's catching a case from a much older variant of if-let that had a different syntax

introom14:10:55

I am seeing this error when using if-let

(require '[clojure.spec.alpha :as s])
(if-let [x false]
  x
  ::s/invalid)
Syntax error macroexpanding clojure.core/if-let

🙌 1
alexmiller14:10:47

the ::s/invalid is problematic as it will be treated as a failing spec in the if-let macro

alexmiller14:10:01

this is a known issue

introom15:10:49

The doc of =if-let= mentions any? what does it refer to?

alexmiller15:10:34

that's the spec, it refers to the clojure.core/any? function

introom15:10:56

I see. There is some fdef on the macro.

introom15:10:21

Is it possible to disable the spec checking on these core functions and macros?

alexmiller14:10:13

you can get around this by doing something like

alexmiller14:10:04

(def inv ::s/invalid)
(if-let [x false]
  x
  inv)

popeye17:10:00

I have a csv file in the root directory where we use to have project.clj file , How to read the file from that location I am using below code which giving file not found, slurp is not an option for me

(with-open [reader (io/reader "in-file.csv")]
  (doall
    (csv/read-csv reader)))

Bob B17:10:16

we'd likely need more context - are you sure that a file with that name exists in the directory where your program is running? Are you running in the REPL or from a -main, because that could have an effect on the directory that's in the context. I know you said slurp isn't an option for you, but are you able to slurp the file? Because if slurping also gives a file not found, then the problem is not "how to read the CSV", but rather around a directory context

popeye18:10:56

I got the required output when I ran from lein run

noisesmith15:10:59

a very common issue is that files that you can read in dev either don't get packed into a jar (solution: include the file in a classpath directory, probably under resources/ somewhere) or it's in the jar but not a file (solution: use io/resource with a classpath relative root - eg. if it's in resources/foo/bar.csv use (io/resource "foo/bar.csv")) to portably load it in dev or other environments).

zach23:10:57

Hello! I am attempting to split a large string on a regex pattern, and keep the delimiter matches, and not having luck. I am wondering if folks would recommend focussing on the regex, or if there’s a more straightforward way to do it. The string is git tag annotations, the result of running git tag -n20,. so it’s a tag name, some spaces, a title, and a body of text after. The tags are all named cg-NNNN , N being any 0-9 digit.

zach23:10:32

if i had the string “cg-2150. This is the first tag\nand some details\ncg-2151 this is the second tag”. I would want to end up with: ["cg-2150" "This is the first tag\nandsomedetails\n" "cg-2151" "this is the second tag"]

zach23:10:39

I’ve attempted to do it with clojure.string/split and re-seq, and trying to do it with a positive lookup on cg-[0-9 ]+, using https://stackoverflow.com/questions/15286711/java-clojure-multiple-character-delimiter-and-keep-the-delimiter as a guide, but cannot get the text after the match at all. I have much to learn with clojure regex, so the answer might be there, but wanted to get clojurian’s advice. Thank you!

tomd00:10:31

I think doubling up the look around helps

(map str/trim (str/split input #"(?=cg-\d{4})|(?<=cg-\d{4})"))

tomd00:10:55

You can also use regex laziness with a lookahead:

(map str/trim (re-seq #"(?s)cg-\d{4}.*?(?=cg-\d{4}|$)" input))

zach00:10:47

Oh, awesome. I just tried the first example on my full input and it worked perfectly. Thank you, @UE1N3HAJH!

👍 1
randomm char03:10:47

where's a good tutorial on regexs? just have questions about the (?s) and ?(?=

tomd07:10:17

I really like https://www.regular-expressions.info/ and it looks like it has a "tutorial" section. For those specific parts, you want to read up on mode modifiers and special groups respectively.

randomm char19:10:16

Thanks for the info

👍 1