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]
current_version = CURRENT_SPECIFICATION_VERSION
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}"
end
...
end
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 :).
Comments