Fork me on GitHub
#babashka
<
2020-04-18
>
souenzzo01:04:22

@bherrmann

user=> (.foo) 
java.lang.NullPointerException

onetom06:04:00

now that babashka has an nrepl, which editor would ppl here recommend for interactively developing bb scripts? i saw chlorine claims to provide support for it: https://mauricio.szabo.link/blog/2020/04/01/nrepl-on-chlorine/ anything else?

ahmed1hsn06:04:36

You can also do that using socket repl, chlorine was originally built for socket repl. I'm using it from 6 months and it works great.

ahmed1hsn06:04:32

shell$ bb --socket-repl 8990

onetom06:04:02

using it with chlorine? any downsides? are you missing any features you would get from an nrepl client?

onetom06:04:32

just for the record, Cursive nREPL client gives this error, btw:

Connecting to remote nREPL server...
clojure.lang.ExceptionInfo: Unable to resolve classname: java.lang.reflect.Method [at line , column ]
Error initialising completion
Error initialising locals clearing:
clojure.lang.ExceptionInfo: Could not resolve symbol: *compiler-options* [at line 1, column 6]
clojure.lang.ExceptionInfo: Could not resolve symbol: clojure.core/clojure-version [at line 1, column 57]
Error initialising REPL:Error updating completions:
clojure.lang.ExceptionInfo: Could not resolve symbol: cursive.repl.runtime/completions [at line 1, column 2]

ahmed1hsn06:04:02

Yes, I use repl to evaluate and redefine functions. It simply works.

onetom06:04:14

may i ask if you are using any autocompletion or refactoring tools with it too?

onetom06:04:06

i have kinda settled with intellij+cursive for now, when it comes to clj development, but in our small company, practically everyone uses a different editor and they are quite keen on staying with it. since im the clojure advocate in the company, i have the ungrateful job of learning all the editors and their clojure toolings, so i can ensure that my colleagues clojure journey is as gelled as possible πŸ™‚

ahmed1hsn06:04:46

I just use it to evaluate expressions and for interactive development. It provides basic auto completion. Although you can use more advanced features. Read readme.md of Atom Chlorine. I came from emacs and am quite satisfied with experience.

onetom06:04:12

we literally have users of all these editors: - 1 intellij (myself) - 1 (neo)vim (the other most experienced programmer) - 1 spacemacs on macos (also quite experienced programmer, but mostly working as a CTO) - 1 spacemacs on linux (nixos) (also experienced ex-physicist coder) - 2-3 vs code (frontend devs) - 1 atom (junior data scientist)

onetom06:04:17

which atom version are u on? stable/beta/nightly? im just asking because something was complaining about the version of the ink package i need to use; had to manually downgrade it or something...

ahmed1hsn06:04:45

I'm on stable version. You can join #chlorine channel to interact with developers and users of chlorine.

onetom06:04:04

could have been just an issue with https://github.com/dvcrn/proton though... which seems to be a quite promising project. it's really similar to spacemacs, which im a bit envious of, while i would really prefer the performance of doom-emacs πŸ™‚

onetom06:04:29

good idea! thx, joining right now.

onetom06:04:03

for the record, Curisve just gets stuck at

Connecting to remote Socket REPL...
when im trying to connect to a bb --socket-repl

ahmed1hsn06:04:01

Emacs is great, but sometimes it's overwhelming for me. And it distracts me. So, I'm staying with Chlorine and Atom.

onetom07:04:22

Ah, thx. I just searched for "editor" within the main readme but haven't found anything. since that readme is so long, i just assumed that's all the available documentation for babashka

borkdude07:04:58

Yeah, I want to cut it in multiple pages, so I started with the REPL page πŸ˜‰

borkdude07:04:15

Maybe I should add the word editor to the description

neo255108:04:31

I use Emacs with Cider and it works great.

bherrmann13:04:10

FYI: I used emacs/cider all day yesterday with bb - no issues

borkdude11:04:43

Trying drewr/postal with bb. Status: it worked!

jeroenvandijk11:04:15

Cool! What’s next? πŸ˜…πŸ’ͺ

borkdude11:04:44

I'm not sure. this was just an experiment to see if I could get it working

wilkerlucio18:04:20

hello, is there a recommended library to parser XML with babashka?

borkdude18:04:42

@wilkerlucio co-incidentally, I was just checking on: https://github.com/borkdude/babashka/issues/153

borkdude18:04:00

it's not yet published

borkdude18:04:31

I want to make sure it also works with jdk11. I had to add these classes to the reflection config:

com.sun.xml.internal.stream.XMLInputFactoryImpl
             {:methods [{:name "<init>" :parameterTypes []}]}
             com.sun.xml.internal.stream.XMLOutputFactoryImpl
             {:methods [{:name "<init>" :parameterTypes []}]}
which makes me a bit uncertain about adding it, since these classes are private and may disappear at one point. But if they still work in jdk11, maybe it's fine

borkdude18:04:52

Seems to still work!

user=> (let [xml (xml/parse-str "<items><item>1</item><item>2</item></items>")] (xml/emit-str xml))
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><items><item>1</item><item>2</item></items>"
user=> (System/getProperty "java.version")
"11.0.6"

borkdude19:04:02

@wilkerlucio So, wanna test?

wilkerlucio19:04:59

@borkdude hehe, interesting, and sure, I would like to test, just use from master?

borkdude19:04:40

@wilkerlucio Check #babashka_circleci_builds. New binaries just got published there from the clojure.data.xml branch

borkdude19:04:20

This library has been on the list for a while, I think it makes sense to add it after some people have proven that it works in their scripts

borkdude20:04:30

@wilkerlucio Let me know about your success or failures when you're done ok?

wilkerlucio20:04:20

@borkdude cool, I got it to work for my case! πŸ˜„

wilkerlucio20:04:34

its a simple bb script to extract project version from pom.xml:

wilkerlucio20:04:36

#!/usr/bin/env bb

(defn xml-seq [path]
  (->> (xml/parse-str (slurp path))
       (tree-seq :content :content)))

(defn tag-name? [tag tname]
  (some-> tag :tag name #{tname}))

(defn tag-content-str [tag]
  (->> tag :content (filter string?) (str/join "")))

(defn pom-version
  ([] (pom-version "pom.xml"))
  ([path]
   (->> (xml-seq path)
        (filter #(tag-name? % "version"))
        first
        tag-content-str)))

(println
  (pom-version))

wilkerlucio20:04:14

so awesome to get this to run so fast, in clojure, I really appreciate babashka work, and your great support πŸ™

borkdude21:04:38

$ lein pom
Wrote /Users/borkdude/Dropbox/dev/clojure/babashka/pom.xml
$ /tmp/pom.clj
0.0.87-SNAPSHOT
Cool, yeah, it worked πŸ™‚

borkdude21:04:06

also: I should add xml-seq as well then, thanks for the reminder

borkdude21:04:26

@wilkerlucio Added your example to the tests and also as an example to the README: https://github.com/borkdude/babashka/tree/clojure.data.xml#pomxml-version

wilkerlucio21:04:09

@borkdude I'm thinking here about scripting dependencies, have you consider at some point allowing scripts to load code direct from the internet/path, I'm thinking on this way:

(require 
  [""
   :as pom])

(println (pom/pom-version))
I imagine this could be nice, if babashka could load and cache, and use the URL itself as internal name for the NS, kinda like nodejs works on file system. The first concern is of course security, given a URL content can change anytime, to aleviate that I was thinking on constraining the URL's for things we know wont change, for example raws from github with a commit SHA present, kind a crazy idea, but wonder what you think about it

borkdude21:04:37

@wilkerlucio I have been thinking about that. The closest you can get to that right now as as follows: https://github.com/borkdude/clojure-toolbox.com-babashka/blob/5b516fa0e325b7c9ba973a88e4600d3bbad97c66/script/generate.clj#L11-L26

borkdude21:04:25

I'm hesitant about introducing something like that because dependency resolution is a tricky thing and I rather leave that to tools like tools.deps, etc.

borkdude21:04:18

you can just download the file with babashka.curl or otherwise and load it with load-file as well or use slurp + load-string.

wilkerlucio21:04:36

yeah, I understand, it just feels very tempting πŸ˜›

wilkerlucio21:04:39

maybe a middle ground solution would be to allow the declaration of clojure deps on the script itself?

wilkerlucio21:04:41

#!/usr/bin/env bb
(include-deps
  {com.wsscode/babashka-tools {:git/url ""
                               :sha "..."}})

(require ['com.wsscode/babashka-tools :as bbt])

borkdude21:04:53

@wilkerlucio This is now possible:

(ns setup
  (:require [clojure.java.shell :refer [sh]]
            [babashka.classpath :as cp]))

(def deps '{:deps {medley {:mvn/version "RELEASE"}}})
(def cp (-> (sh "clojure" "-Sdeps" (str deps) "-Spath") :out))
(cp/add-classpath cp)

(ns script
  (:require [medley.core :refer [index-by]]))

(index-by :a [{:a 1} {:a 2}]) ;; => {1 {:a 1}, 2 {:a 2}}

wilkerlucio21:04:18

yeah, just saw that in docs, pretty cool, to turn that in a special "require" seems quite easy

penryu21:04:32

I'm trying to port some perl code that uses the $//`$RS` variable for line-based iteration (eg, while (<$fh>) { ... }) to babashka, but it doesn't look like the jvm offers any such override; just NL/CR. Is there a good workaround for this?

borkdude21:04:24

@penryu I'm not sure what this all means πŸ™‚ Typically you iterate over lines with line-seq or (clojure.string/split s #"\n")

penryu21:04:00

Yeah, sorry for pasting p$r1 c0d$ with wild abandon. The str/split approach gives me the desired output. However, in this script s is the contents of a potentially huge file I'm trying to avoid slurping.

penryu21:04:19

That's the main advantage of the $RS var in perl and awk.

borkdude21:04:20

what about line-seq?

penryu21:04:53

line-seq is at the mercy of what BufferedReader considers a line ending, isn't it?

penryu21:04:04

generally, \n/`\r`?

borkdude21:04:30

true but maybe it obeys what is printed here?

$ bb '(System/lineSeparator)'
"\n"

penryu21:04:18

Oh, let me clarify: I'm looking for way to change the separator from \n` to ===\n so I can process text like

multiple
lines
===
some
more
===

penryu21:04:52

(str/split ... #"===\n") works, but requires slurping.

borkdude21:04:53

then why don't you use line-seq and skip over the ===?

penryu22:04:52

Hrm. true, === does work with that. Now I'm not sure how to reassemble "multiple\n" and "lines\n" back into "multiple\nlines\n" ... maybe something like partition-by?

borkdude22:04:54

@penryu I'd use (clojure.string/join ...) for that

borkdude22:04:15

Something like this might work:

(ns lines
  (:require [ :as io]
            [clojure.string :as str]))

(with-open [r (io/reader "/tmp/foo.txt")]
  (doall
   (keep #(when-not (= "===" (first %))
            (str/join "\n" %))
         (partition-by #(= "===" %) (line-seq r)))))
("multiple\nlines" "some\nmore")

penryu22:04:33

hrm. yeah. maybe a (str/join (take-while #(not= % linesep) ...))

dpsutton22:04:20

i'm working on adding support for bb in inf-clojure. Is there a good way for tooling to know its in a Clojure repl powered by bb rather than clojure? Normally there is some kind of repl ns that is unique like lumo.repl or planck.repl. The only think i can think of right now for bb is #?(:bb :bb :default :not-bb)

borkdude22:04:28

it would be convenient if clojure had something like partition-by that skipped the separator

borkdude22:04:25

@dpsutton The reader conditional approach works.

borkdude22:04:29

@dpsutton bb also has a namespace called babashka.classpath which is probably not present in any JVM environments, unless someone is going to use babashka as a library, which seems unlikely

borkdude22:04:50

but the reader conditional is probably the safest thing to do

dpsutton22:04:50

agreed. thanks!

borkdude22:04:28

@penryu This might be faster using transducers, less garbage:

(ns lines
  (:require [ :as io]
            [clojure.string :as str]))

(with-open [r (io/reader "/tmp/foo.txt")]
  (into []
        (comp (partition-by #(= "===" %))
              (filter #(not= "===" (first %)))
              (map (partial str/join "\n")))
        (line-seq r)))

dpsutton22:04:02

bb is not interested in macroexpansion right? out of scope? (just seeing which features the bb path of inf-clojure needs to support)

borkdude22:04:27

@dpsutton bb does have macroexpand

dpsutton22:04:42

(macroexpand '(doseq [x (range 2)] (prn :x))) doesn't seem to match what clj does with it

borkdude22:04:14

@dpsutton yeah, doseq is kind of a special built-in thing in bb, that's why not all macroexpanions look the same

borkdude22:04:18

$ bb "(macroexpand '(when true 1 2))"
(if true (do 1 2))

dpsutton22:04:47

i just happened to pick a bad example πŸ™‚

borkdude22:04:11

yeah, there are a few of those. if it's important I could make it look the same but so far it didn't seem like a big deal πŸ˜‰

dpsutton22:04:28

and confirm there's no readline or dumb-terminal option i need for bb?

borkdude22:04:48

to be honest, I don't know what these are

dpsutton22:04:12

then i think it will work perfectly

dpsutton22:04:42

but i think its the difference between clj and clojure. in planck and lumo you specify -d for "dumb terminal"

dpsutton22:04:54

basically so it doesn't redraw the terminal line i think.

borkdude22:04:37

@dpsutton the behavior of the bb repl is pretty similar to clojure. i.e. if you don't use rlwrap, it sucks πŸ˜‰

borkdude22:04:06

but I don't see how that relates to the socket-repl

borkdude22:04:39

the code for the socket repl and repl are pretty much directly borrowed from clojure itself though

dpsutton22:04:49

inf-clojure can work with a socket repl or just interact with the dumb repl run in emacs itself

dpsutton22:04:02

and if there's no rlwrap involved it works out of the box

borkdude22:04:27

nice, so then it's already a "dumb" terminal so to speak?

dpsutton22:04:58

i'm surprised this is coming back nil though

dpsutton22:04:00

(doc json/parse-string)

borkdude22:04:02

@dpsutton That's an historical thing. Try (doc yaml/parse-string).

borkdude22:04:33

bb didn't have vars with docstrings in the beginning and cheshire was there very early on. fixing this is easy though

dpsutton22:04:15

cool. just making sure i've got everything hooked up correctly

borkdude22:04:27

I'll make an issue for this

borkdude22:04:41

is there a reason you're using the "dumb" repl and not the socket REPL?

dpsutton22:04:55

because the dumb one inf-clojure can just crank up on its own. emacs runs bb as a subprocess and makes it easy to get editing. if i run it as a socket repl i presumably start it up in a terminal and then connect from emacs

borkdude22:04:28

makes sense. I'm afk now πŸ’€

dpsutton22:04:38

thanks for the help!

penryu23:04:08

How taboo is it to use defs inside let? E.g., minimal example,

(let [HOME (System/getenv "HOME")]
  (def bashrc (str HOME "/.bashrc"))
  (def zshrc (str HOME "/.zshrc")))

penryu23:04:39

I should probably just do this, huh?

(def HOME (System/getenv "HOME"))
(def bashrc (str HOME "/.bashrc"))
(def zshrc (str HOME "/.zshrc"))

sogaiu23:04:38

my impression is that in clojure, 'inline defs' are seen by some as a helpful debugging aid, but not for production code.