Jeff Kreeftmeijer

Don't put your *.gemspec in your Rakefile

2010-04-03

Yesterday I wrote “.gitignore your *.gemspec”, an article about how annoying it is to have your .gemspec in your repository.

Just to be clear; I was not talking about completely removing .gemspecs from gems and I was not talking to people writing their .gemspecs themselves. My previous post was about using Jeweler. When using Jeweler, you put your gem information in your Rakefile and generate your .gemspec when you need it.

The problem I found with this was people unnecessarily updating the .gemspec file — it’s as easy as running rake .gemspec — in patches, so I suggested to stop putting .gemspecs in gem repositories.

I think I started a discussion.

@rbates made a comment about five minutes after I posted. Here’s the deal; Bundler has the ability bundle a library from its git repository or from a local path by specifying this in your Gemfile:

# from git
gem 'yourgem', :git => 'git://github.com/user/yourgem.git'

# from a local path
gem 'yourgem', :path => '~/code/yourgem.git'

If you load a library like this, it does need to have a .gemspec in its code if it has any dependencies, otherwise Bundler will be unable to resolve and include these dependencies in the bundle.

@joshpeek suggests that Jeweler shouldn’t even have to write a .gemspec file, but @wycats eventually wrote a blogpost about adding .gemspecs to your repositories “as intended”. Be sure to read it.

I started thinking about other solutions to the initial problem of people updating .gemspecs and wondered; Why are we putting our .gemspecs in our Rakefiles? Is the Rakefile really a place for gem information?

From the replies to my blogpost, a lot of people were just updating their .gemspecs themselves. I opened one of my .gemspec files and didn’t remember why I had to generate all this.

You don’t need a tool to generate a .gemspec for you, it’s as simple as:

Gem::Specification.new do |gem|
  gem.name    = 'yourgem'
  gem.version = '0.0.1'
  gem.date    = Date.today.to_s
  
  gem.summary = "an awesome gem"
  gem.description = "extended description"
  
  gem.authors  = ['Me Myself', 'One Other']
  gem.email    = 'me@example.com'
  gem.homepage = 'http://github.com/user/yourgem'
  
  # ensure the gem is built out of versioned files
  gem.files = Dir['Rakefile', '{bin,lib,man,test,spec}/**/*',
                  'README*', 'LICENSE*'] & `git ls-files -z`.split("\0")
end

If you’re extremely lazy, check out @mislav’s TextMate snippet that generates a new gemspec just by typing gemspec.

The file is easy to read and easy to update. To release a gem, do:

$ gem build gem.gemspec
$ gem push gem-0.0.1.gem

This solves the issue of having your gem information in your repository twice — in your Rakefile and in your .gemspec — and will probably keep people from updating it unintentionally when patching your gem.

So, In my previous article I didn’t consider installing gems from git or a local path. Right now, you do need your .gemspec in your repository when you want your users to be able to do that.