The latest project I’m working on, written in Ruby on Rails, is run completely in Docker; from development to production. As a practitioner of TDD I rely heavily on the Ruby bundle to run my tests. Out of the box, it assumes your development environment to be on your local machine but with a bit of tinkering we can change those assumptions.

The Ruby bundle will try to find a Ruby binary within $PATH, however, by setting $TM_RUBY we can tell TextMate the exact location of the Ruby binary we want to use.

We create a new directory, .bin, within the root of our project. Within it we place a small Ruby binary wrapper named ruby.

#!/usr/bin/env bash
docker-compose run --rm -v "$RUBYLIB:/usr/src/textmate" web ruby -I/usr/src/textmate "${@//$PWD//usr/src/app}"

We also ensure it’s executable, chmod +x ./.bin/ruby.

There are a few things going on in the wrapper above. The Ruby bundle relies on a few supporting files for parsing the test output before presentation. These files are shipped within the Ruby bundle itself and thus not exposed to our Docker container. Fortunately, $RUBYLIB points to the location of these files, allowing us to mount the folder as we spin up a new container. Just mounting the folder alone won’t do much. We also have tell Ruby to include the newly mounted folder in its $LOAD_PATH.

The next problem is that any file path provided as an argument to the wrapper will be from the host’s perspective, not the Docker container. E.g., on my machine the project is located at /Users/kevinsjoberg/code/my-project whereas in Docker it’s located at /usr/src/app. We solve this using Parameter substitution; replacing all occurrences of our working directory with /usr/src/app.

Now all we have to do is tell the Ruby bundle about our Ruby binary wrapper. We create a .tm_properties file within the project root with the following contents.

TM_RUBY = "$CWD/.bin/ruby"

Voilà!