Ruby developers use Gemfiles all the time, and most of us know how to do the basics. In this post I want to dive deep into everything we can do with a Gemfile.
What is a Gemfile?
A Gemfile is a file we create which is used for describing gem dependencies for Ruby programs. A gem is a collection of Ruby code that we can extract into a “collection” which we can call later.
Your Gemfile should always be in the root of your project directory, this is where Bundler expects it to be and it is the standard place for any package manager style files to live.
It is useful to note that your Gemfile is evaluated as Ruby code. When it is evaluated by Bundler the context it is in allows us access to certain methods that we will use to explain our gem requirements.
Setting up a Gemfile
The first thing we need to do is tell the Gemfile where to look for gems, this is called the source.
We use the
#source method for doing this.
It isn’t recommended to have more than one source per project. For 99% of projects that require a Gemfile your source will be set to
https://rubygems.org. The only requirement for a source is that it must be a valid Rubygems repository.
Now seems like a good time to discuss source priority.
As well as defining a
source at the top of our Gemfile we can define a source against each gem we are loading in. We can also define a path for a local gem or a git path for a gem hosted somewhere like GitHub (we will get to these later).
When Bundler attempts to locate a gem it will look first at what has been explicitly set on the gem and use that.
If you set up a gem using
git any dependencies for that gem will look in those locations first before trying anywhere else.
If nothing has been explicitly set Bundler will look at the sources you have defined, starting at the first one and working down.
If a gem is found in more than one global source (this should rarely be the case because you should only really have one source) then you will get a warning explaining which gem source has been used.
You can call
#source as a block;
Sources with Credentials
Some sources you use will require credentials to be set.
Bundle has a config option that allows you to set a username and password for each source;
This will need to be set up by anyone who wants access to install gems using Bundler as it doesn’t go into version control (which is one of the nice things about doing it this way).
You can also set you credentials straight in the Gemfile, of course when you do it this way your details will be committed into version control.
Anything you specify in the source will override anything you have set using
Setting up Ruby information
If the application you are creating requires a specific Ruby version or engine we can set this in the Gemfile.
When setting this up the only required bit of information is the ruby version (in our example
:patchlevelspecifies the patch level for Ruby.
:enginespecifies the Ruby engine to be used.
:engine_versionspecifies the version of the engine being used. If this is set then
:enginealso needs to be set.
Setting up your Gems
Now onto the main point of using a Gemfile, setting up the gems!
The most basic syntax is;
In this case
my_gem is the name of the gem. The name is the only thing that is required, there are several optional parameters that you can use.
Setting the version of a Gem
The most common thing you will want to do with a gem is set its version.
If you don’t set a version you are basically saying any version will do;
There are seven operators you can use when specifying your gems.
!=Not Equal To
>=Greater Than or Equal To
<=Less Than or Equal To
~>Pessimistically Greater Than or Equal To
Pessimistically Greater Than or Equal To
~> operator allows you to say that your application will work with future versions of a gem in a safe way.
If you feel that the gem you are including is safe for an entire version you can specify;
This will allow any version of 2.x to be installed, but nothing from version 3.x
Perhaps you don’t feel comfortable giving a gem such a wide remit, in that case you can specify a more specific version;
This will allow anything from 2.5.0 up to anything below 2.6.0.
The following conversions might help you to understand it better;
gem "my_gem", "~> 1.0"–>
gem "my_gem", ">= 1.0", "< 2.0"
gem "my_gem", "~> 1.5.0"–>
gem "my_gem", ">= 1.5.0", "< 1.6.0"
gem "my_gem", "~> 1.5.5"–>
gem "my_gem", ">= 1.5.5", "< 1.6.0"
Setting your Gem to be Required
If you are using Rails this bit of “magic” may have been hidden from you, but inside your
config/application.rb you will see the following line;
This line will require all the gems that have been assigned a group of the same name as your Rails environment (for example test, or development). It will also require all the gems that haven’t specifically been assigned a group. We will cover groups shortly.
By default if you include a gem in your Gemfile it will be included when
Bundler.require is called. We can stop this by setting require to false;
You can also specify which folder(s) should be required when your gem is included;
This is useful when your gem has a lot of functionality that you need to manually require each time you want to call it.
Grouping your Gem
As I mentioned a gem can belong to one or more groups. When it doesn’t belong to any groups it is put into the
There are two ways you group a gem. The first is by assigning a value to the
This means it will only be required when the development environment is running.
It also means when you are installing gems (with
bundle install) that you can specify certain groups to not install. This can speed up the install time for new projects considerably.
Would install everything except gems in the development or test group.
The second way you can decide a grouping for a gem is by setting your gems up inside a block;
This is visually more pleasing, and you can combine groups;
If there is a group you want to be optional you can pass
optional: true before the block;
When this is set in order for it to be installed the user has to perform
bundle install --with development
Setting a Platform for your Gem
If a gem should only be used on a particular platform (or set of platforms) then you can specify so in the Gemfile.
Platforms work in much the same way as groups, expect that you do not need to run calls with the
--without flag as this will happen automatically.
Here is a list of all the different platforms you can ask your gem to install under.
- ruby – C Ruby (MRI) or Rubinius, but not Windows
- ruby_18 to ruby_22 – ruby & (version 1.8 .. version 2.2)
- mri – Same as ruby, but not Rubinius
- mri_18 to mri_22 – mri & (version 1.8 .. version 2.2)
- rbx – Same as ruby, but only Rubinius (not MRI)
- jruby – JRuby
- mswin – Windows
- mingw – Windows 32 bit mingw32 platform (aka RubyInstaller)
- mingw_18 to mingw_22 – mingw & (version 1.8 .. version 2.2)
- x64_mingw – Windows 64 bit mingw32 platform
- x64_mingw_20 to x64_mingw_22 – x64_mingw & (version 2.0 .. version 2.2)
I have found platforms really helpful when a development team are working across different platforms, if one of your developers is running Windows you might need different versions of gems depending on what is supported.
I normally use the block syntax when using platforms;
Setting a source for your Gem
As I mentioned earlier there is a notion of setting sources for your gems.
This is done in the following way;
If the gem isn’t found at this source it will not fall back to being searched for in the default source, it just will not install.
Installing a Gem from Git
You can set your install location to be from a git repository (such as Github). This acts in much the same way as changing the
Whilst you can link to the repository using
git protocols it is highly recommended that you use only
SSH since the others could leave you victim to a man-in-the-middle attack.
If you are storing your gem in a repository it should contain at least one file at the root of the directory with a
.gemspec extension. This should contain a valid gem specification.
If you don’t provide this file then Bundler will try and create one, but it shouldn’t be relied upon. If you do try and include a gem hosted on a git repository without a
.gemspec you need to have a version for your gem specified.
You can set either a
ref for your gem. The default is
You can also force Bundler to expand any submodules hosted in the git repository by passing in
If you have several gems you want to load in from the same git repository you can use a block;
Setting Git as a Source
You can set a URL to act as a more generalised source of information for your gems. You do this by calling
#git_source and passing in a name as an argument and a block which receives one argument and returns a string for the full repository address.
Bitbucket and Github helper methods
Since both Bitbucket and Github are popular places to house git repositories there are helper methods made for them.
In both cases Bundler assumes the repositories are public.
You can specify a branch by using the
If both the username and the repository name are the same (as is the case with projects like Rails) then you can omit one.
Warning – You shouldn’t use the
:github parameter until Bundler 2 comes out as right now it defaults to using the
git:// protocol, which as we have already heard can leave you open to man-in-the-middle attacks.
Another helper is
:gist, this can be used if your project is hosted on Github as a gist. You can just use the gist ID as the path. Like
:bitbucket you can pass a
:branch parameter into the method.
Include local Gem with the Path parameter
You can specify that your gem lives locally on your system by passing in the
If you specify a relative path (like I did above) they will be relative to the directory containing the Gemfile.
If you have an entire directory full of gems you want to include locally you can call this directory as block;
One thing to note is that Bundler will not compile C extensions for gems that have been specified using
Conditionally Installing Gems
Sometimes you want to only install a gem if some prerequisite is true, for example if there is a program available on your system.
This method accepts a proc or a lambda. In this example we only want to install a gem if we are on a Mac.