Ruby software is commonly distributed as “gems”, packages containing Ruby
applications and/or libraries, which can be installed using the
RubyGems package manager, typically run as a command
named gem
. On Debian systems, some gems are also available as Debian
packages through the Debian package repositories. For Ruby developers on
Debian, it is almost inevitable that some gems will be installed through
RubyGems and some will be installed through the Debian package managers (and
possibly some installed through both). This post discusses some tips for
minimizing the pain of this situation.
Although the tips in this post have only been tested on Debian, they should be applicable to Debian-based distributions (such as Ubuntu and its derivatives) with only minimal changes, if any.
Why Use RubyGems and Debian Packages?
First, a quick digression: Why bother using both RubyGems and Debian packages? Why not choose one and stick with it? Half of the reason is simple, Debian packages only exist for a small subset of available gems. The other half is not as simple, and indeed it would be possible to avoid installing Debian packages for gems. However, using the Debian packages for gems carries the advantages of using any other Debian package: Integration-testing, compliance with Debian Policy (including the FHS), security support from the Debian Security Team, management using the Debian package managers, bug-tracking through bugs.debian.org, etc.
For the above reasons, and my personal biases, I’ll assume that if there is a Debian package available for a gem (and for the RubyGems package manager itself) that the Debian package will be used. Although, if a newer version of a gem than the one available as a Debian package is required, it’s easy enough to install that version using RubyGems.
Informing RubyGems of Debian Packages
In the default installation, RubyGems is not aware of any gems which have been
installed through the Debian package managers. Although this doesn’t cause
any serious problems, since the installation locations are different, it may
result in duplicate copies of gems being installed, causing confusion and
wasting space and bandwidth. The solution to this problem is very simple,
ensure that RubyGems is installed from a Debian package (either the
rubygems package for Ruby 1.8 or
by using the Debian package for Ruby 1.9, which includes RubyGems), then
install the
rubygems-integration
package through a Debian package manager (e.g. apt-get install
rubygems-integration
).
Once this is done, RubyGems will use already-installed Debian package gems to
satisfy dependencies and won’t install a second copy of such gems. Note
however that this will not, as far as I am aware, cause gem
to install a
Debian package to satisfy a dependency if one is available. The user must
first install the Debian package, if one is available, for it to be used.
Installing to /usr/local
As an administrator, I strongly prefer to keep all non-packaged software in /usr/local (or user home directories for user-specific software). This provides a clear distinction between software/files which I have to keep an eye on (to maintain, update, clean, remove, and provide security support) and those which I can defer to their Debian maintainers. However, there are valid reasons for keeping the default installation location, some of which are discussed in bug 448639, and users who find these more compelling may freely skip this section.
There are a few ways to change the installation location, called the “gem path” in the RubyGems documentation, although none of them are without drawbacks. Unfortunately, there is no supported way to change the system-wide default RubyGems installation location, that I am aware of.
Manually Specify the Installation Dir
The first option is simply to include
--install-dir=/usr/local/lib/ruby/gems/1.9
whenever gem
is invoked. This
could be accomplished with a shell alias, a wrapper script, or a very large
amount of discipline (for single-user systems).
Set the GEM_PATH
Another option is to set the GEM_PATH
environment variable. This could be
set system-wide in /etc/environment
(or /etc/profile
or /etc/bash.bashrc
for bash) or in user logon scripts.
Modify the RubyGems Source
The most fool-proof option, and the one with the highest maintenance burden, is to edit the RubyGems source to change the default install location. This is relatively simple, although it does require re-editing the source after each upgrade and comes with some risks for users not familiar with Ruby.
To change the system-wide default installation directory (if the
rubygems-integration
package is installed), edit
/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb:4
as
follows:
def default_dir
# File.join('/', 'var', 'lib', 'gems', Gem::ConfigMap[:ruby_version])
File.join('/', 'usr', 'local', 'lib', 'ruby', 'gems', Gem::ConfigMap[:ruby_version])
end
If the rubygems-integration
package is not installed, edit
/usr/lib/ruby/1.9.1/rubygems/defaults.rb
and change the following lines at
the end of self.default_dir
as follows:
# @default_dir ||= File.join(*path)
@default_dir ||= File.join('/', 'usr', 'local', 'lib', 'ruby', 'gems', ConfigMap[:ruby_version])
With those edits made, the default installation directory will be
/usr/local/lib/ruby/gems/1.9/
. Remember to re-edit the files after an
upgrading rubygems-integration
(or libruby1.9.1
if rubygems-integration
is not installed). As a reminder, it may be useful to place a hold on the
package in the Debian package management system to require explicitly
upgrading the package (e.g. aptitude hold rubygems-integration
).
Conclusion
That’s it. Those minor issues aside, everything seems to work quite well. Enjoy writing Ruby on Debian!