Why "require 'rubygems'" Is Wrong

The following was originally published at gist.github.com/54177 but has been copied here for posterity and because people keep asking me on IRC for the original link; it must be hard to find on gist for some reason.

In response to all the “huh?” responses to this tweet: You should never do this in a source file included with your library, app, or tests:

require 'rubygems'

The system I use to manage my $LOAD_PATH is not your library / app / tests concern. Whether rubygems is used or not is an environment issue. Your library or app should have no say in the matter. Explicitly requiring rubygems is either not necessary or misguided.

When you feel the urge to "require 'rubygems'" because some shit isn’t working, stop and consider whether one of these solutions is more appropriate:

1. RubyGems installs special wrapper versions of executables included with gems. Here’s /opt/local/bin/rake on my system as an example:

$ cat /opt/local/bin/rake
#!/opt/local/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'rake' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version = $1
  ARGV.shift
end
gem 'rake', version
load 'rake'

In this case, rubygems is required when the executable is run. Explicitly requiring rubygems in code loaded by these files doesn’t make sense. The whole point of these wrapper scripts is to push the rubygems loading machinery into the environment and out of your app / library / tests.

2. When running ruby FOO.rb and a LoadError occurs because rubygems is not available, DO NOT add require 'rubygems' to FOO.rb. Instead, run the command as ruby -rubygems FOO.rb. This will require rubygems before evaluating FOO.rb.

3. When running ruby FOO.rb and a LoadError occurs because rubygems is not available, DO NOT add require 'rubygems' to FOO.rb. Instead, set the RUBYOPT environment variable:

$ RUBYOPT="rubygems"
$ export RUBYOPT
$ ruby FOO.rb

You can even put that in your ~/.{bash,zsh,sh}rc if you prefer to always have rubygems loaded and available.

Why You Shouldn’t Force Rubygems On People

When I use your library, deploy your app, or run your tests I may not want to use rubygems. When you require 'rubygems' in your code, you remove my ability to make that decision. I cannot unrequire rubygems, but you can not require it in the first place.