We're hiring!

We're actively seeking developers for our new Detroit location. Learn more

Using Bundler for Ruby Gem Development

Just over a year ago I posted about Dealing With Gem Development Dependencies using Bundler. Bundler (v1.0.7 at the time of this writing) has changed quite a bit since that was written, so I want to update my previous post with the latest in Ruby gem development using Bundler to manage dependencies.

First of all, when starting a new gem you can now run bundle gem to generate a skeleton project directory:

1
2
3
4
5
6
7
8
> bundle gem my_project
      create  my_project/Gemfile
      create  my_project/Rakefile
      create  my_project/.gitignore
      create  my_project/my_project.gemspec
      create  my_project/lib/my_project.rb
      create  my_project/lib/my_project/version.rb
Initializating git repo in my_project

The Gemfile that is generated contains only two commands:

1
2
3
4
source "http://rubygems.org"

# Specify your gem's dependencies in my_project.gemspec
gemspec

As the comment in the Gemfile mentions, the actual dependencies of your gem go in the .gemspec file. Yehuda Katz considers this to be using a gemspec as intended. I really like that I don’t need an additional dependency in order to manage the .gemspec file.

Here is the generated .gemspec:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "my_project/version"

Gem::Specification.new do |s|
  s.name        = "my_project"
  s.version     = MyProject::VERSION
  s.platform    = Gem::Platform::RUBY
  s.authors     = ["TODO: Write your name"]
  s.email       = ["TODO: Write your email address"]
  s.homepage    = ""
  s.summary     = %q{TODO: Write a gem summary}
  s.description = %q{TODO: Write a gem description}

  s.rubyforge_project = "my_project"

  s.files         = `git ls-files`.split("\n")
  s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
  s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
  s.require_paths = ["lib"]
end

This .gemspec will automatically include all git versioned files in the gem. It gets the gem version number from another of the generated files: lib/my_project/version.rb. In the previous post I specified the dependencies in the Gemfile. Now I use the gemspec command in the Gemfile and specify the dependencies in the .gemspec file like this:

1
2
3
4
5
6
7
  s.add_dependency "dm-core", "= 0.10.1"
  s.add_dependency "dm-serializer", "= 0.10.1"
  s.add_dependency "dm-validations", "= 0.10.1"
  s.add_dependency "json", "~> 1.4"
  
  s.add_development_dependency "rspec", "~> 2"
  s.add_development_dependency "mocha", "= 0.9.8"

A generated Rakefile adds tasks for building, installing, and releasing the gem. And by putting require "bundler/setup" in my spec_helper.rb the runtime and development dependencies, as well as the source files for the current project, are available in the load path. No need to add your lib directory to the load path in your tests.

For more information about Bundler and .gemspec files (including when you should check-in the Gemfile.lock file) you should also read the Yehuda Katz post Clarifying the Roles of the .gemspec and Gemfile.

Patrick Bacon (44 Posts)

I’m a software developer at Atomic Object (since 2005) in Grand Rapids, MI.

This entry was posted in Ruby and tagged . Bookmark the permalink. Both comments and trackbacks are currently closed.

3 Comments

  1. Don Barlow
    Posted January 10, 2011 at 1:28 am

    When using Bundler for gem development, do you include Bundler itself as a dependency?

  2. Posted January 10, 2011 at 1:28 am

    Don: I have not been including Bundler as a development dependency so far. At this point I am treating Bundler a lot like Rake. Those are the two gems I always have installed in the system gems, and I assume they are available in any development environment. Everything else goes in a Gemfile.

  3. Don Barlow
    Posted January 10, 2011 at 1:28 am

    That makes sense, especially for gems that are strictly libraries.

    In my case, I have a gem that is more of a framework to run automated jobs. The jobs should run in the context of the bundle, so I’m going add as a dependency. I just needed to clarify that a little more in my mind.

    Thanks for the help.