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 73
73:     def from_gems_in(*spec_dirs)
74:       source_index = new
75:       source_index.spec_dirs = spec_dirs
76:       source_index.refresh!
77:     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 54
54:     def from_installed_gems(*deprecated)
55:       if deprecated.empty?
56:         from_gems_in(*installed_spec_directories)
57:       else
58:         from_gems_in(*deprecated) # HACK warn
59:       end
60:     end

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

[Source]

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

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

[Source]

     # File lib/rubygems/source_index.rb, line 83
 83:     def load_specification(file_name)
 84:       begin
 85:         spec_code = if RUBY_VERSION < '1.9' then
 86:                       File.read file_name
 87:                     else
 88:                       File.read file_name, :encoding => 'UTF-8'
 89:                     end.untaint
 90: 
 91:         gemspec = eval spec_code, binding, file_name
 92: 
 93:         if gemspec.is_a?(Gem::Specification)
 94:           gemspec.loaded_from = file_name
 95:           return gemspec
 96:         end
 97:         alert_warning "File '#{file_name}' does not evaluate to a gem specification"
 98:       rescue SignalException, SystemExit
 99:         raise
100:       rescue SyntaxError => e
101:         alert_warning e
102:         alert_warning spec_code
103:       rescue Exception => e
104:         alert_warning "#{e.inspect}\n#{spec_code}"
105:         alert_warning "Invalid .gemspec format in '#{file_name}'"
106:       end
107:       return nil
108:     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 119
119:   def initialize(specifications={})
120:     @gems = specifications
121:     @spec_dirs = nil
122:   end

Public Instance methods

Add a gem specification to the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 179
179:   def add_spec(gem_spec)
180:     @gems[gem_spec.full_name] = gem_spec
181:   end

Add gem specifications to the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 186
186:   def add_specs(*gem_specs)
187:     gem_specs.each do |spec|
188:       add_spec spec
189:     end
190:   end

[Source]

     # File lib/rubygems/source_index.rb, line 382
382:   def dump
383:     Marshal.dump(self)
384:   end

Iterate over the specifications in the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 202
202:   def each(&block) # :yields: gem.full_name, gem
203:     @gems.each(&block)
204:   end

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

[Source]

     # File lib/rubygems/source_index.rb, line 240
240:   def find_name(gem_name, version_requirement = Gem::Requirement.default)
241:     dep = Gem::Dependency.new(/^#{gem_name}$/, version_requirement)
242:     search dep
243:   end

The signature for the given gem specification.

[Source]

     # File lib/rubygems/source_index.rb, line 226
226:   def gem_signature(gem_full_name)
227:     require 'rubygems/digest/sha2'
228: 
229:     Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
230:   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 217
217:   def index_signature
218:     require 'rubygems/digest/sha2'
219: 
220:     Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
221:   end

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

[Source]

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

Alias for size

Reconstruct the source index from the specifications in spec_dirs.

[Source]

     # File lib/rubygems/source_index.rb, line 127
127:   def load_gems_in(*spec_dirs)
128:     @gems.clear
129: 
130:     spec_dirs.reverse_each do |spec_dir|
131:       spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
132: 
133:       spec_files.each do |spec_file|
134:         gemspec = self.class.load_specification spec_file.untaint
135:         add_spec gemspec if gemspec
136:       end
137:     end
138: 
139:     self
140:   end

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

[Source]

     # File lib/rubygems/source_index.rb, line 313
313:   def outdated
314:     outdateds = []
315: 
316:     latest_specs.each do |local|
317:       dependency = Gem::Dependency.new local.name, ">= #{local.version}"
318: 
319:       begin
320:         fetcher = Gem::SpecFetcher.fetcher
321:         remotes = fetcher.find_matching dependency
322:         remotes = remotes.map { |(name, version,_),_| version }
323:       rescue Gem::RemoteFetcher::FetchError => e
324:         raise unless fetcher.warn_legacy e do
325:           require 'rubygems/source_info_cache'
326: 
327:           specs = Gem::SourceInfoCache.search_with_source dependency, true
328: 
329:           remotes = specs.map { |spec,| spec.version }
330:         end
331:       end
332: 
333:       latest = remotes.sort.last
334: 
335:       outdateds << local.name if latest and local.version < latest
336:     end
337: 
338:     outdateds
339:   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 305
305:   def refresh!
306:     raise 'source index not created from disk' if @spec_dirs.nil?
307:     load_gems_in(*@spec_dirs)
308:   end

Remove a gem specification named full_name.

[Source]

     # File lib/rubygems/source_index.rb, line 195
195:   def remove_spec(full_name)
196:     @gems.delete(full_name)
197:   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 254
254:   def search(gem_pattern, platform_only = false)
255:     version_requirement = nil
256:     only_platform = false
257: 
258:     # TODO - Remove support and warning for legacy arguments after 2008/11
259:     unless Gem::Dependency === gem_pattern
260:       warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated"
261:     end
262: 
263:     case gem_pattern
264:     when Regexp then
265:       version_requirement = platform_only || Gem::Requirement.default
266:     when Gem::Dependency then
267:       only_platform = platform_only
268:       version_requirement = gem_pattern.version_requirements
269:       gem_pattern = if Regexp === gem_pattern.name then
270:                       gem_pattern.name
271:                     elsif gem_pattern.name.empty? then
272:                       //
273:                     else
274:                       /^#{Regexp.escape gem_pattern.name}$/
275:                     end
276:     else
277:       version_requirement = platform_only || Gem::Requirement.default
278:       gem_pattern = /^#{gem_pattern}/i
279:     end
280: 
281:     unless Gem::Requirement === version_requirement then
282:       version_requirement = Gem::Requirement.create version_requirement
283:     end
284: 
285:     specs = @gems.values.select do |spec|
286:       spec.name =~ gem_pattern and
287:         version_requirement.satisfied_by? spec.version
288:     end
289: 
290:     if only_platform then
291:       specs = specs.select do |spec|
292:         Gem::Platform.match spec.platform
293:       end
294:     end
295: 
296:     specs.sort_by { |s| s.sort_obj }
297:   end

[Source]

     # File lib/rubygems/source_index.rb, line 232
232:   def size
233:     @gems.size
234:   end

The gem specification given a full gem spec name.

[Source]

     # File lib/rubygems/source_index.rb, line 209
209:   def specification(full_name)
210:     @gems[full_name]
211:   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 345
345:   def update(source_uri, all)
346:     source_uri = URI.parse source_uri unless URI::Generic === source_uri
347:     source_uri.path += '/' unless source_uri.path =~ /\/$/
348: 
349:     use_incremental = false
350: 
351:     begin
352:       gem_names = fetch_quick_index source_uri, all
353:       remove_extra gem_names
354:       missing_gems = find_missing gem_names
355: 
356:       return false if missing_gems.size.zero?
357: 
358:       say "Missing metadata for #{missing_gems.size} gems" if
359:       missing_gems.size > 0 and Gem.configuration.really_verbose
360: 
361:       use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
362:     rescue Gem::OperationNotSupportedError => ex
363:       alert_error "Falling back to bulk fetch: #{ex.message}" if
364:       Gem.configuration.really_verbose
365:       use_incremental = false
366:     end
367: 
368:     if use_incremental then
369:       update_with_missing(source_uri, missing_gems)
370:     else
371:       new_index = fetch_bulk_index(source_uri)
372:       @gems.replace(new_index.gems)
373:     end
374: 
375:     true
376:   end

[Validate]