Extended maintenance of Ruby 1.9.3 ended on February 23, 2015. Read more
SpecFetcher handles metadata updates from remote gem repositories.
# File rubygems/spec_fetcher.rb, line 42 def self.fetcher @fetcher ||= new end
# File rubygems/spec_fetcher.rb, line 50 def initialize require 'fileutils' @dir = File.join Gem.user_home, '.gem', 'specs' @update_cache = File.stat(Gem.user_home).uid == Process.uid @specs = {} @latest_specs = {} @prerelease_specs = {} @caches = { :latest => @latest_specs, :prerelease => @prerelease_specs, :all => @specs } @fetcher = Gem::RemoteFetcher.fetcher end
Returns the local directory to write uri
to.
# File rubygems/spec_fetcher.rb, line 72 def cache_dir(uri) # Correct for windows paths escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\1-/') File.join @dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path) end
# File rubygems/spec_fetcher.rb, line 101 def fetch(*args) fetch_with_errors(*args).first end
# File rubygems/spec_fetcher.rb, line 105 def fetch_spec(spec, source_uri) source_uri = URI.parse source_uri if String === source_uri spec = spec - [nil, 'ruby', ''] spec_file_name = "#{spec.join '-'}.gemspec" uri = source_uri + "#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}" cache_dir = cache_dir uri local_spec = File.join cache_dir, spec_file_name if File.exist? local_spec then spec = Gem.read_binary local_spec else uri.path << '.rz' spec = @fetcher.fetch_path uri spec = Gem.inflate spec if @update_cache then FileUtils.mkdir_p cache_dir open local_spec, 'wb' do |io| io.write spec end end end # TODO: Investigate setting Gem::Specification#loaded_from to a URI Marshal.load spec end
Fetch specs matching dependency
. If all
is true,
all matching (released) versions are returned. If
matching_platform
is false, all platforms are returned. If
prerelease
is true, prerelease versions are included.
# File rubygems/spec_fetcher.rb, line 84 def fetch_with_errors(dependency, all = false, matching_platform = true, prerelease = false) specs_and_sources, errors = find_matching_with_errors(dependency, all, matching_platform, prerelease) ss = specs_and_sources.map do |spec_tuple, source_uri| [fetch_spec(spec_tuple, URI.parse(source_uri)), source_uri] end return [ss, errors] end
# File rubygems/spec_fetcher.rb, line 176 def find_matching(*args) find_matching_with_errors(*args).first end
Find spec names that match dependency
. If all
is
true, all matching released versions are returned. If
matching_platform
is false, gems for all platforms are
returned.
# File rubygems/spec_fetcher.rb, line 142 def find_matching_with_errors(dependency, all = false, matching_platform = true, prerelease = false) found = {} rejected_specs = {} list(all, prerelease).each do |source_uri, specs| found[source_uri] = specs.select do |spec_name, version, spec_platform| if dependency.match?(spec_name, version) if matching_platform and !Gem::Platform.match(spec_platform) pm = (rejected_specs[dependency] ||= Gem::PlatformMismatch.new(spec_name, version)) pm.add_platform spec_platform false else true end end end end errors = rejected_specs.values specs_and_sources = [] found.each do |source_uri, specs| uri_str = source_uri.to_s specs_and_sources.concat(specs.map { |spec| [spec, uri_str] }) end [specs_and_sources, errors] end
Returns a list of gems available for each source in Gem.sources. If all
is true, all released versions are returned instead of only latest
versions. If prerelease
is true, include prerelease versions.
# File rubygems/spec_fetcher.rb, line 213 def list(all = false, prerelease = false) # TODO: make type the only argument type = if all :all elsif prerelease :prerelease else :latest end list = {} file = FILES[type] cache = @caches[type] Gem.sources.each do |source_uri| source_uri = URI.parse source_uri unless cache.include? source_uri cache[source_uri] = load_specs source_uri, file end list[source_uri] = cache[source_uri] end if type == :all list.values.map do |gems| gems.reject! { |g| !g[1] || g[1].prerelease? } end end list end
Loads specs in file
, fetching from source_uri
if
the on-disk cache is out of date.
# File rubygems/spec_fetcher.rb, line 250 def load_specs(source_uri, file) file_name = "#{file}.#{Gem.marshal_version}" spec_path = source_uri + "#{file_name}.gz" cache_dir = cache_dir spec_path local_file = File.join(cache_dir, file_name) loaded = false if File.exist? local_file then begin spec_dump = @fetcher.fetch_path(spec_path, File.mtime(local_file)) rescue Gem::RemoteFetcher::FetchError => e alert_warning "Error fetching data: #{e.message}" end loaded = true if spec_dump spec_dump ||= Gem.read_binary local_file else spec_dump = @fetcher.fetch_path spec_path loaded = true end specs = begin Marshal.load spec_dump rescue ArgumentError spec_dump = @fetcher.fetch_path spec_path loaded = true Marshal.load spec_dump end if loaded and @update_cache then begin FileUtils.mkdir_p cache_dir open local_file, 'wb' do |io| io << spec_dump end rescue end end specs end
Suggests a gem based on the supplied gem_name
. Returns a
string of the gem name if an approximate match can be found or nil
otherwise. NOTE: for performance reasons only gems which exactly match the
first character of gem_name
are considered.
# File rubygems/spec_fetcher.rb, line 186 def suggest_gems_from_name gem_name gem_name = gem_name.downcase max = gem_name.size / 2 specs = list.values.flatten 1 matches = specs.map { |name, version, platform| next unless Gem::Platform.match platform distance = levenshtein_distance gem_name, name.downcase next if distance >= max return [name] if distance == 0 [name, distance] }.compact matches = matches.uniq.sort_by { |name, dist| dist } matches.first(5).map { |name, dist| name } end
Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.
If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.
If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.
If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.