-.- --. .-. --..

Installing Patched Ruby using ruby-install

25 Jan 2015

Chruby + Ruby-Install is a very minimal Ruby version manager that I’ve been using for a long time. The ruby-install tool, unlike RVM, doesn’t ship with patches internally but it makes it trivial to apply third-party patches. Obtaining patches, though, is a problem with every new release of Ruby. Thanks to RVM, this problem is solved.

Obtaining patches

RVM ships with patches in the form of patchsets that are hosted on a separate Github repo. These patchsets and patches then go into RVM’s main repo. The patches are catalogued according to the Ruby version with which they are compatible. This is much better than hunting out for Ruby patches and updating them whenever a new release comes up. A patchset is just a collection of multiple patches. For example, some of the patches that are directed towards Rails applications are grouped into a patchset called railsexpress. This patchset will contain a list of patches—like Funny Falcon’s method cache patch—which makes it easy for RVM users to install all of them without listing them out individually . This, however, is specific to RVM and is not supported by ruby-install. For ruby-install, these patches have to be provided manually.

Installing patches

The -p flag to ruby-install can be used to install a particular patch. The argument supplied should be the raw text of the patch. For example, if we were to add Funny Falcon’s method cache patch to Ruby 2.1.2—which is present at the 2.1.2 railsexpress patchset URL—then the command that can be used is:

ruby-install -p https://github.com/skaes/rvm-patchsets/blob/master/patches/ruby/2.1.2/railsexpress/10-funny-falcon-method-cache.patch ruby 2.1.3

You can add multiple patches by passing more URLs: ruby-install -p patch1 -p patch2 ruby version

I use a ruby script to install ruby with a particular patchset (so meta!). It takes two arguments – a patchset name and the ruby version – and installs the Ruby version with the specified patchset:

#!/usr/bin/env ruby

require 'open-uri'
patchset = ARGV[0]
version  = ARGV[1]

raise 'Please specify a patchset' if patchset.nil?
raise 'Please specify a ruby version' if version.nil?

patches = open("https://raw.githubusercontent.com/skaes/rvm-patchsets/master/patchsets/ruby/#{version}/#{patchset}").read.split("\n").map do |patch|
  "-p https://raw.githubusercontent.com/skaes/rvm-patchsets/master/patches/ruby/#{version}/#{patch}"
end.join(" ")

puts "Installing ruby with #{`ruby-install --version`}"
puts "Available Rubies: #{`ruby-install`}"
`ruby-install #{patches} ruby #{version}`

Use this snippet like so:

./install_with_patches.rb railsexpress 2.1.2

This would install Ruby version 2.1.2 with the patchset 2.1.2/railsexpress.