New Mac Problems

As you may or may not know, macOS comes with a version of Ruby installed ( 2.3.3 released 11/21/2016). But something surprised me on my newest MacBook when I tried to install rspec… my terminal gave me the following permission error:

Fetching: rspec-3.7.0.gem (100%)
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory.

My experience in Ruby is quite limited - I started learning it ~2 years ago because it was the language to learn as a beginning programmer (the community is very supportive and there are a lot of learning resources posted all over the internet). I abandoned it to learn other programming languages after I began doubting it’s usefulness to me. I still remember a lot of the syntax and behavior, but one thing I do not remember is having to use sudo to install rspec when I was trying to learn TDD.

At first I thought my MacBook permissions got messed up because I had created a new admin user and deleted the original. Turns out, I was wrong. After a format and fresh install of macOS, the problem I was having still remained. This is due to macOS including Ruby inside the root file system so when trying to install a new gem, it attempts to install it within a root directory. The permission problem occurs because each individual user only has full read/write permissions within their home directory and only has read permissions for the root directory. Someone else in my internship program pointed out having the same problem and it was recommended that they use rbenv. So I decided to check it out.

Installing rbenv with Homebrew

Following the installation instructions on the README of the rbenv Github repo, it was fairly painless to install using homebrew:

  1. First, install homebrew by running the following command in your terminal: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  2. Install rbenv by running the brew install rbenv command.
  3. Initialize rbenv by running the rbenv init command.

Of course, I didn’t read anything else in the README until after I tried to install rspec again and got the same permission error. As it turns out, the README file does an excellent job of explaining how rbenv works and how to use it.

Behind the Scenes

rbenv manages different versions of Ruby on your computer. With rbenv, you can run 2.2.1 ruby code in one project and 2.4.3 ruby code in another project. It essentially works by intercepting the commands you run from your terminal. Everytime you run an executable in Terminal without specifying the full directory path where that executable is stored (using the ruby command, git, brew, rspec, etc,..), your terminal searches the list of directories specified in your in a system-wide environment variable called PATH. Using the echo $PATH command in a bash Terminal will return that list, with each directory separated by a colon (the default PATH in macOS High Sierra is /usr/local/bin:/usr/bin:/usr/sbin/:/sbin/). You can use the ls command to peak into any of these directories and you should see some familiar binaries (executables). Installing rbenv modifies the PATH variable, adding it’s own directory before any of the others. Because your Terminal searches through each sequentially until it finds a match, rbenv can then begin to intercept commands.

Installing Ruby with rbenv

Now, let’s walk through how to install the latest version of Ruby using rbenv and make it the system-wide default. Running the rbenv install -l command returns a list of all the Ruby versions available in rbenv. At the time of writing, 2.5.1 was the latest version of Ruby, so running rbenv install 2.5.1 should return something similar to:

$ rbenv install 2.5.1
ruby-build: use openssl from homebrew
Downloading ruby-2.5.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.1.tar.bz2
Installing ruby-2.5.1...
Installed ruby-2.5.1 to /Users/tim/.rbenv/versions/2.5.1

Changing Your Default Ruby Version with rbenv

Now, check the current system-wide default by using rbenv global (and/or ruby -v to check the current default version) and then set a new default using the same command with an added version parameter (rbenv global 2.5.1), and double check that the default version was updated using rbenv global and/or ruby -v (if either of these commands return the wrong version, try opening a new terminal window, and reissuing the commands):

$ rbenv global
system
$ ruby -v
ruby 2.3.3p222 (2016-11-21 revision 56859) [universal.x86_64-darwin17]
$ rbenv global 2.5.1
$ rbenv global
2.5.1
$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]

Success! The latest version of Ruby is now the system-wide default! If you’d like to find out more about what rbenv can do (such as using a different Ruby version for different projects), be sure to checkout the official README.