Building Tools with GitHub

Appendix A: Ruby, NodeJS, (and the Shell) at GitHub

The founders of GitHub all had deep ties and contributions to the Ruby programming language, so we cover it more than other languages in this book.

In recent years, NodeJS (JavaScript for the server side) has grown in popularity, and JavaScript has always been an interesting language because it works on both the client side and server side. GitHub has offered several popular open source projects written in NodeJS.

For these reasons, this appendix gives a little more detail on using these two languages.

In addition, some fluency with the shell is beneficial. There are many GUI programs that hide the command line from you, but to truly dive deep into the GitHub API, it is worthwhile to use the command line inside a shell. These examples all work with bash (the Bourne Again Shell), but are careful not to use any advanced features of bash (so they should convert to other shells if you strongly favor another shell).

GitHub and Ruby

When the history of GitHub is documented, the Ruby language will take its place as a major character. Tom Preston Warner (one of the three founders of GitHub) built the initial libraries for using Git with Ruby, a library called Grit. You can host blogs on GitHub for free, and this tool called Jekyll is built using Ruby. Gollum, the technology that powers GitHub wikis, is built using Grit and runs on Ruby.

To understand GitHub, it is best to understand a little bit of Ruby. You can use many of the tools used at GitHub by simply installing Ruby, and not knowing any Ruby syntax. This book will not require you to become an expert in Ruby, but will ask you to read through Ruby code. We write in a literal, readable way, so that anyone with basic software developer skills and mastery of the English language should be able to understand the tools we are using. Ruby is not a perfect language, but is a useful addition to a developer’s toolkit because of its focus on developer productivity.

Installing Ruby

There are many ways to get Ruby but not all of them are created equal. As a long-time user I have experienced the pain of using a preinstalled Ruby or one from a package manager, and generally these installation methods provide a suboptimal experience. If you are not familiar with Ruby, use this appendix to get through installation with the least friction and trouble.

You might already have a version of Ruby installed. Mac OS X comes bundled with Ruby and various flavors of Linux do as well (or provide a quick and easy installation through the built-in package manager like "apt-get"). However, I recommend that you use the method of installation described here rather than using the stock installed version of Ruby you might already have on your system. Often Ruby packages require a specific version of Ruby, though they may work with other versions. The problem is that you might encounter subtle bugs that have never been seen before, and using the methods described here will make it trivial to install any version of Ruby that you need side by side with any other version. You can guarantee you are using the correct version, and the method described here will not interfere with any other previously installed version of Ruby you already have on your system.

To install Ruby, use RVM. RVM stands for Ruby Version Manager. RVM allows you to install multiple versions of Ruby on your machine and have them interoperate without conflict. You will probably only need to install a single version of Ruby to use the examples in the book. And RVM makes it so that if you choose to install another version, you will not have to reconfigure any applications that relied on the other versions installed.

Installation of Ruby using RVM depends on your operating system. If you are using Mac OS X or Linux, your installation will probably be as simple as running these commands from a shell:

$ \curl -sSL https://get.rvm.io | bash -s stable

This will install RVM and Ruby.

If you are running Windows, you can use RVM to install Ruby, but your instructions are a little more complicated. Refer to the documentation to do so. A better option is to consider installing something like VirtualBox (a virtual machine manager). If you do this, you can install RVM inside a Linux Virtual Machine (VM). Windows is, sadly, a second-class citizen with Ruby and RVM and, for this reason, it is often better to install RVM inside a host system like Linux, which has a wider community around it to support you. VirtualBox and Linux are free as in beer and as in speech, so you can try them out without cost (other than your time). There are many native gems for Ruby that don’t properly compile if the host system is Windows, so you can save yourself considerable time by just using a completely free (as in beer) option like VirtualBox and a Linux virtual machine running on Windows instead of fighting with running everything directly on Windows.

Important Ruby and RVM Concepts

Here are a few tips when using Ruby and RVM:

Gemfile

Ruby packages libraries in a format called a gem. A gemfile is a manifest that describes which gems your application needs. Gemfiles make it simple to install all the required libraries: run the bundle command from a shell prompt and all libraries will be installed, which can include downloading from the network and building from source if compilation is required.

.ruby-version or .rvmrc

These two files tell your application (or shell) which version of Ruby to use. Often applications will include this file as a part of their package. If you use RVM, it will either switch to that version of Ruby or prompt you to install that version. Imagine that you have an application that only runs on Ruby 2.1.3. You can create a file called .ruby-version, which contains the string ruby-2.1.3 and when your application starts, it will automatically use that version of Ruby. There are other Ruby-based tools (like the zero-configuration web server Pow) that are aware of files like .ruby-version and will properly use the correct version of Ruby if they see this file.

config.ru

This is a file used to run Ruby applications using Rack. Rack is a web server interface, compatible with many application servers. If you see a config.ru file, you can run this application with many different servers. These can be powerful frontends used in production on many large sites on the Internet, or they can be minimal servers used just on a single laptop; Rack makes it easy to set up a server.

Potential Problems Installing Ruby

Missing system tools

If you are running Mac OS X, you need to install Xcode and the command-line tools. If you are a software developer, you probably have these already installed. If not, review online documentation to install these. If you are running Linux, you might not have installed the compiler chain; you can install all the build tools you will ever need using this command: sudo apt-get install build-essential. This can take a while, but will ensure you have all the tools necessary for building RVM and any binary gems.

Missing developer libraries

There are some libraries that support Ruby (readline support, as an example, which allows you to use command-line history inside of an interactive Ruby shell) that are not always installed or available to the RVM tool. RVM has greatly improved in detecting the correct libraries, and there are often notes that tell you how to properly configure these libraries. Make sure to read the output printed to the screen as you install Ruby using RVM for special instructions specific to your platform.

GitHub Is Excited about NodeJS

NodeJS is the server-side version of JavaScript. JavaScript is the only ubiquitious client-side programming language for the Web. Between Ruby and JavaScript, you can build any web application you need. Tools like Hubot show the benefits of using a language like JavaScript running on the NodeJS platform, which facilitates building "fast, scalable networked applications."

NodeJS Installation

The nodejs.org web page offers various binary installers. These are generally the best way to install the most recent version of NodeJS.

Node Version Manager

NVM stands for "Node Version Manager" and is a direct correlate to RVM. Like RVM, NVM allows you to install multiple versions of NodeJS on a single machine and switch between them seamlessly. This can be very useful when using a tool like NodeJS that is iterating rapidly (and whose modules are also often tested against only a very new version of NodeJS). NVM runs on OS X or Linux. To install, run these commands from a shell prompt:

$ curl -o- \
https://raw.githubusercontent.com/creationix/nvm/v0.25.3/install.sh | \
bash

This will install NVM for you. You then might need to run source ~/.bash_profile to load the NVM scripts. Once this is completed, you are able to run NVM commands:

$ nvm install 0.10 # Install version 0.10
$ nvm use 0.10     # Use version 0.10

There are many more commands available with NVM, all of which can be found at the repository where the tool is hosted.

package.json

Much like Ruby has a Gemfile that indicates required libraries, so too does NodeJS have an equivalent file. In NodeJS, this file is called package.json. To install all required libraries for any project, use the npm tool (installed by default when you install NodeJS using NVM). Running npm without any arguments will install all libraries specified by the application if there is a package.json file included with the project. If you want to add a package to an existing package.json file, you can append --save to the npm command and npm will update package.json for you once the installation of the package has completed.

Command-Line Basics and the Shell

Though most chapters have focused on a specific programming language (aside from [introduction]), all of the chapters contain command-line invocations. There are a few intricacies when using the shell you might not be familiar with that we will explain here, with an actual example of each.

Shell Comments

If you type a hash character (#) into a shell command, the rest of the line is considered a comment. This makes it easy to document commands on the same line:

$ cat file.txt # This prints out the file "file.txt"

This command ends after the file.txt string. We use this often throughout the appendix to document shell commands.

Providing Variables to Commands

When a process runs in the shell, it runs within an environment, and this environment can be configured with key/value pairs. These are called environment variables. A common reason for this is that you can write a program that reads passwords from the environment variables and then specify them at runtime rather than in the source code. You specify environment variables either as key/value pairs joined by an equal sign in front of a command, or by using the export command to persist them across commands:

$ PASSWORD=MyPwd123 myProgram  # myProgram retrieves the variable PASSWORD
$ export PASSWORD=MyPwd123
$ myProgram # PASSWORD is now a persisted key value

Splitting Commands into Multiple Lines

The shell invokes commands when you hit the Enter key. But there are times when you want to break a command into multiple lines for readability. In this case, break each line up using the backslash character:

$ git log -S http
...
$ git \
log \
-S \
http
...

Though not the most compelling command to break into multiple lines, this example shows two commands that do exactly the same thing.

Piping Output to Successive Commands

Shell commands were written long ago in an era when programs fulfilled upon a small set of functionality, in stark contrast to today’s monolithic GUI programs. Each program generally did a few simple things and then passed information to another program for further processing. Programs then needed an elegant way to pass data between each other, and the pipe was born. Pipes facilitate communication between processes: one command’s output becomes another command’s input.

$ cat /etc/mime.types | grep http
application/http
application/vnd.httphone
application/x-httpd-eruby     rhtml
application/x-httpd-php
phtml pht php
application/x-httpd-php-source      phps

This invocation uses the cat program to output the file /etc/mime.types, and then passes this information to the grep program, which looks inside the input to find all lines that contain the string http.

Redirection

Similar to the pipe, shells support redirecting output to files using the > and >> characters. > will overwrite an existing file (or create a new file if it does not exist) while the double >> string will append to a file:

$ cat /etc/mime.types | grep http > saved-output.txt

After running this command, the file saved-output.txt will contain the same text as was produced in the prior example for the pipe. The file will be overwritten if it existed already.