By James Owen Jan 2 2021 • 5 min read
# A lightweight bash Object Oriented function based on jq
I've developed a tiny function that wraps jq to provide an object oriented coding package that plays nice with BATS and VS code debugging. The function is available on github (opens new window), and this article explains and supplements the oo_jq code
# Motivation
At one point I decided I was stuck refactoring my team's extensive bash scripts, and I should bite the bullet and get used to it. My main objections to bash were:
- No debugger
- No object oriented capabilities
- No way to implement unit tests
So I began searching for bash packages that would fill these gaps. Very quickly I was pleasantly surprised to find a healthy sets of solutions for these short-comings:
- Visual Studio code has a bash debugger (opens new window) that works quite well
- BATS testing framework (opens new window) works beautifully
- bash oo framework (opens new window) provides a heavy weight system
I was quickly disappointed in the oo framework because of how slow it was when debugging it in vscode; I think it was taking a minute to load the human.sh example. While it was very quick when running on the command line, it was too lethargic in the debugger, and besides, it was a heavy commitment to a custom language that would be hard to sell to my team. I needed a simpler, smaller bash oo framework
# Can I build a lighter version that is usable?
I began looking into building my own OOP framework imitating articles (opens new window), and then I realized a popular command line json tool (jq (opens new window)) already implements full json support that I could leverage. I experimented with using pure jq syntax and then wrapping jq and I landed on a single 50 line function that parses the first few arguments to implement 3 operators for object oriented operations.
# Resulting Syntax
oo mark = new Human
oo mark . name = 'Mark G. Smith'
oo mark . height = 180
oo mark : eat 'corn'
oo mark : eat 'blueberries'
# get properties
echo $(oo result = mark . name)
oo description = mark : describeYourSelf
echo $description
$ name: Mark G. Smith, height: 180, meals eaten: 2, meals: [ corn, blueberries ]
# Unit tests
I used BATS to provide a few tests that sample a few OOP paradigms:
- simplest constructor (oo mark = new Human)
- constructor with 2 args (oo mark = new Human a b)
- method with no return (oo mark : addYears 3)
- human inherits from animal
- human has eyes (aggregation)
- using objects directly (without a constructor like javascript Object literals)
# Class definition function boilerplate
In order to bundle together properties and methods for an object, we use a function with local variables and a case statement for the methods (which include an optional Constructor triggered by a "new" operator). Here's a skeleton template:
#!/usr/local/bin/env bash
source $PWD/oo_jq.sh
Human() {
local method=$1; shift 1
local -n self=$1; shift 1
case $method in
constructor)
oo self . class = $FUNCNAME
#... initialize properties with
# oo self . propertyName = <value>
;;
method_name)
#... statements using oo to read and write properties
;;
esac
}
# Development cycle with BATS and VS code
BATS allows TDD development but cannot be debugged in vscode. To get around this shortcoming, I copy the code under development into a .sh file (I use oo_jq.debug.sh over and over), I add a few lines of of code that trigger the code, add breakpoints and debug the code
# Conclusion
I've moved on from my original team, and I no longer have a need for heavy bash coding, but I hope this package might help others organize large bash scripts while allowing tests and debugging. I'm interested to know if this package is useful and usable in it's current form, and I'd be interested in extending it as necessary and collaborating with those interested as users and contributors. Please contact me at james.owen@virtualtwigs.com
© James Owen, Jan 2 2021