Ruby "gem generate" broken with Builder 3.0.0

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

We use gem generate to run our own gem server. When we create a new gem, we run the gem generate command to refresh all the server indexes.

We just found a problem:

  $ 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?

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

Recommendation: gem authors should use gem versions

Be on the lookout for incompatibilities due to gem versions, and if you are a gem author then please use gem versions: when you require a gem, specify the version number that you want.



What's Next?

blog comments powered by Disqus