It has really been a long time since I last talked about Ruby; this has been mostly due to my dayjob bringing me further and further away from Ruby – until now at least – so that I didn’t really have time to help the Gentoo Ruby team keep up with the maintenance. I came back to this world in the past few weeks because of two of my customers (a custom web application and a user-editable website), and as usual I’m here to rant.
I could be ranting about Rails 3, and its documentation that declares one thing when the code does a very different one, but I’ll leave that for a different time. I could rant about Radiant documentation being even worse, and the fact that every other extension for it has trouble to work with the latest code.. but that’s a story to long to complete here.
So I’ll start with ranting about Bundler.
For those who do not know and would prefer not guessing, Bundler is a Ruby gem that was initially designed to make it easier to bundle (or, as they wanted to call it for a while, “vendorize”) other gems, so that you wouldn’t have to worry about the interface you used, the monkeypatching you did, or any customization at all. Since you probably know me well enough, you know that it didn’t really make me happy and proud of Ruby.
Thankfully, it seems like someone at some point wondered “Are we sure of what we’re doing?” and decided to make it behave in a saner way for what distributions are concerned, by making it possible to satisfy the bundled-gems requirement through other installed gems. Phew!
While Gentoo still prefers not dealing with bundler, if at a ll possible, it’s not as bi a deal as it was before. And in some ways, it’s a bit nicer, especially when you’re dealing with Rails applications, such as Radiant, to restrict the rubygems installed gems to the one directory, rather than litter the filesystem with them. And it provides with at least a quick way to check what the original developers intended you to use their code with (in term of gems and versions).
Interestingly enough, when you use an actual bundler-powered project, its wrapping around of requirements also make sure that only the gems that are requested are actually used. This is quite an improvement over the default handling of dependencies in gems, and I salute it happily indeed. This got tricky with my fakegem approach as the original implementation ignored the original gem’s metadata, which included its dependencies, which is required for bundler to have a good idea of the dependency tree for the project. Luckily for me, Hans and Alex tackled the issue, and now as much metadata as possible is kept from the original gems when installing our “fake” copies.
Unfortunately, that’s only one of the issues: the other is that a number of projects are not actually writing their specifications properly. One of these projects .. is Rails. At least the 2.3 branch. Indeed I was hitting issues trying to bump Radiant to the 1.0.0rc3 version, and I couldn’t figure out why.. googling for the kind of error message I was receiving (something about inheritable attributes) only turned up issues of people unable to load activesupport due to missing iconv library … well, they were half right in my situation. When I tried reproducing the issue with
irb I couldn’t.. and the reason was relatively easy to find, once I actually looked through the code being looked up… Bundler couldn’t load activesupport because it tried to load i18n, which was not in the calculated tree.
It is true that this is not fully Rails Project fault, as the original activesupport gem wouldn’t need the i18n gem — but the version we install has that gem (and a couple more) “un-vendorized”, or to call it with its name, unbundled. Instead they are brought in as dependencies. But up to the other day, those dependencies weren’t listed in the specifications. A quick patch afterward, and this is now solved, and indeed Radiant works nicely.
Unfortunately, this brought up a secondary issue related to bundler and its Gemfile support. In some software, such as Radiant is, you can’t simply get rid of Bundler, nor you can remove its
Gemfile, as it is part of the interface that it uses even to produce the skeleton application for the websites. In these cases, we have to generate during the ebuild compile phase, the companion file
Gemfile.lock. While the first file lists the dependencies’ version requirements (minimum, maximum and range), the other lists the exact version that was found of each gem, and allows no other version to be used. This for good or bad, a similar situation as the soname lockdown that we know from ELF files.. and might actually require us to either write a tool similar to
revdep-rebuild for these Gemfiles — or we could consider getting a modular, single tool to handle rebuilds for the next Google Summer of Code… it would replace
python-updater and the like…
Okay, I guess after this rant I can go back at working on setting up the Radiant instance for my customer, and getting the extensions to play well together — before writing my own extension to give him access to a few more personal features. Uff.