Skip to main content

Open Source Consultant, Software Developer and System Administrator

If you are interrested in hiring a consultant for the effective use of open source software on an enterprise grade, take a look around in the About section to see, what I have to offer.

Blog and snippets

Various snippets or code parts I found useful, so I keep them here for reference.

Make SDKMAN work in TMUX

SDKMAN -- the tool formerly known as GVM -- inherited a problem if used in tmux: in the newly started sessions within tmux the paths are not longer setup correctly to run the installed tools (e.g. like groovy).

To just make SDKMAN initialize again for each new tmux window, add this in your .zshrc (or in the .*rc of your shell) before your call to

if test "x$TMUX" != "x"; then
        export SDKMAN_INIT=false

Groovy `each` - or why everything is a nail

With the aspiring groovyist there is a tendency to use each for everything. When coming from an imperative programming language you did all the heavy lifting with for, while, if, etc. so each gets adopted again for that style of programming. This at some point will end with the question: how to break out of an each. And the simple answer is: you can't (well, you shouldn').

In Groovy many things look like some basic instruction from the language, so each looks like some loop instruction from the Groovy language, right? [1,2,3].each{ println it }? Well actually each is just a method, that takes a clojure as param, for this list and Groovy allows you leave out parentheses in that case. Does this still look like something basic like for: [1,2,3].each({ println it }) ?

What does each do then? It runs a for loop and passes each element to your provided closure. Your return value is ignored. No break, no continue makes sense here. Actually return early in your closure provides continue behaviour. Also note, that the return value of the each method is the list itself.

So here are a few each anti-patterns:

each instead of a map:

// NO!
def results = []
        results << (it*it)
// YES!
def results = [1,3,4].collect{ it*it }

each instead of a filter:

// NO!
def results = []
        if (it>1) {
                results << it
// YES!
def results = [1,2,3].findAll{ it>1 }

each to find first:

// NO, really NO!
def result
        if (it==2) {
                result = it
                break // does not work
// YES!
def result = [1,2,3].find{ it==2 }

each instead of a reduce:

// NO!
def sum = 0
        sum += it
// YES
def sum = [1,2,3].sum()
// or as an actual reduce, if you prefer:
def sum = [1,2,3].inject(0) { r,it -> r += it }

So what when you really need the behaviour of for? Well it's not forbidden in groovy. Just use it, it's even faster than each.

Make the Figwheel REPL work in vim-fireplace

I just have created a pull request with Vim-Fireplace, that allows passing down an expression to :Piggieback. This allows using the Figwheel REPL without much hassle.

First follow the instructions to create a Figwheel project. E.g. lein new figwheel example-project. Check the generated project.clj file and remove the comment on the line, that sets the nREPL port (:nrepl-port 7888, pick any port number you like).

To make Vim-Fireplace pick up the nREPL port create an .nrepl-port file containing the port number. E.g. echo 7888 > .nrepl-port. Otherwise connect from the Vim command line with :Connect nrepl://localhost:7888 (or follow the dialog with just :Connect).

In Vim then open any ClojureScript file (e.g. the generated src/example_project/core.cljs) and then enter at the Vim command prompt:

:Piggieback! (do (require 'figwheel-sidecar.repl-api) (figwheel-sidecar.repl-api/cljs-repl))

Now saving ClojureScript or CSS files will automatically (and statefully) reload in the browser. And all the regular things in Vim-Fireplace like evaluating expressions or requesting the docs work too.

For repeatability add this alias in your .vimrc (or in an after script for Clojure or Vim-Fireplace):

command! Figwheel :Piggieback! (do (require 'figwheel-sidecar.repl-api) (figwheel-sidecar.repl-api/cljs-repl))