When creating a new ruby gem (for example by running bundle gem my_gem ), two files are created which help manage dependencies: my_gem.gemspec and Gemfile . Both seem to allow us to specify that our gem relies on other gems.

Gem::Specification (the schema for defining a gem that is used in the gemspec file) provides two methods for specifying dependencies:

add_runtime_dependency for gems that ours relies on.

for gems that ours relies on. add_development_dependency for gems that used to develop the gem, but are not requirements for the gem to be used (for instance, rspec or rubocop ).

Both of these methods only allow for two arguments: the name of the gem, and a set of version requirements.

However, what if we want to use code from a github repository that has not been properly released as a gem?

How gem dependencies are installed

When a gem is installed (whether via gem or bundle ), its gemspec is used to determine which dependencies the gem requires, so that they can be installed as well. Only runtime dependencies are installed by bundle install (or gem install ) by default.

There’s a problem if we want to install code directly from git, though: neither add_runtime_dependency nor add_development_dependency allows specifying a gem source like bundler does via Gemfile .

In fact, the gemspec only specifies names and version requirements of dependencies because the source doesn’t matter — just that a gem can be found that matches the name and version in the spec. Sources are defined either by the Gemfile of the project that is requiring our gem, or as a --source flag to gem install .

A gem’s Gemfile is not considered at all when a gem is installed, and thus any dependencies within it are not installed.

Gems have Gemfiles too

When a gem is under active development, it is often useful to make use of code that has not been released as an actual gem. For instance, I have a small repo that contains a default rubocop configuration that I include into my projects so that I don’t have to repeat it each time. I don’t feel like it’s useful to release it as a proper gem, which means I need to load it via bundler’s git: option.

This is where the gem’s Gemfile is helpful. The bundler DSL provides a gemspec method which loads the dependencies from your gemspec (which is useful because then you don’t need to repeat the gems in both gemspec and Gemfile ). When bundle install is run, either by you, another developer, or a CI tool, all the gems required for both running and developing your gem will be installed.

Furthermore, bundler takes any development dependencies in the gemspec (specified by add_development_dependency ) and creates an implicit development group¹ within the Gemfile . This means that if you were to run bundle install --without development , any development dependencies listed in the gemspec would not actually be installed².

We can do this ourselves, by adding to the gem’s Gemfile (and even organize gems into the same groups if desired³). Any gems listed in the Gemfile will be installed by bundle install along with any from gemspec , so developers and CI will have these dependencies available. However, when the gem is packaged and then installed, these gems will not be included.

Example of how I include my rubocop_default github “gem” in other projects.

Remember that adding gems to the Gemfile will have effect when bundle install is called for the gem itself, and not any projects that include the gem in their bundle, so this trick will not allow adding runtime requirements that aren’t released as proper gems.