Most of the time, gems in Ruby Just Work. But there’s a big problem with Ruby magic: when things go wrong, it’s hard to find out why.
You won’t often run into problems with your gems. But when you do, Google is surprisingly unhelpful. The error messages are generic, so they could have one of many different causes. And if you don’t understand how gems actually work with Ruby, you’re going to have a tough time debugging these problems on your own.
Gems might seem magical. But with a little investigation, they’re pretty easy to understand.
What does gem install do?
A Ruby gem is just some code zipped up with a little extra data. You can see the code inside a gem with gem unpack:
gem install, in its simplest form, does something kind of like this. It grabs the gem and puts its files into a special directory on your system. You can see where gem install will install your gems if you run gem environment (look for the INSTALLATION DIRECTORY: line):
All of your installed gem code will be there, under the gems directory.
These paths vary from system to system, and they also depend on how you installed Ruby (rvm is different from Homebrew, which is different from rbenv, and so on). So gem environment will be helpful when you want to know where your gems’ code lives.
How does gem code get required?
To help you use the code inside of your gems, RubyGems overrides Ruby’s require method. (It does this in core_ext/kernel_require.rb). The comment is pretty clear:
For example, say you wanted to load active_support. RubyGems will try to require it using Ruby’s require method. That gives you this error:
Then, it activates the gem, which adds the code inside the gem to Ruby’s load path (the directories you can require files from):
Now that active_support is on the load path, you can require the files in the gem just like any other piece of Ruby code. You can even use the original version of require, the one that was overwritten by RubyGems:
A little knowledge goes a long way
RubyGems might seem complicated. But at its most basic level, it’s just managing Ruby’s load path for you. That’s not to say it’s all easy. I didn’t cover how RubyGems manages version conflicts between gems, gem binaries (like rails and rake), C extensions, and lots of other stuff.
But knowing RubyGems even at this surface level will help out a lot. With a little code reading and playing in irb, you’ll be able to dive into the source of your gems. You can understand where your gems live, so you can make sure that RubyGems knows about them. And once you know how gems are loaded, you can dig into some crazy-looking loading problems.