Packaging from a gemspec is not the Best Way

drbrain | Fri, 09 Dec 2011 22:57:06 GMT

Posted in ,

Or, why you should use Hoe (or a tool like it) to package your gems.

A while back Yehuda wrote Using .gemspecs as Intended and asserted that packaging directly from a .gemspec file was both the way you were supposed to build gems and the best way to build gems.

This is not true.

Rake::GemPackageTask (now Gem::PackageTask) was added to rake less than two weeks after the first commit on RubyGems. Which points to the recognition of a need to have a better way to describe and build a gem than just a file.

Using rake allows you to do more than just package a static list of files in a clean and reusable manner. You can write tasks to generate files that are then packaged in your gem at build time. Hoe builds atop Rake to support many types of generated files easily through task dependencies.

For example, generating a .gemtest file to work with GemTesters, integrating with rake-compiler for pre-compiled gems or generating parsers.

I can hear you thinking "you might have a point there, but I don't generate any files, so how does this apply to me?" Well, what if you wanted to include generated man pages in your gem using binman?

In the world of packaging directly from a gemspec the way to automatically generate files is to violate RubyGems' internals by overriding Gem::Specification#initialize. I can't blame Suraj Kurapati for this, he's working within the framework of the popular thing to do and this is the only way he could implement it.

(Hoe, on the other hand, handles such pre-package dependencies through a set of pre-defined rake tasks that you can add dependencies too. If you need to generate a file you make the package task dependent on it. See the examples above.)

How can we make this better?

First of all, stop using gemspecs as the One True Description of your gem. Let rake generate it. While Hoe is obviously the best way to do this, it doesn't support generating the gemspec by default. You can use one of the gemspec plugins for that. I'm sure there are other build tools have the equivalent built right in.

Second, if you've writing a tool that generates files that will be packaged into a gem, provide a rake task like the one that ships with binman that build tool authors can hook to make packaging seamless.

(Also, please, don't use system when you can use API.) comments

Comments RSS FEED

One does not necessarily need to use Hoe to simplify Gem packaging, simply leverage Rake tasks:

require ‘rubygems/package_task’

  1. require ‘binman/rakefile’
    task :gem => :binman
    task :gem => ‘autogenned.md’
    file ‘autogenned.md’ do

  2. end

Rake is subtly powerful, and improves on the original project build utility: make. Rake is also bundled with Ruby 1.9, so no additional dependencies to worry about.

postmodern said about 13 hours later

You definitely don’t need to use Hoe, but how could I legitimately avoid promoting one of my own projects?

Eric Hodel said about 20 hours later

If the problem is needing to hook into undocumented internals in rubygems… how about fix rubygems to provide a documented/supported hook instead. Why provide extra tools to work around missing functionality instead of just improving rubygems itself?

Jonathan Rochkind said about 21 hours later

RubyGems provides both Gem::Builder and Gem::PackageTask which is used by Rake. The problem here is not that RubyGems does not support or document these things, it’s that the lessons of history are being willfully ignored.

Eric Hodel said 1 day later

Sorry, I was referring to your statement about:

> In the world of packaging directly from a gemspec the way to automatically generate files is to violate RubyGems’ internals by overriding Gem::Specification#initialize

That seemed to be your main concrete argument against using a bare gemspec to generate, that there’s no way to do it with public api. So, I wonder still, wouldn’t it be of benefit for rubygems to provide public api to do what over-riding #initialize does, but still with a bare gemspec?

If such public api were available, what would be the remaining downsides of packaging from a gemspec?

Jonathan Rochkind said 2 days later

Such a public API is available through rake. Any other tool can duplicate the features Gem::PackageTask exposes through use of Gem::Builder.

The gem commands should be as simple and reliable as possible. They should not duplicate the features of rake when rake is a good alternative. This adds complexity and duplicates the features of other libraries that are better-suited to the task.

What’s especially odd about Yehuda’s post is that it says “use gem build” followed by “you can automate this with a Rakefile”, so why don’t we just skip to step two and go back to doing it the way we’ve always done it, which is using `rake package`?

Eric Hodel said 2 days later

Comments are disabled