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.

ES6 object property shorthand with Groovy

Recently someone asked on StackOverflow whether there is an equivalent in Groovy for the JavaScript shorthand for properties of the object literal. It basically looks like this:

const a = 'foo';
const b = 42;
const c = {};
const obj = { a, b, c };
// the same as: const obj = { a: a, b: b, c: c };

While this feature is not supported in Groovy directly, it's easy to reproduce using a very underused feature: a macro. Macros are supported in Groovy since 2.5.

Create new file to contain all macros. E.g. Macros.groovy:

import org.codehaus.groovy.ast.tools.GeneralUtils
import org.codehaus.groovy.macro.runtime.*
import org.codehaus.groovy.ast.expr.*
import org.codehaus.groovy.syntax.*

class Macros {
    @Macro
    static Expression mapOf(MacroContext ctx, final Expression... exps) {
        return new MapExpression(
            exps.collect{
                new MapEntryExpression(GeneralUtils.constX(it.getText()), it)
            }
        )
    }
}

Then compile this file (this is important to do first, or else Groovy gets confused when something references the class, but it's not there):

# groovyc Macros.groovy

Next make the macro known. There must a file META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule in the classpath containing the following lines to make Macros from above work:

moduleName=Some name
moduleVersion=0.1-SNAPSHOT
extensionClasses=Macros

And then finally try it out:

def labels=["a", "b"]
def values=[1, 2]
println(
    [labels, values]
        .transpose()
        .collect{ label, value -> 
            mapOf(label,value) 
        }
)

And run it:

# groovy test.groovy
[[label:a, value:1], [label:b, value:2]]

Advent of code 2020

This year I am doing my first Advent of code ever using in Clojure. Advent of code gives daily code challenges, consisting of two parts building on each other.

I used this to try out vim-iced to replace vim-fireplace and tried out Kaocha.

Iced

Pros:

  • Starts its own REPL, so no need to fiddle with cider plugins etc.

  • Good integration into NeoVim.

  • Code evaluation is shown inline

  • Macro-expand into buffer

Cons:

  • The CLI tool needs a local installation of node to run shadow-cljs.

  • Code navigation only works when reloading a name-space.

  • Multiple crashes of NeoVim over the course of the month.

Kaocha

I replaced lein-test-refresh with Kaocha as my watching test runner. I really like the workflow of having my test run automatically every time I save a file.

Pros:

  • Ability to focus tests with meta annotations.

  • Colored, pretty printed output on test failure.

  • Seamless integration with clojure.test and Leiningen.

  • Many plugins and helpers (e.g. notify on test failure/success with a configured tool).

Cons:

  • Found no way to stop an long running test other than Ctrl-C.

  • The diffed output can be so overwhelming, I re-run tests sometimes with lein test just to get the plain data.

  • Output is captured and only prints once the test is finished; so "debug-println" is delayed and might never print in case of infinite loops.

Conclusion

While I am not convinced that I will stick with Iced, I really liked Kaocha.

The code is on GitHub

Media player SPA

I have put together a media player (listing of media and generating playlist of it) as an SPA using ClosjureScript. The server-side only needs some minimal setup with Nginx (namely to enable listing of directories as JSON). The code can be found on GitHub.

TIL: Using the Groovy CLI like Perl/AWK/...

While most of the time using groovysh as a REPL or groovyc to quickly compile a few files, I never realised that groovy comes with several features mimicking features from classic CLI tools like Perl.

The scripts to run on the input can either be passed as -e <s> where <s> is an argument with the actual Groovy code - or just pass a file name to load as script.

Filter lines like Perl

It's easy to write single line filters. The same works with groovy -ne 'script...'. The script gets line (the full line) and count (the current line number starting at 1). E.g.:

# head -n3 /etc/passwd | groovy -ne 'println "${count}. ${line}"'
1. root:x:0:0:root:/root:/bin/bash
2. daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3. bin:x:2:2:bin:/bin:/usr/sbin/nologin

There is also an option -a <s> to split the lines. If <s> is not given, a space is used. The array will be available as split in the script. E.g.:

# head -n3 /etc/passwd | groovy -n -a : -e 'println "${split[4]} uses ${split[6]}"'
root uses /bin/bash
daemon uses /usr/sbin/nologin
bin uses /usr/sbin/nologin

Begin and end AWK like

If the script to run contains a method begin and/or end, then those will be called at the beginning or end of processing. E.g.:

// stuff.groovy
def begin() {
    println "Start"
}

def end() {
    println "End"
}

println line
# head -n1 /etc/passwd | groovy -n stuff.groovy
Start
root:x:0:0:root:/root:/bin/bash
End

Transforming file content SED like

Given the flag -i <.suffix>, any arguments passed as files will be processed by the given script (and a <file.suffix> backup is stored. E.g.:

# echo World > 1.txt                               
# groovy -i .bak -p -e 'println "Hello ${line}"' 1.txt
# cat 1.txt                                           
Hello World
# cat 1.txt.bak 
World

Process data from sockets

Given the flag -l <port>, a socket server will be spawned and will run the given script against the data send from clients. E.g. start the server:

# groovy -l 5000 -e 'println "Hello, ${line}"'
groovy is listening on port 5000

And then send data to it:

# echo "World" | nc -w 1 localhost 5000
Hello, World