Class Gem::SourceIndex
In: lib/rubygems/source_index.rb
Parent: Object

The SourceIndex object indexes all the gems available from a particular source (e.g. a list of gem directories, or a remote source). A SourceIndex maps a gem full name to a gem specification.

NOTE:The class used to be named Cache, but that became confusing when cached source fetchers where introduced. The constant Gem::Cache is an alias for this class to allow old YAMLized source index objects to load properly.

Methods

Included Modules

Enumerable Gem::UserInteraction Gem::UserInteraction

Attributes

spec_dirs  [RW]  Directories to use to refresh this SourceIndex when calling refresh!

Public Class methods

Creates a new SourceIndex from the ruby format gem specifications in spec_dirs.

[Source]

    # File lib/rubygems/source_index.rb, line 71
71:     def from_gems_in(*spec_dirs)
72:       source_index = new
73:       source_index.spec_dirs = spec_dirs
74:       source_index.refresh!
75:     end

Factory method to construct a source index instance for a given path.

deprecated:If supplied, from_installed_gems will act just like from_gems_in. This argument is deprecated and is provided just for backwards compatibility, and should not generally be used.
return:SourceIndex instance

[Source]

    # File lib/rubygems/source_index.rb, line 52
52:     def from_installed_gems(*deprecated)
53:       if deprecated.empty?
54:         from_gems_in(*installed_spec_directories)
55:       else
56:         from_gems_in(*deprecated) # HACK warn
57:       end
58:     end

Returns a list of directories from Gem.path that contain specifications.

[Source]

    # File lib/rubygems/source_index.rb, line 63
63:     def installed_spec_directories
64:       Gem.path.collect { |dir| File.join(dir, "specifications") }
65:     end

Loads a ruby-format specification from file_name and returns the loaded spec.

[Source]

     # File lib/rubygems/source_index.rb, line 81
 81:     def load_specification(file_name)
 82:       begin
 83:         spec_code = File.read(file_name).untaint
 84:         gemspec = eval spec_code, binding, file_name
 85:         if gemspec.is_a?(Gem::Specification)
 86:           gemspec.loaded_from = file_name
 87:           return gemspec
 88:         end
 89:         alert_warning "File '#{file_name}' does not evaluate to a gem specification"
 90:       rescue SignalException, SystemExit
 91:         raise
 92:       rescue SyntaxError => e
 93:         alert_warning e
 94:         alert_warning spec_code
 95:       rescue Exception => e
 96:         alert_warning(e.inspect.to_s + "\n" + spec_code)
 97:         alert_warning "Invalid .gemspec format in '#{file_name}'"
 98:       end
 99:       return nil
100:     end

Constructs a source index instance from the provided specifications

specifications:[Hash] hash of [Gem name, Gem::Specification] pairs

[Source]

     # File lib/rubygems/source_index.rb, line 111
111:   def initialize(specifications={})
112:     @gems = specifications
113:     @spec_dirs = nil
114:   end

Public Instance methods

Add a gem specification to the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 171
171:   def add_spec(gem_spec)
172:     @gems[gem_spec.full_name] = gem_spec
173:   end

Add gem specifications to the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 178
178:   def add_specs(*gem_specs)
179:     gem_specs.each do |spec|
180:       add_spec spec
181:     end
182:   end

[Source]

     # File lib/rubygems/source_index.rb, line 368
368:   def dump
369:     Marshal.dump(self)
370:   end

Iterate over the specifications in the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 194
194:   def each(&block) # :yields: gem.full_name, gem
195:     @gems.each(&block)
196:   end

Find a gem by an exact match on the short name.

[Source]

     # File lib/rubygems/source_index.rb, line 232
232:   def find_name(gem_name, version_requirement = Gem::Requirement.default)
233:     search(/^#{gem_name}$/, version_requirement)
234:   end

The signature for the given gem specification.

[Source]

     # File lib/rubygems/source_index.rb, line 218
218:   def gem_signature(gem_full_name)
219:     require 'rubygems/digest/sha2'
220: 
221:     Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
222:   end

The signature for the source index. Changes in the signature indicate a change in the index.

[Source]

     # File lib/rubygems/source_index.rb, line 209
209:   def index_signature
210:     require 'rubygems/digest/sha2'
211: 
212:     Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
213:   end

Returns an Array specifications for the latest versions of each gem in this index.

[Source]

     # File lib/rubygems/source_index.rb, line 138
138:   def latest_specs
139:     result = Hash.new { |h,k| h[k] = [] }
140:     latest = {}
141: 
142:     sort.each do |_, spec|
143:       name = spec.name
144:       curr_ver = spec.version
145:       prev_ver = latest.key?(name) ? latest[name].version : nil
146: 
147:       next unless prev_ver.nil? or curr_ver >= prev_ver or
148:                   latest[name].platform != Gem::Platform::RUBY
149: 
150:       if prev_ver.nil? or
151:          (curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
152:         result[name].clear
153:         latest[name] = spec
154:       end
155: 
156:       if spec.platform != Gem::Platform::RUBY then
157:         result[name].delete_if do |result_spec|
158:           result_spec.platform == spec.platform
159:         end
160:       end
161: 
162:       result[name] << spec
163:     end
164: 
165:     result.values.flatten
166:   end
length()

Alias for size

Reconstruct the source index from the specifications in spec_dirs.

[Source]

     # File lib/rubygems/source_index.rb, line 119
119:   def load_gems_in(*spec_dirs)
120:     @gems.clear
121: 
122:     spec_dirs.reverse_each do |spec_dir|
123:       spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
124: 
125:       spec_files.each do |spec_file|
126:         gemspec = self.class.load_specification spec_file.untaint
127:         add_spec gemspec if gemspec
128:       end
129:     end
130: 
131:     self
132:   end

Returns an Array of Gem::Specifications that are not up to date.

[Source]

     # File lib/rubygems/source_index.rb, line 299
299:   def outdated
300:     outdateds = []
301: 
302:     latest_specs.each do |local|
303:       dependency = Gem::Dependency.new local.name, ">= #{local.version}"
304: 
305:       begin
306:         fetcher = Gem::SpecFetcher.fetcher
307:         remotes = fetcher.find_matching dependency
308:         remotes = remotes.map { |(name, version,_),_| version }
309:       rescue Gem::RemoteFetcher::FetchError => e
310:         raise unless fetcher.warn_legacy e do
311:           require 'rubygems/source_info_cache'
312: 
313:           specs = Gem::SourceInfoCache.search_with_source dependency, true
314: 
315:           remotes = specs.map { |spec,| spec.version }
316:         end
317:       end
318: 
319:       latest = remotes.sort.last
320: 
321:       outdateds << local.name if latest and local.version < latest
322:     end
323: 
324:     outdateds
325:   end

Replaces the gems in the source index from specifications in the directories this source index was created from. Raises an exception if this source index wasn‘t created from a directory (via from_gems_in or from_installed_gems, or having spec_dirs set).

[Source]

     # File lib/rubygems/source_index.rb, line 291
291:   def refresh!
292:     raise 'source index not created from disk' if @spec_dirs.nil?
293:     load_gems_in(*@spec_dirs)
294:   end

Remove a gem specification named full_name.

[Source]

     # File lib/rubygems/source_index.rb, line 187
187:   def remove_spec(full_name)
188:     @gems.delete(full_name)
189:   end

Search for a gem by Gem::Dependency gem_pattern. If only_platform is true, only gems matching Gem::Platform.local will be returned. An Array of matching Gem::Specification objects is returned.

For backwards compatibility, a String or Regexp pattern may be passed as gem_pattern, and a Gem::Requirement for platform_only. This behavior is deprecated and will be removed.

[Source]

     # File lib/rubygems/source_index.rb, line 245
245:   def search(gem_pattern, platform_only = false)
246:     version_requirement = nil
247:     only_platform = false
248: 
249:     case gem_pattern # TODO warn after 2008/03, remove three months after
250:     when Regexp then
251:       version_requirement = platform_only || Gem::Requirement.default
252:     when Gem::Dependency then
253:       only_platform = platform_only
254:       version_requirement = gem_pattern.version_requirements
255:       gem_pattern = if Regexp === gem_pattern.name then
256:                       gem_pattern.name
257:                     elsif gem_pattern.name.empty? then
258:                       //
259:                     else
260:                       /^#{Regexp.escape gem_pattern.name}$/
261:                     end
262:     else
263:       version_requirement = platform_only || Gem::Requirement.default
264:       gem_pattern = /^#{gem_pattern}/i
265:     end
266: 
267:     unless Gem::Requirement === version_requirement then
268:       version_requirement = Gem::Requirement.create version_requirement
269:     end
270: 
271:     specs = @gems.values.select do |spec|
272:       spec.name =~ gem_pattern and
273:       version_requirement.satisfied_by? spec.version
274:     end
275: 
276:     if only_platform then
277:       specs = specs.select do |spec|
278:         Gem::Platform.match spec.platform
279:       end
280:     end
281: 
282:     specs.sort_by { |s| s.sort_obj }
283:   end

[Source]

     # File lib/rubygems/source_index.rb, line 224
224:   def size
225:     @gems.size
226:   end

The gem specification given a full gem spec name.

[Source]

     # File lib/rubygems/source_index.rb, line 201
201:   def specification(full_name)
202:     @gems[full_name]
203:   end

Updates this SourceIndex from source_uri. If all is false, only the latest gems are fetched.

[Source]

     # File lib/rubygems/source_index.rb, line 331
331:   def update(source_uri, all)
332:     source_uri = URI.parse source_uri unless URI::Generic === source_uri
333:     source_uri.path += '/' unless source_uri.path =~ /\/$/
334: 
335:     use_incremental = false
336: 
337:     begin
338:       gem_names = fetch_quick_index source_uri, all
339:       remove_extra gem_names
340:       missing_gems = find_missing gem_names
341: 
342:       return false if missing_gems.size.zero?
343: 
344:       say "Missing metadata for #{missing_gems.size} gems" if
345:       missing_gems.size > 0 and Gem.configuration.really_verbose
346: 
347:       use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
348:     rescue Gem::OperationNotSupportedError => ex
349:       alert_error "Falling back to bulk fetch: #{ex.message}" if
350:       Gem.configuration.really_verbose
351:       use_incremental = false
352:     end
353: 
354:     if use_incremental then
355:       update_with_missing(source_uri, missing_gems)
356:     else
357:       new_index = fetch_bulk_index(source_uri)
358:       @gems.replace(new_index.gems)
359:     end
360: 
361:     true
362:   end

[Validate]