The Project Three Cs: Ruby
I really enjoy setting up projects through vagrant because I can achieve a philosophy for a project that I think of as The Project Three Cs:
|Clean||Build a system from the basics|
|Consistent||Create a system the same way over and over|
|Convenient||Easily run steps by anyone at anytime|
When I rebuilt my blog to run jekyll server in a vagrant system instead of running the site on my local system, the vagrant system made blogging simpler for me precisely for the above reasons.
Even if a project has great test coverage, if it is hard to setup the system to run the tests, the project is frustrating to work with. Making a project as easy as possible for others (including myself) to get up and running increases a project’s utility.
There is nothing more frustrating than spending time fighting a system to meet a project’s requirements. It does not help that similar requirements can be tricky to install (i.e. multiple versions of a programming language interpreter, programming libraries, system permissions, etc.)
I follow the Three Cs because that’s what makes it fun for me to get into a project. It’s a bit more overhead up front in a project, but it really saves effort later on.
When I looked into applying the same Three Cs concept to one of my Ruby projects, I found I had to include in the README.md file these comments to the user:
- login: vagrant ssh
- change to vagrant shared folder: $ cd /vagrant
- install bundler: $ gem install bundler
- bundle required gems: $ bundle
The most likely person to need this information will be me, but the information is in the README.md, who reads that??? :-)
These notes are fine, but I asked myself: “Can I do better?” The answer is: yes!
Automating Post-Install Steps
When I look at the commands:
- host $ vagrant ssh
- guest $ cd /vagrant
- guest $ gem install bundler
- guest $ bundle
These commands are applicable to almost any Ruby project, they are not specific to the project.
This means we can automate these steps! Automated steps don’t have to be in the post-install notes!
As the project is using RVM to manage Ruby (so the system still works with the system installed Ruby,) the user needs to execute these post install commands, not root.
This problem seems really familiar. How did I solve it before?
Before, rvm.io gave instructions to use an external script and use the
privileged: false option.
Let’s do that again here.
External Shell Script
First, let’s create the external shell script file named
in the same directory as the Vagrantfile.
The file contents will be the post-install commands from earlier:
This is exactly the commands I would type post-install. The first
#!/usr/bin/env bash figures out the environment version of
bash to use (as some systems can have multiple bash install in
/usr/bin/env is a helper function to figure
out what version to use for the current environment setup.
Next, I will add to the Vagrantfile I have from before: first
installing rvm, then Ruby. Only after installing those items, run the
For each of the scripts, use the
privileged: false option so
the vagrant user executes these commands, not the root user.
Setting Up Project
Now, to bring up a system with a project fully configured:
These commands will do everything from: downloading the OS image, installing, configuring, getting the stable version of RVM, installing the specified version of Ruby, installing bundler, and getting all the project libraries.
Running Project Tests
Now the system is ready, let’s run tests (as all good projects will have!)
We’ve gone from cloning the repository to running the project specs with these six simple commands:
- git clone <repository>
- cd <repository directory>
- vagrant up
- vagrant ssh
- cd /vagrant
- <run test suite command>
Setting up any project just got a lot easier:
- Two of these commands are basic git commands to clone a repository.
- The next three commands are basic vagrant commands to bring up a guest system, logging into it, and changing to the shared directory.
- The last command is to run the test suite.
These fit the bill of a project’s Three Cs: clean, consistent, and convenient.
With one additional script to my original Jekyll Vagrant box, any Ruby
project is setup and ready for work, after:
vagrant up. Just
vagrant ssh and then
cd /vagrant. Then run anything needed for the
This is my philosophy for setting up any future project:
- have a Clean environment for each project
- each project is Consistent to setup
- super Convenient to bring up and take down
I really enjoy having such automated setups. It helps me jump in and out of projects because it’s easy and they follow the three Cs: Clean, Consistent, and Convenient.