Ruby "gem generate" indexer broken with XML Builder 3.0.0
In which rubygems breaks compatibility, botches documentation, and fails to require specific gem versions.
The ruby "gem generate" command has a problem with the new XML Builder 3.0.0 gem.
== Symptom: gem generate fails because it's missing XML Builder
$ gem generate
ERROR: While executing gem ... (RuntimeError)
Gem::Indexer requires that the XML Builder library be installed:
gem install builder
We try this:
$ gem install builder
We verify that builder is now installed:
$ gem list builder
builder (3.0.0)
But gem generate still fails with the same error message. How is this possible?
== Invesigation: indexer needs builder/xchar and to_xs method
Digging into rubygem source code, we find the error message come from in this file:
/rubygems/indexer.rb
The indexer initialize method tests for the XChar to_xs method:
def initialize(directory)
unless ''.respond_to? :to_xs then
fail "Gem::Indexer requires that the XML Builder library be installed:" \
The indexer requires the Builder XChar library so it should work:
gem 'builder'
require 'builder/xchar'
So we dig into the Builder source code...
== How Builder does encoding and monkey patching
Builder does define the to_xs method, but only some of the time.
Builder does conditional definition of a big chunk of code:
if String.method_defined?(:encode)
... new approach using encoding ...
else
... old approach using monkey patching ...
class String
...
def to_xs(escape=true)
Essentially, Builder wants to define methods in terms of string encoding, but will fall back to monkey-patching the Ruby String class to define to_xs.
We look through the commits to Builder and we see that an older version of Builder does things differently: it always monkey-patches String and always defines to_xs.
== Solution: Edit Ruby gem to require the older Builder
We edit the Ruby gem source code to make it require the older Builder:
gem 'builder', '~> 2.1'
require 'builder/xchar'
Success!
$ gem generate
Loading 50 gems from ...
Loaded all gems
Moral of the story: don't trust Ruby gem error messages, be on the lookout for incompatibilities due to gem versions, and if you are a gem author then please require gems with version numbers.