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:
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.
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.
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.
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
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.
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.
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.