This week, we released a new version of RubyGems. We haven’t done
very well with Open Source’s "Release Early—Release
Often" rule of thumb (on either count). But, we have added a lot of
new stuff. Because there are so many new features stacked up, we need a lot
of help putting this release through its paces. Specifically:

Applications

We’ve added the ability to install "applications". With the
previous RubyGems release, you could install libraries, but if you had an
executable program included with your package, there was no direct support
for installing it. Now, you can do this:

  tashi-delek:~ chadfowler$ sudo gem -Ri rake
   Attempting remote installation of 'rake'
   Successfully installed rake version 0.3.2
  tashi-delek:~ chadfowler$ rake --version
   rake, version 0.3.2

Because RubyGems allows multiple versions of the same package to co-exist,
we auto-generate an executable script that points to the real location of
the script (in the gems directory). It looks like this for now:

  require 'rubygems'
  require_gem 'rake', "0.3.2"
  load 'rake'

I’ve been considering adding an option that would allow the
"0.3.2" part to be overridable, so you could do something like:

  rake --gem-version 0.3.1

I’m not sure about that yet.

Binary Gems

The previous release of RubyGems only supported installation of either pure
Ruby gems or pre-compiled, platform-dependent gems (e.g. x86 Linux
XMLParser). We recognize the need for two things: 1) Installation of
extensions from source and 2) "intelligent" selection of
precompiled gems in the remote installation process. Rich took a stab at the first
of these. A gemspec can now contain a reference to one or more extconf.rb
scripts, which will be run (to generate a Makefile), followed by a
‘make install’:

  spec.extensions << "ext/mygem/extconf.rb"

We’ve tested this one with an RDF/OWL library that Rich is working on
as well as with Ripper.
We could use help testing it and (probably) making it work on Windows. It
seems like this would be a fragile area, so the more gems we see and test,
the better. If you’ve got a Ruby/C extension—especially if it
does something unusual—please consider making a gem of it and sending
it in.

Gem Testing

If you’ve got unit tests for your library or application, you can
include them in your gem spec, and users will have the option of running
them at install time. If tests fail, RubyGems will ask the user if they
would like to keep the software or remove it. You specify a test suite by
adding a pointer to a file that references all of your tests to the gem
specification:

   spec.test_suite_file = "test/all_tests.rb"

Then when you run

   gem -Ri my-well-tested-lib --run-tests

the RubyGems system will download, install, and run the library’s
tests.

Library Stubs

Typically, to use a gem, you have to do something like this:

  require 'rubygems'
  require_gem "somegem", ">= 1.0.0" # version spec is optional

This will load the RubyGems library and then add somgem to the
LOAD_PATH and load whatever libary is listed as the gem’s
"autorequire". So, in most cases, these two lines will load
everything you need in order to use an external library.

There have been various hacks and work-arounds suggested to avoid having to
1) require the RubyGems library and 2) use the special
"require_gem" as opposed to a normal "require". Gavin
Sinclair went ahead and implemented one of them, installing a library stub
(similar to the application stub mentioned above) into Ruby’s
"site_ruby" directory. So, if your gem’s autorequire is
"rss/rss.rb", it will be possible to

   require 'rss/rss'

and a stub library will load RubyGems and use "require_gem" to
load the "rss" library. The behavior is optional and turned off
by default in the current CVS (left it on for the 0.3.0 release). To
install a library with the stub, you just do:

   tashi-delek:~ chadfowler$ gem -Ri rubyzip --install-stub

   tashi-delek:~ chadfowler$ ruby -e 'puts require "zip/zip"'
   true

Of all the hacks and work-arounds, I think I like this one the best,
because it actually installs a real file that gets require’d instead
of replacing Ruby’s require at runtime. Having said that, though I
like it better than the other ways, I’m still not sure if I like it.
Time will tell. I’d be interested in hearing reactions from users.

Config/Preferences File

Gavin also created a simple config file option for the "gem"
command. It looks by default for ~/.gemrc, though it can be overridden by
the "—config-file" option of the "gem" command.

The config file is in YAML format with,
at the time, only two options. It looks something like this:

   gem: --gen-rdoc --run-tests
   rdoc: --template kilmer

This config file will cause "—gen-rdoc" and
"—run-tests" to be prepended to all invocations of the
"gem" command and will cause the "kilmer" template to
be used when generating rdoc documents. This is a good way to make
non-default behavior the default for you. Someone was asking on irc that,
for example, —gen-rdoc be on by default. There was an informal vote
showing that only one person wanted this feature to be on by default.
Fortunately for him, .gemrc can do that.

Library Versioning

There has been a lot of discussion around library versioning between these
releases. We haven’t actually done anything about it, and I have to
admit that it’s making me tired. Here
and here
are good places to start if you’d like to take a peek into the
debate. It centers around how to deal with API-level incompatibilities in
libraries. There are four leading solutions, none of which are really all
that great:

  • Introduce a new API version number which is unrelated to the gem version
    number
  • Make the gem version number have some implicit meanings, the worst of which
    is that "> 1.0" would implicitly mean "< 2.0".
    This one really bothers me. "Greater than one"
    shouldn’t implicitly mean "less than two".
  • Add the ability to specify a version dependency that looks like
    "1.." (any version in the "1" family)
  • Ignore the issue until it becomes an actual problem. It probably
    won’t be hard to get around anyway.

So far, I’ve personally been doing the latter. I’m sure there
will come a time when something needs to be done about this, but I
don’t think the sky is falling just yet. Someone probably need to
spend a day or so looking through similar systems to see how it’s
done.


It’s interesting to work on a project that you hope everyone
in your "community" will use while also being a user yourself. If
I were doing an editor or a piece of weblog software, I could just make
decisions based on how I would like to use it. But since we’re
trying to create software to pervade throughout the Ruby community, we have
to do things (sort of) by committee. It’s much harder to justify a
unilateral decision, which creates a different tone during development.

RubyGems is an interesting project, because it’s useless
unless it becomes the standard.

So, Ruby programmers, please download RubyGems
0.3.0
and install it. Install some gems and use them, and then make
gems
of your own libraries and send them in. If you don’t have
libraries to make gems of, make some gems out of other people’s
libraries and send the gemspecs to the authors. Ruby needs a
standardized package management system. This problem is 20% technical and
80% social. Every little bit can help.