A closer look at ruby gems

Have you ever been stuck at "Bulk updating Gem source index for http://gems.rubyforge.org/" while installing a gem?!Due the to the latest drop in the Internet connectivity in the middle east and my own country, Egypt, installing gems started to be like hell.. I had to wait for hours before having my library installed so I decided to have a closer look. surprisingly.. it was due to a bug in rubygems 1.0.1.

You can easily overcome this by updating to the latest gem 1.3.1 through gem update --system

Gem downloads libraries metadata about all available gems in a gem server. by default we have gem source "http://gems.rubyforge.org/" and recently i added "http://gems.github.com".gem saves this data in a cache file before it performs the required operation, so it doesn't have to download it again the next time.

Part of the code that reads the cache looks like this:

MARSHAL_FIELDS = { -1 => 16, 1 => 16, 2 => 16 }
# Load custom marshal format, re-initializing defaults as needed
def self._load(str)
   array = Marshal.load str

   spec = Gem::Specification.new
   spec.instance_variable_set :@specification_version, array[1]


   field_count = MARSHAL_FIELDS[spec.specification_version]

   if field_count.nil? or array.size < field_count then
      raise TypeError, "invalid Gem::Specification format #{array.inspect}"

That above load method is executed to load and validate the metadata of each library from the cache unless an exception is thrown. field_count represents the expected number of attributes per gem according the that gem specification version (either -1, 1, 2 but it is 16 in all cases). the keys of the MARSHAL_FIELDS hash are numbers. but the spec.specification_version is string representation of that number. so MARSHAL_FIELDS[spec.specification_version] is always nil.

Changing it to MARSHAL_FIELDS[spec.specification_version.to_i] made the rubygems work like any civilized tool :).


Popular posts from this blog

Ruby script for downloading rails casts

Stress Testing with Siege and Bombard, know your limits

Exporting data from remote mysql instance in csv, using mysql client and sed