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

Public Class methods

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

[Source]

    # File lib/rubygems/source_index.rb, line 65
65:     def from_gems_in(*spec_dirs)
66:       self.new.load_gems_in(*spec_dirs)
67:     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 46
46:     def from_installed_gems(*deprecated)
47:       if deprecated.empty?
48:         from_gems_in(*installed_spec_directories)
49:       else
50:         from_gems_in(*deprecated) # HACK warn
51:       end
52:     end

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

[Source]

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

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

[Source]

    # File lib/rubygems/source_index.rb, line 73
73:     def load_specification(file_name)
74:       begin
75:         spec_code = File.read(file_name).untaint
76:         gemspec = eval spec_code, binding, file_name
77:         if gemspec.is_a?(Gem::Specification)
78:           gemspec.loaded_from = file_name
79:           return gemspec
80:         end
81:         alert_warning "File '#{file_name}' does not evaluate to a gem specification"
82:       rescue SyntaxError => e
83:         alert_warning e
84:         alert_warning spec_code
85:       rescue Exception => e
86:         alert_warning(e.inspect.to_s + "\n" + spec_code)
87:         alert_warning "Invalid .gemspec format in '#{file_name}'"
88:       end
89:       return nil
90:     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 101
101:   def initialize(specifications={})
102:     @gems = specifications
103:   end

Public Instance methods

Add a gem specification to the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 160
160:   def add_spec(gem_spec)
161:     @gems[gem_spec.full_name] = gem_spec
162:   end

Add gem specifications to the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 167
167:   def add_specs(*gem_specs)
168:     gem_specs.each do |spec|
169:       add_spec spec
170:     end
171:   end

[Source]

     # File lib/rubygems/source_index.rb, line 343
343:   def dump
344:     Marshal.dump(self)
345:   end

Iterate over the specifications in the source index.

[Source]

     # File lib/rubygems/source_index.rb, line 183
183:   def each(&block) # :yields: gem.full_name, gem
184:     @gems.each(&block)
185:   end

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

[Source]

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

The signature for the given gem specification.

[Source]

     # File lib/rubygems/source_index.rb, line 207
207:   def gem_signature(gem_full_name)
208:     require 'rubygems/digest/sha2'
209: 
210:     Gem::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s
211:   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 198
198:   def index_signature
199:     require 'rubygems/digest/sha2'
200: 
201:     Gem::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s
202:   end

Returns a Hash of name => Specification of the latest versions of each gem in this index.

[Source]

     # File lib/rubygems/source_index.rb, line 127
127:   def latest_specs
128:     result = Hash.new { |h,k| h[k] = [] }
129:     latest = {}
130: 
131:     sort.each do |_, spec|
132:       name = spec.name
133:       curr_ver = spec.version
134:       prev_ver = latest.key?(name) ? latest[name].version : nil
135: 
136:       next unless prev_ver.nil? or curr_ver >= prev_ver or
137:                   latest[name].platform != Gem::Platform::RUBY
138: 
139:       if prev_ver.nil? or
140:          (curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then
141:         result[name].clear
142:         latest[name] = spec
143:       end
144: 
145:       if spec.platform != Gem::Platform::RUBY then
146:         result[name].delete_if do |result_spec|
147:           result_spec.platform == spec.platform
148:         end
149:       end
150: 
151:       result[name] << spec
152:     end
153: 
154:     result.values.flatten
155:   end
length()

Alias for size

Reconstruct the source index from the specifications in spec_dirs.

[Source]

     # File lib/rubygems/source_index.rb, line 108
108:   def load_gems_in(*spec_dirs)
109:     @gems.clear
110: 
111:     spec_dirs.reverse_each do |spec_dir|
112:       spec_files = Dir.glob File.join(spec_dir, '*.gemspec')
113: 
114:       spec_files.each do |spec_file|
115:         gemspec = self.class.load_specification spec_file.untaint
116:         add_spec gemspec if gemspec
117:       end
118:     end
119: 
120:     self
121:   end

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

[Source]

     # File lib/rubygems/source_index.rb, line 283
283:   def outdated
284:     dep = Gem::Dependency.new '', Gem::Requirement.default
285: 
286:     remotes = Gem::SourceInfoCache.search dep, true
287: 
288:     outdateds = []
289: 
290:     latest_specs.each do |local|
291:       name = local.name
292:       remote = remotes.select { |spec| spec.name == name }.
293:         sort_by { |spec| spec.version.to_ints }.
294:         last
295: 
296:       outdateds << name if remote and local.version < remote.version
297:     end
298: 
299:     outdateds
300:   end

Replaces the gems in the source index from specifications in the installed_spec_directories,

[Source]

     # File lib/rubygems/source_index.rb, line 276
276:   def refresh!
277:     load_gems_in(*self.class.installed_spec_directories)
278:   end

Remove a gem specification named full_name.

[Source]

     # File lib/rubygems/source_index.rb, line 176
176:   def remove_spec(full_name)
177:     @gems.delete(full_name)
178:   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 234
234:   def search(gem_pattern, platform_only = false)
235:     version_requirement = nil
236:     only_platform = false
237: 
238:     case gem_pattern # TODO warn after 2008/03, remove three months after
239:     when Regexp then
240:       version_requirement = platform_only || Gem::Requirement.default
241:     when Gem::Dependency then
242:       only_platform = platform_only
243:       version_requirement = gem_pattern.version_requirements
244:       gem_pattern = if gem_pattern.name.empty? then
245:                       //
246:                     else
247:                       /^#{Regexp.escape gem_pattern.name}$/
248:                     end
249:     else
250:       version_requirement = platform_only || Gem::Requirement.default
251:       gem_pattern = /^#{gem_pattern}/i
252:     end
253: 
254:     unless Gem::Requirement === version_requirement then
255:       version_requirement = Gem::Requirement.create version_requirement
256:     end
257: 
258:     specs = @gems.values.select do |spec|
259:       spec.name =~ gem_pattern and
260:       version_requirement.satisfied_by? spec.version
261:     end
262: 
263:     if only_platform then
264:       specs = specs.select do |spec|
265:         Gem::Platform.match spec.platform
266:       end
267:     end
268: 
269:     specs.sort_by { |s| s.sort_obj }
270:   end

[Source]

     # File lib/rubygems/source_index.rb, line 213
213:   def size
214:     @gems.size
215:   end

The gem specification given a full gem spec name.

[Source]

     # File lib/rubygems/source_index.rb, line 190
190:   def specification(full_name)
191:     @gems[full_name]
192:   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 306
306:   def update(source_uri, all)
307:     source_uri = URI.parse source_uri unless URI::Generic === source_uri
308:     source_uri.path += '/' unless source_uri.path =~ /\/$/
309: 
310:     use_incremental = false
311: 
312:     begin
313:       gem_names = fetch_quick_index source_uri, all
314:       remove_extra gem_names
315:       missing_gems = find_missing gem_names
316: 
317:       return false if missing_gems.size.zero?
318: 
319:       say "Missing metadata for #{missing_gems.size} gems" if
320:       missing_gems.size > 0 and Gem.configuration.really_verbose
321: 
322:       use_incremental = missing_gems.size <= Gem.configuration.bulk_threshold
323:     rescue Gem::OperationNotSupportedError => ex
324:       alert_error "Falling back to bulk fetch: #{ex.message}" if
325:       Gem.configuration.really_verbose
326:       use_incremental = false
327:     end
328: 
329:     if use_incremental then
330:       update_with_missing(source_uri, missing_gems)
331:     else
332:       new_index = fetch_bulk_index(source_uri)
333:       @gems.replace(new_index.gems)
334:     end
335: 
336:     true
337:   end

[Validate]