aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2022-04-28 17:15:43 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2022-04-28 19:08:49 +0900
commit1056489ea3e1c3f201936666b2725bfc142bb0f2 (patch)
treecc993148b660f7cc2d92823ccfafcf10d3009c0a
parentcd2410f9d8c99fd0fbb232eb5f195188fbfc122f (diff)
downloadruby-1056489ea3e1c3f201936666b2725bfc142bb0f2.tar.gz
Merge https://github.com/rubygems/rubygems/commit/3f7d0352e84b29d4a2d4cd93b31e5ebdb5f79cc6
-rw-r--r--lib/bundler/definition.rb19
-rw-r--r--lib/bundler/resolver.rb87
-rw-r--r--lib/bundler/resolver/spec_group.rb4
-rw-r--r--lib/bundler/ruby_version.rb13
-rw-r--r--lib/bundler/rubygems_ext.rb17
-rw-r--r--lib/bundler/source/metadata.rb2
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb2
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/errors.rb58
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb2
-rw-r--r--lib/bundler/vendor/tsort/lib/tsort.rb637
-rw-r--r--lib/rubygems.rb4
-rw-r--r--lib/rubygems/optparse/lib/optparse.rb77
-rw-r--r--lib/rubygems/optparse/lib/optparse/ac.rb2
-rw-r--r--lib/rubygems/optparse/lib/optparse/date.rb2
-rw-r--r--lib/rubygems/optparse/lib/optparse/kwargs.rb2
-rw-r--r--lib/rubygems/optparse/lib/optparse/shellwords.rb2
-rw-r--r--lib/rubygems/optparse/lib/optparse/time.rb2
-rw-r--r--lib/rubygems/optparse/lib/optparse/uri.rb2
-rw-r--r--lib/rubygems/specification.rb10
-rw-r--r--spec/bundler/bundler/ruby_version_spec.rb26
-rw-r--r--spec/bundler/commands/lock_spec.rb34
-rw-r--r--spec/bundler/commands/update_spec.rb4
-rw-r--r--spec/bundler/install/gems/resolving_spec.rb37
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb2
-rw-r--r--test/rubygems/helper.rb13
-rw-r--r--test/rubygems/test_gem.rb16
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock8
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock8
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_resolver_installer_set.rb2
31 files changed, 611 insertions, 487 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 09be2db68c..c1d865d049 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -736,30 +736,13 @@ module Bundler
def metadata_dependencies
@metadata_dependencies ||= begin
- ruby_versions = ruby_version_requirements(@ruby_version)
[
- Dependency.new("Ruby\0", ruby_versions),
+ Dependency.new("Ruby\0", RubyVersion.system.gem_version),
Dependency.new("RubyGems\0", Gem::VERSION),
]
end
end
- def ruby_version_requirements(ruby_version)
- return [] unless ruby_version
- if ruby_version.patchlevel
- [ruby_version.to_gem_version_with_patchlevel]
- else
- ruby_version.versions.map do |version|
- requirement = Gem::Requirement.new(version)
- if requirement.exact?
- "~> #{version}.0"
- else
- requirement
- end
- end
- end
- end
-
def expand_dependencies(dependencies, remote = false)
deps = []
dependencies.each do |dep|
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index be0751d9d2..433a5e53e1 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -312,29 +312,66 @@ module Bundler
e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty?
- solver_name = "Bundler"
- possibility_type = "gem"
e.message_with_trees(
- :solver_name => solver_name,
- :possibility_type => possibility_type,
- :reduce_trees => lambda do |trees|
+ :full_message_for_conflict => lambda do |name, conflict|
+ o = if name.end_with?("\0")
+ String.new("Bundler found conflicting requirements for the #{name} version:")
+ else
+ String.new("Bundler could not find compatible versions for gem \"#{name}\":")
+ end
+ o << %(\n)
+ if conflict.locked_requirement
+ o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
+ o << %( #{SharedHelpers.pretty_dependency(conflict.locked_requirement)}\n)
+ o << %(\n)
+ end
+ o << %( In #{name_for_explicit_dependency_source}:\n)
+ trees = conflict.requirement_trees
+
# called first, because we want to reduce the amount of work required to find maximal empty sets
trees = trees.uniq {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } }
# bail out if tree size is too big for Array#combination to make any sense
- return trees if trees.size > 15
- maximal = 1.upto(trees.size).map do |size|
- trees.map(&:last).flatten(1).combination(size).to_a
- end.flatten(1).select do |deps|
- Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
- end.min_by(&:size)
-
- trees.reject! {|t| !maximal.include?(t.last) } if maximal
-
- trees.sort_by {|t| t.reverse.map(&:name) }
- end,
- :printable_requirement => lambda {|req| SharedHelpers.pretty_dependency(req) },
- :additional_message_for_conflict => lambda do |o, name, conflict|
+ if trees.size <= 15
+ maximal = 1.upto(trees.size).map do |size|
+ trees.map(&:last).flatten(1).combination(size).to_a
+ end.flatten(1).select do |deps|
+ Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
+ end.min_by(&:size)
+
+ trees.reject! {|t| !maximal.include?(t.last) } if maximal
+
+ trees.sort_by! {|t| t.reverse.map(&:name) }
+ end
+
+ metadata_requirements = {}
+
+ o << trees.map do |tree|
+ t = "".dup
+ depth = 2
+
+ base_tree = tree.first
+ base_tree_name = base_tree.name
+
+ if base_tree_name.end_with?("\0")
+ metadata_requirements[base_tree_name] = base_tree
+ t = nil
+ else
+ tree.each do |req|
+ t << " " * depth << SharedHelpers.pretty_dependency(req)
+ unless tree.last == req
+ if spec = conflict.activated_by_name[req.name]
+ t << %( was resolved to #{spec.version}, which)
+ end
+ t << %( depends on)
+ end
+ t << %(\n)
+ depth += 1
+ end
+ end
+ t
+ end.compact.join("\n")
+
if name == "bundler"
o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
@@ -355,11 +392,13 @@ module Bundler
o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n"
end
end
+ elsif name.end_with?("\0")
+ o << %(\n Current #{name} version:\n #{SharedHelpers.pretty_dependency(metadata_requirements[name])}\n\n)
elsif conflict.locked_requirement
o << "\n"
o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
o << %(the gems in your Gemfile, which may resolve the conflict.\n)
- elsif !conflict.existing && !name.end_with?("\0")
+ elsif !conflict.existing
o << "\n"
relevant_source = conflict.requirement.source || source_for(name)
@@ -372,14 +411,8 @@ module Bundler
o << gem_not_found_message(name, conflict.requirement, relevant_source, extra_message)
end
- end,
- :version_for_spec => lambda {|spec| spec.version },
- :incompatible_version_message_for_conflict => lambda do |name, _conflict|
- if name.end_with?("\0")
- %(#{solver_name} found conflicting requirements for the #{name} version:)
- else
- %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
- end
+
+ o
end
)
end
diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb
index 232520de77..18ab5a52a3 100644
--- a/lib/bundler/resolver/spec_group.rb
+++ b/lib/bundler/resolver/spec_group.rb
@@ -97,10 +97,10 @@ module Bundler
spec = @specs[platform].first
return [] if spec.is_a?(LazySpecification)
dependencies = []
- if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
+ unless spec.required_ruby_version.none?
dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
end
- if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
+ unless spec.required_rubygems_version.none?
dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform)
end
dependencies
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index d3b7963920..3f51cf4528 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -110,19 +110,6 @@ module Bundler
@ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version)
end
- def to_gem_version_with_patchlevel
- @gem_version_with_patch ||= begin
- Gem::Version.create("#{@gem_version}.#{@patchlevel}")
- rescue ArgumentError
- @gem_version
- end
- end
-
- def exact?
- return @exact if defined?(@exact)
- @exact = versions.all? {|v| Gem::Requirement.create(v).exact? }
- end
-
private
def matches?(requirements, version)
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index 78422ceb76..b0e35e005e 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -67,6 +67,23 @@ module Gem
full_gem_path
end
+ unless const_defined?(:LATEST_RUBY_WITHOUT_PATCH_VERSIONS)
+ LATEST_RUBY_WITHOUT_PATCH_VERSIONS = Gem::Version.new("2.1")
+
+ alias_method :rg_required_ruby_version=, :required_ruby_version=
+ def required_ruby_version=(req)
+ self.rg_required_ruby_version = req
+
+ @required_ruby_version.requirements.map! do |op, v|
+ if v >= LATEST_RUBY_WITHOUT_PATCH_VERSIONS && v.release.segments.size == 4
+ [op == "~>" ? "=" : op, Gem::Version.new(v.segments.tap {|s| s.delete_at(3) }.join("."))]
+ else
+ [op, v]
+ end
+ end
+ end
+ end
+
def groups
@groups ||= []
end
diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb
index 524afd750a..185fe70824 100644
--- a/lib/bundler/source/metadata.rb
+++ b/lib/bundler/source/metadata.rb
@@ -5,7 +5,7 @@ module Bundler
class Metadata < Source
def specs
@specs ||= Index.build do |idx|
- idx << Gem::Specification.new("Ruby\0", RubyVersion.system.to_gem_version_with_patchlevel)
+ idx << Gem::Specification.new("Ruby\0", RubyVersion.system.gem_version)
idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s|
s.required_rubygems_version = Gem::Requirement.default
end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb
index 10a25d2f08..4d577213b9 100644
--- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb
@@ -32,7 +32,7 @@ module Bundler::Molinillo
# all belong to the same graph.
# @return [Array<Vertex>] The sorted vertices.
def self.tsort(vertices)
- TSort.tsort(
+ Bundler::TSort.tsort(
lambda { |b| vertices.each(&b) },
lambda { |v, &b| (v.successors & vertices).each(&b) }
)
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb
index e210202b69..8c8cafb447 100644
--- a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb
@@ -107,36 +107,42 @@ module Bundler::Molinillo
end
end
- conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
- o << "\n" << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
- if conflict.locked_requirement
- o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
- o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
- o << %(\n)
- end
- o << %( In #{name_for_explicit_dependency_source}:\n)
- trees = reduce_trees.call(conflict.requirement_trees)
-
- o << trees.map do |tree|
- t = ''.dup
- depth = 2
- tree.each do |req|
- t << ' ' * depth << printable_requirement.call(req)
- unless tree.last == req
- if spec = conflict.activated_by_name[name_for(req)]
- t << %( was resolved to #{version_for_spec.call(spec)}, which)
+ full_message_for_conflict = opts.delete(:full_message_for_conflict) do
+ proc do |name, conflict|
+ o = "\n".dup << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
+ if conflict.locked_requirement
+ o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
+ o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
+ o << %(\n)
+ end
+ o << %( In #{name_for_explicit_dependency_source}:\n)
+ trees = reduce_trees.call(conflict.requirement_trees)
+
+ o << trees.map do |tree|
+ t = ''.dup
+ depth = 2
+ tree.each do |req|
+ t << ' ' * depth << printable_requirement.call(req)
+ unless tree.last == req
+ if spec = conflict.activated_by_name[name_for(req)]
+ t << %( was resolved to #{version_for_spec.call(spec)}, which)
+ end
+ t << %( depends on)
end
- t << %( depends on)
+ t << %(\n)
+ depth += 1
end
- t << %(\n)
- depth += 1
- end
- t
- end.join("\n")
+ t
+ end.join("\n")
- additional_message_for_conflict.call(o, name, conflict)
+ additional_message_for_conflict.call(o, name, conflict)
- o
+ o
+ end
+ end
+
+ conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
+ o << full_message_for_conflict.call(name, conflict)
end.strip
end
end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
index e13a781a50..a0cfc21672 100644
--- a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
@@ -2,5 +2,5 @@
module Bundler::Molinillo
# The version of Bundler::Molinillo.
- VERSION = '0.7.0'.freeze
+ VERSION = '0.8.0'.freeze
end
diff --git a/lib/bundler/vendor/tsort/lib/tsort.rb b/lib/bundler/vendor/tsort/lib/tsort.rb
index 8454583295..4a0e1a4e25 100644
--- a/lib/bundler/vendor/tsort/lib/tsort.rb
+++ b/lib/bundler/vendor/tsort/lib/tsort.rb
@@ -6,24 +6,24 @@
#
#
-# TSort implements topological sorting using Tarjan's algorithm for
+# Bundler::TSort implements topological sorting using Tarjan's algorithm for
# strongly connected components.
#
-# TSort is designed to be able to be used with any object which can be
+# Bundler::TSort is designed to be able to be used with any object which can be
# interpreted as a directed graph.
#
-# TSort requires two methods to interpret an object as a graph,
+# Bundler::TSort requires two methods to interpret an object as a graph,
# tsort_each_node and tsort_each_child.
#
# * tsort_each_node is used to iterate for all nodes over a graph.
# * tsort_each_child is used to iterate for child nodes of a given node.
#
# The equality of nodes are defined by eql? and hash since
-# TSort uses Hash internally.
+# Bundler::TSort uses Hash internally.
#
# == A Simple Example
#
-# The following example demonstrates how to mix the TSort module into an
+# The following example demonstrates how to mix the Bundler::TSort module into an
# existing class (in this case, Hash). Here, we're treating each key in
# the hash as a node in the graph, and so we simply alias the required
# #tsort_each_node method to Hash's #each_key method. For each key in the
@@ -32,10 +32,10 @@
# method, which fetches the array of child nodes and then iterates over that
# array using the user-supplied block.
#
-# require 'tsort'
+# require 'bundler/vendor/tsort/lib/tsort'
#
# class Hash
-# include TSort
+# include Bundler::TSort
# alias tsort_each_node each_key
# def tsort_each_child(node, &block)
# fetch(node).each(&block)
@@ -52,7 +52,7 @@
#
# A very simple `make' like tool can be implemented as follows:
#
-# require 'tsort'
+# require 'bundler/vendor/tsort/lib/tsort'
#
# class Make
# def initialize
@@ -70,7 +70,7 @@
# each_strongly_connected_component_from(target) {|ns|
# if ns.length != 1
# fs = ns.delete_if {|n| Array === n}
-# raise TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
+# raise Bundler::TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
# end
# n = ns.first
# if Array === n
@@ -93,7 +93,7 @@
# def tsort_each_child(node, &block)
# @dep[node].each(&block)
# end
-# include TSort
+# include Bundler::TSort
# end
#
# def command(arg)
@@ -120,334 +120,333 @@
# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
#
-module Bundler
- module TSort
- class Cyclic < StandardError
- end
- # Returns a topologically sorted array of nodes.
- # The array is sorted from children to parents, i.e.
- # the first element has no child and the last node has no parent.
- #
- # If there is a cycle, TSort::Cyclic is raised.
- #
- # class G
- # include TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # p graph.tsort #=> [4, 2, 3, 1]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # p graph.tsort # raises TSort::Cyclic
- #
- def tsort
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- TSort.tsort(each_node, each_child)
- end
+module Bundler::TSort
+ class Cyclic < StandardError
+ end
- # Returns a topologically sorted array of nodes.
- # The array is sorted from children to parents, i.e.
- # the first element has no child and the last node has no parent.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # If there is a cycle, TSort::Cyclic is raised.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p TSort.tsort(each_node, each_child) # raises TSort::Cyclic
- #
- def TSort.tsort(each_node, each_child)
- TSort.tsort_each(each_node, each_child).to_a
- end
+ # Returns a topologically sorted array of nodes.
+ # The array is sorted from children to parents, i.e.
+ # the first element has no child and the last node has no parent.
+ #
+ # If there is a cycle, Bundler::TSort::Cyclic is raised.
+ #
+ # class G
+ # include Bundler::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # p graph.tsort #=> [4, 2, 3, 1]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # p graph.tsort # raises Bundler::TSort::Cyclic
+ #
+ def tsort
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Bundler::TSort.tsort(each_node, each_child)
+ end
- # The iterator version of the #tsort method.
- # <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
- # modification of _obj_ during the iteration may lead to unexpected results.
- #
- # #tsort_each returns +nil+.
- # If there is a cycle, TSort::Cyclic is raised.
- #
- # class G
- # include TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.tsort_each {|n| p n }
- # #=> 4
- # # 2
- # # 3
- # # 1
- #
- def tsort_each(&block) # :yields: node
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- TSort.tsort_each(each_node, each_child, &block)
- end
+ # Returns a topologically sorted array of nodes.
+ # The array is sorted from children to parents, i.e.
+ # the first element has no child and the last node has no parent.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # If there is a cycle, Bundler::TSort::Cyclic is raised.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Bundler::TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Bundler::TSort.tsort(each_node, each_child) # raises Bundler::TSort::Cyclic
+ #
+ def self.tsort(each_node, each_child)
+ tsort_each(each_node, each_child).to_a
+ end
- # The iterator version of the TSort.tsort method.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # TSort.tsort_each(each_node, each_child) {|n| p n }
- # #=> 4
- # # 2
- # # 3
- # # 1
- #
- def TSort.tsort_each(each_node, each_child) # :yields: node
- return to_enum(__method__, each_node, each_child) unless block_given?
+ # The iterator version of the #tsort method.
+ # <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
+ # modification of _obj_ during the iteration may lead to unexpected results.
+ #
+ # #tsort_each returns +nil+.
+ # If there is a cycle, Bundler::TSort::Cyclic is raised.
+ #
+ # class G
+ # include Bundler::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.tsort_each {|n| p n }
+ # #=> 4
+ # # 2
+ # # 3
+ # # 1
+ #
+ def tsort_each(&block) # :yields: node
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Bundler::TSort.tsort_each(each_node, each_child, &block)
+ end
- TSort.each_strongly_connected_component(each_node, each_child) {|component|
- if component.size == 1
- yield component.first
- else
- raise Cyclic.new("topological sort failed: #{component.inspect}")
- end
- }
- end
+ # The iterator version of the Bundler::TSort.tsort method.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Bundler::TSort.tsort_each(each_node, each_child) {|n| p n }
+ # #=> 4
+ # # 2
+ # # 3
+ # # 1
+ #
+ def self.tsort_each(each_node, each_child) # :yields: node
+ return to_enum(__method__, each_node, each_child) unless block_given?
- # Returns strongly connected components as an array of arrays of nodes.
- # The array is sorted from children to parents.
- # Each elements of the array represents a strongly connected component.
- #
- # class G
- # include TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
- #
- def strongly_connected_components
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- TSort.strongly_connected_components(each_node, each_child)
- end
+ each_strongly_connected_component(each_node, each_child) {|component|
+ if component.size == 1
+ yield component.first
+ else
+ raise Cyclic.new("topological sort failed: #{component.inspect}")
+ end
+ }
+ end
- # Returns strongly connected components as an array of arrays of nodes.
- # The array is sorted from children to parents.
- # Each elements of the array represents a strongly connected component.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p TSort.strongly_connected_components(each_node, each_child)
- # #=> [[4], [2], [3], [1]]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p TSort.strongly_connected_components(each_node, each_child)
- # #=> [[4], [2, 3], [1]]
- #
- def TSort.strongly_connected_components(each_node, each_child)
- TSort.each_strongly_connected_component(each_node, each_child).to_a
- end
+ # Returns strongly connected components as an array of arrays of nodes.
+ # The array is sorted from children to parents.
+ # Each elements of the array represents a strongly connected component.
+ #
+ # class G
+ # include Bundler::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
+ #
+ def strongly_connected_components
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Bundler::TSort.strongly_connected_components(each_node, each_child)
+ end
- # The iterator version of the #strongly_connected_components method.
- # <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
- # <tt><em>obj</em>.strongly_connected_components.each</tt>, but
- # modification of _obj_ during the iteration may lead to unexpected results.
- #
- # #each_strongly_connected_component returns +nil+.
- #
- # class G
- # include TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.each_strongly_connected_component {|scc| p scc }
- # #=> [4]
- # # [2]
- # # [3]
- # # [1]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # graph.each_strongly_connected_component {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def each_strongly_connected_component(&block) # :yields: nodes
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- TSort.each_strongly_connected_component(each_node, each_child, &block)
- end
+ # Returns strongly connected components as an array of arrays of nodes.
+ # The array is sorted from children to parents.
+ # Each elements of the array represents a strongly connected component.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Bundler::TSort.strongly_connected_components(each_node, each_child)
+ # #=> [[4], [2], [3], [1]]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Bundler::TSort.strongly_connected_components(each_node, each_child)
+ # #=> [[4], [2, 3], [1]]
+ #
+ def self.strongly_connected_components(each_node, each_child)
+ each_strongly_connected_component(each_node, each_child).to_a
+ end
- # The iterator version of the TSort.strongly_connected_components method.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
- # #=> [4]
- # # [2]
- # # [3]
- # # [1]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def TSort.each_strongly_connected_component(each_node, each_child) # :yields: nodes
- return to_enum(__method__, each_node, each_child) unless block_given?
+ # The iterator version of the #strongly_connected_components method.
+ # <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
+ # <tt><em>obj</em>.strongly_connected_components.each</tt>, but
+ # modification of _obj_ during the iteration may lead to unexpected results.
+ #
+ # #each_strongly_connected_component returns +nil+.
+ #
+ # class G
+ # include Bundler::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.each_strongly_connected_component {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ # # [3]
+ # # [1]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # graph.each_strongly_connected_component {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def each_strongly_connected_component(&block) # :yields: nodes
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Bundler::TSort.each_strongly_connected_component(each_node, each_child, &block)
+ end
- id_map = {}
- stack = []
- each_node.call {|node|
- unless id_map.include? node
- TSort.each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
- yield c
- }
- end
- }
- nil
- end
+ # The iterator version of the Bundler::TSort.strongly_connected_components method.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Bundler::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ # # [3]
+ # # [1]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Bundler::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def self.each_strongly_connected_component(each_node, each_child) # :yields: nodes
+ return to_enum(__method__, each_node, each_child) unless block_given?
- # Iterates over strongly connected component in the subgraph reachable from
- # _node_.
- #
- # Return value is unspecified.
- #
- # #each_strongly_connected_component_from doesn't call #tsort_each_node.
- #
- # class G
- # include TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.each_strongly_connected_component_from(2) {|scc| p scc }
- # #=> [4]
- # # [2]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # graph.each_strongly_connected_component_from(2) {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- #
- def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
- TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
- end
+ id_map = {}
+ stack = []
+ each_node.call {|node|
+ unless id_map.include? node
+ each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
+ yield c
+ }
+ end
+ }
+ nil
+ end
- # Iterates over strongly connected components in a graph.
- # The graph is represented by _node_ and _each_child_.
- #
- # _node_ is the first node.
- # _each_child_ should have +call+ method which takes a node argument
- # and yields for each child node.
- #
- # Return value is unspecified.
- #
- # #TSort.each_strongly_connected_component_from is a class method and
- # it doesn't need a class to represent a graph which includes TSort.
- #
- # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_child = lambda {|n, &b| graph[n].each(&b) }
- # TSort.each_strongly_connected_component_from(1, each_child) {|scc|
- # p scc
- # }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def TSort.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
- return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
+ # Iterates over strongly connected component in the subgraph reachable from
+ # _node_.
+ #
+ # Return value is unspecified.
+ #
+ # #each_strongly_connected_component_from doesn't call #tsort_each_node.
+ #
+ # class G
+ # include Bundler::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ #
+ def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
+ Bundler::TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
+ end
- minimum_id = node_id = id_map[node] = id_map.size
- stack_length = stack.length
- stack << node
+ # Iterates over strongly connected components in a graph.
+ # The graph is represented by _node_ and _each_child_.
+ #
+ # _node_ is the first node.
+ # _each_child_ should have +call+ method which takes a node argument
+ # and yields for each child node.
+ #
+ # Return value is unspecified.
+ #
+ # #Bundler::TSort.each_strongly_connected_component_from is a class method and
+ # it doesn't need a class to represent a graph which includes Bundler::TSort.
+ #
+ # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_child = lambda {|n, &b| graph[n].each(&b) }
+ # Bundler::TSort.each_strongly_connected_component_from(1, each_child) {|scc|
+ # p scc
+ # }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def self.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
+ return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
- each_child.call(node) {|child|
- if id_map.include? child
- child_id = id_map[child]
- minimum_id = child_id if child_id && child_id < minimum_id
- else
- sub_minimum_id =
- TSort.each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
- yield c
- }
- minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
- end
- }
+ minimum_id = node_id = id_map[node] = id_map.size
+ stack_length = stack.length
+ stack << node
- if node_id == minimum_id
- component = stack.slice!(stack_length .. -1)
- component.each {|n| id_map[n] = nil}
- yield component
+ each_child.call(node) {|child|
+ if id_map.include? child
+ child_id = id_map[child]
+ minimum_id = child_id if child_id && child_id < minimum_id
+ else
+ sub_minimum_id =
+ each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
+ yield c
+ }
+ minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
end
+ }
- minimum_id
+ if node_id == minimum_id
+ component = stack.slice!(stack_length .. -1)
+ component.each {|n| id_map[n] = nil}
+ yield component
end
- # Should be implemented by a extended class.
- #
- # #tsort_each_node is used to iterate for all nodes over a graph.
- #
- def tsort_each_node # :yields: node
- raise NotImplementedError.new
- end
+ minimum_id
+ end
- # Should be implemented by a extended class.
- #
- # #tsort_each_child is used to iterate for child nodes of _node_.
- #
- def tsort_each_child(node) # :yields: child
- raise NotImplementedError.new
- end
+ # Should be implemented by a extended class.
+ #
+ # #tsort_each_node is used to iterate for all nodes over a graph.
+ #
+ def tsort_each_node # :yields: node
+ raise NotImplementedError.new
+ end
+
+ # Should be implemented by a extended class.
+ #
+ # #tsort_each_child is used to iterate for child nodes of _node_.
+ #
+ def tsort_each_child(node) # :yields: child
+ raise NotImplementedError.new
end
end
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index d2c404d7d3..137c08610b 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -864,9 +864,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
return @ruby_version if defined? @ruby_version
version = RUBY_VERSION.dup
- if defined?(RUBY_PATCHLEVEL) && RUBY_PATCHLEVEL != -1
- version << ".#{RUBY_PATCHLEVEL}"
- elsif defined?(RUBY_DESCRIPTION)
+ unless defined?(RUBY_PATCHLEVEL) && RUBY_PATCHLEVEL != -1
if RUBY_ENGINE == "ruby"
desc = RUBY_DESCRIPTION[/\Aruby #{Regexp.quote(RUBY_VERSION)}([^ ]+) /, 1]
else
diff --git a/lib/rubygems/optparse/lib/optparse.rb b/lib/rubygems/optparse/lib/optparse.rb
index e4b1c61f79..98865612ba 100644
--- a/lib/rubygems/optparse/lib/optparse.rb
+++ b/lib/rubygems/optparse/lib/optparse.rb
@@ -50,7 +50,7 @@
#
# === New to \Gem::OptionParser?
#
-# See the {Tutorial}[./doc/optparse/tutorial_rdoc.html].
+# See the {Tutorial}[optparse/tutorial.rdoc].
#
# === Introduction
#
@@ -420,7 +420,7 @@
# === Further documentation
#
# The above examples, along with the accompanying
-# {Tutorial}[./doc/optparse/tutorial_rdoc.html],
+# {Tutorial}[optparse/tutorial.rdoc],
# should be enough to learn how to use this class.
# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
#
@@ -674,6 +674,29 @@ class Gem::OptionParser
end
end
+ def pretty_print_contents(q) # :nodoc:
+ if @block
+ q.text ":" + @block.source_location.join(":") + ":"
+ first = false
+ else
+ first = true
+ end
+ [@short, @long].each do |list|
+ list.each do |opt|
+ if first
+ q.text ":"
+ first = false
+ end
+ q.breakable
+ q.text opt
+ end
+ end
+ end
+
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) {pretty_print_contents(q)}
+ end
+
#
# Switch that takes no arguments.
#
@@ -693,6 +716,10 @@ class Gem::OptionParser
def self.pattern
Object
end
+
+ def pretty_head # :nodoc:
+ "NoArgument"
+ end
end
#
@@ -710,6 +737,10 @@ class Gem::OptionParser
end
conv_arg(*parse_arg(arg, &method(:raise)))
end
+
+ def pretty_head # :nodoc:
+ "Required"
+ end
end
#
@@ -727,6 +758,10 @@ class Gem::OptionParser
conv_arg(arg)
end
end
+
+ def pretty_head # :nodoc:
+ "Optional"
+ end
end
#
@@ -750,6 +785,10 @@ class Gem::OptionParser
end
val
end
+
+ def pretty_head # :nodoc:
+ "Placed"
+ end
end
end
@@ -781,6 +820,17 @@ class Gem::OptionParser
@list = []
end
+ def pretty_print(q) # :nodoc:
+ q.group(1, "(", ")") do
+ @list.each do |sw|
+ next unless Switch === sw
+ q.group(1, "(" + sw.pretty_head, ")") do
+ sw.pretty_print_contents(q)
+ end
+ end
+ end
+ end
+
#
# See Gem::OptionParser.accept.
#
@@ -1293,6 +1343,29 @@ XXX
def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
alias to_s help
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) do
+ first = true
+ if @stack.size > 2
+ @stack.each_with_index do |s, i|
+ next if i < 2
+ next if s.list.empty?
+ if first
+ first = false
+ q.text ":"
+ end
+ q.breakable
+ s.pretty_print(q)
+ end
+ end
+ end
+ end
+
+ def inspect # :nodoc:
+ require 'pp'
+ pretty_print_inspect
+ end
+
#
# Returns option summary list.
#
diff --git a/lib/rubygems/optparse/lib/optparse/ac.rb b/lib/rubygems/optparse/lib/optparse/ac.rb
index ff2f4c2dc3..e84d01bf91 100644
--- a/lib/rubygems/optparse/lib/optparse/ac.rb
+++ b/lib/rubygems/optparse/lib/optparse/ac.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: false
-require 'rubygems/optparse/lib/optparse'
+require_relative '../optparse'
class Gem::OptionParser::AC < Gem::OptionParser
private
diff --git a/lib/rubygems/optparse/lib/optparse/date.rb b/lib/rubygems/optparse/lib/optparse/date.rb
index 11131e92c2..d9a9f4f48a 100644
--- a/lib/rubygems/optparse/lib/optparse/date.rb
+++ b/lib/rubygems/optparse/lib/optparse/date.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: false
-require 'rubygems/optparse/lib/optparse'
+require_relative '../optparse'
require 'date'
Gem::OptionParser.accept(DateTime) do |s,|
diff --git a/lib/rubygems/optparse/lib/optparse/kwargs.rb b/lib/rubygems/optparse/lib/optparse/kwargs.rb
index 9290344c39..6987a5ed62 100644
--- a/lib/rubygems/optparse/lib/optparse/kwargs.rb
+++ b/lib/rubygems/optparse/lib/optparse/kwargs.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-require 'rubygems/optparse/lib/optparse'
+require_relative '../optparse'
class Gem::OptionParser
# :call-seq:
diff --git a/lib/rubygems/optparse/lib/optparse/shellwords.rb b/lib/rubygems/optparse/lib/optparse/shellwords.rb
index 60dd91990c..d47ad60255 100644
--- a/lib/rubygems/optparse/lib/optparse/shellwords.rb
+++ b/lib/rubygems/optparse/lib/optparse/shellwords.rb
@@ -2,6 +2,6 @@
# -*- ruby -*-
require 'shellwords'
-require 'rubygems/optparse/lib/optparse'
+require_relative '../optparse'
Gem::OptionParser.accept(Shellwords) {|s,| Shellwords.shellwords(s)}
diff --git a/lib/rubygems/optparse/lib/optparse/time.rb b/lib/rubygems/optparse/lib/optparse/time.rb
index cb19f6e998..c59e1e4ced 100644
--- a/lib/rubygems/optparse/lib/optparse/time.rb
+++ b/lib/rubygems/optparse/lib/optparse/time.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: false
-require 'rubygems/optparse/lib/optparse'
+require_relative '../optparse'
require 'time'
Gem::OptionParser.accept(Time) do |s,|
diff --git a/lib/rubygems/optparse/lib/optparse/uri.rb b/lib/rubygems/optparse/lib/optparse/uri.rb
index 088f309992..664d7f2af4 100644
--- a/lib/rubygems/optparse/lib/optparse/uri.rb
+++ b/lib/rubygems/optparse/lib/optparse/uri.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
# -*- ruby -*-
-require 'rubygems/optparse/lib/optparse'
+require_relative '../optparse'
require 'uri'
Gem::OptionParser.accept(URI) {|s,| URI.parse(s) if s}
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 0d72cee51d..7e7599f7db 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -657,6 +657,8 @@ class Gem::Specification < Gem::BasicSpecification
@rdoc_options ||= []
end
+ LATEST_RUBY_WITHOUT_PATCH_VERSIONS = Gem::Version.new("2.1")
+
##
# The version of Ruby required by this gem. The ruby version can be
# specified to the patch-level:
@@ -683,6 +685,14 @@ class Gem::Specification < Gem::BasicSpecification
def required_ruby_version=(req)
@required_ruby_version = Gem::Requirement.create req
+
+ @required_ruby_version.requirements.map! do |op, v|
+ if v >= LATEST_RUBY_WITHOUT_PATCH_VERSIONS && v.release.segments.size == 4
+ [op == "~>" ? "=" : op, Gem::Version.new(v.segments.tap {|s| s.delete_at(3) }.join("."))]
+ else
+ [op, v]
+ end
+ end
end
##
diff --git a/spec/bundler/bundler/ruby_version_spec.rb b/spec/bundler/bundler/ruby_version_spec.rb
index 8c6c071d7f..3e3850031c 100644
--- a/spec/bundler/bundler/ruby_version_spec.rb
+++ b/spec/bundler/bundler/ruby_version_spec.rb
@@ -498,31 +498,5 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
end
end
end
-
- describe "#to_gem_version_with_patchlevel" do
- shared_examples_for "the patchlevel is omitted" do
- it "does not include a patch level" do
- expect(subject.to_gem_version_with_patchlevel.to_s).to eq(version)
- end
- end
-
- context "with nil patch number" do
- let(:patchlevel) { nil }
-
- it_behaves_like "the patchlevel is omitted"
- end
-
- context "with negative patch number" do
- let(:patchlevel) { -1 }
-
- it_behaves_like "the patchlevel is omitted"
- end
-
- context "with a valid patch number" do
- it "uses the specified patchlevel as patchlevel" do
- expect(subject.to_gem_version_with_patchlevel.to_s).to eq("#{version}.#{patchlevel}")
- end
- end
- end
end
end
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index ee1c3ffd46..9c5240157f 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -542,6 +542,40 @@ RSpec.describe "bundle lock" do
bundle "lock --add-platform x86_64-linux", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
+ it "respects lower bound ruby requirements" do
+ skip "this spec does not work with prereleases because their version is actually lower than their reported `RUBY_VERSION`" if RUBY_PATCHLEVEL == -1
+
+ build_repo4 do
+ build_gem "our_private_gem", "0.1.0" do |s|
+ s.required_ruby_version = ">= #{RUBY_VERSION}"
+ end
+ end
+
+ gemfile <<-G
+ source "https://localgemserver.test"
+
+ gem "our_private_gem"
+ G
+
+ lockfile <<-L
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ our_private_gem (0.1.0)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ our_private_gem
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle "install", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ end
+
context "when an update is available" do
let(:repo) { gem_repo2 }
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index d013d5bd73..d45a565475 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -1182,6 +1182,8 @@ RSpec.describe "bundle update --bundler" do
end
it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo, :realworld do
+ skip "ruby-head has a default Bundler version too high for this spec to work" if RUBY_PATCHLEVEL == -1
+
pristine_system_gems "bundler-2.3.9"
build_repo4 do
@@ -1226,6 +1228,8 @@ RSpec.describe "bundle update --bundler" do
end
it "errors if the explicit target version does not exist", :realworld do
+ skip "ruby-head has a default Bundler version too high for this spec to work" if RUBY_PATCHLEVEL == -1
+
pristine_system_gems "bundler-2.3.9"
build_repo4 do
diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb
index 209996f61f..83f1e60806 100644
--- a/spec/bundler/install/gems/resolving_spec.rb
+++ b/spec/bundler/install/gems/resolving_spec.rb
@@ -301,7 +301,28 @@ RSpec.describe "bundle install with install-time dependencies" do
end
let(:ruby_requirement) { %("#{RUBY_VERSION}") }
- let(:error_message_requirement) { "~> #{RUBY_VERSION}.0" }
+ let(:error_message_requirement) { "= #{RUBY_VERSION}" }
+
+ it "raises a proper error that mentions the current Ruby version during resolution" do
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false
+ source "http://localgemserver.test/"
+ gem 'require_ruby'
+ G
+
+ expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
+
+ nice_error = strip_whitespace(<<-E).strip
+ Bundler found conflicting requirements for the Ruby\0 version:
+ In Gemfile:
+ require_ruby was resolved to 1.0, which depends on
+ Ruby\0 (> 9000)
+
+ Current Ruby\0 version:
+ Ruby\0 (#{error_message_requirement})
+
+ E
+ expect(err).to end_with(nice_error)
+ end
shared_examples_for "ruby version conflicts" do
it "raises an error during resolution" do
@@ -316,10 +337,12 @@ RSpec.describe "bundle install with install-time dependencies" do
nice_error = strip_whitespace(<<-E).strip
Bundler found conflicting requirements for the Ruby\0 version:
In Gemfile:
- Ruby\0 (#{error_message_requirement})
-
require_ruby was resolved to 1.0, which depends on
Ruby\0 (> 9000)
+
+ Current Ruby\0 version:
+ Ruby\0 (#{error_message_requirement})
+
E
expect(err).to end_with(nice_error)
end
@@ -329,7 +352,6 @@ RSpec.describe "bundle install with install-time dependencies" do
describe "with a < requirement" do
let(:ruby_requirement) { %("< 5000") }
- let(:error_message_requirement) { "< 5000" }
it_behaves_like "ruby version conflicts"
end
@@ -337,7 +359,6 @@ RSpec.describe "bundle install with install-time dependencies" do
describe "with a compound requirement" do
let(:reqs) { ["> 0.1", "< 5000"] }
let(:ruby_requirement) { reqs.map(&:dump).join(", ") }
- let(:error_message_requirement) { Gem::Requirement.new(reqs).to_s }
it_behaves_like "ruby version conflicts"
end
@@ -361,10 +382,12 @@ RSpec.describe "bundle install with install-time dependencies" do
nice_error = strip_whitespace(<<-E).strip
Bundler found conflicting requirements for the RubyGems\0 version:
In Gemfile:
- RubyGems\0 (= #{Gem::VERSION})
-
require_rubygems was resolved to 1.0, which depends on
RubyGems\0 (> 9000)
+
+ Current RubyGems\0 version:
+ RubyGems\0 (= #{Gem::VERSION})
+
E
expect(err).to end_with(nice_error)
end
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb
index 66dd7f534a..5cbb484c68 100644
--- a/spec/bundler/install/gems/standalone_spec.rb
+++ b/spec/bundler/install/gems/standalone_spec.rb
@@ -120,7 +120,7 @@ RSpec.shared_examples "bundle install --standalone" do
realworld_system_gems "tsort --version 0.1.0"
- necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.0"]
+ necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.1"]
necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.a")
necessary_system_gems += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a")
realworld_system_gems(*necessary_system_gems, :path => scoped_gem_path(bundled_app("bundle")))
diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb
index be9016b831..6b57ff066e 100644
--- a/test/rubygems/helper.rb
+++ b/test/rubygems/helper.rb
@@ -1098,7 +1098,7 @@ Also, a list:
Zlib::Deflate.deflate data
end
- def util_set_RUBY_VERSION(version, patchlevel = nil, revision = nil, description = nil, engine = "ruby", engine_version = nil)
+ def util_set_RUBY_VERSION(version, patchlevel, revision, description, engine = "ruby", engine_version = nil)
if Gem.instance_variables.include? :@ruby_version
Gem.send :remove_instance_variable, :@ruby_version
end
@@ -1106,16 +1106,16 @@ Also, a list:
@RUBY_VERSION = RUBY_VERSION
@RUBY_PATCHLEVEL = RUBY_PATCHLEVEL if defined?(RUBY_PATCHLEVEL)
@RUBY_REVISION = RUBY_REVISION if defined?(RUBY_REVISION)
- @RUBY_DESCRIPTION = RUBY_DESCRIPTION if defined?(RUBY_DESCRIPTION)
+ @RUBY_DESCRIPTION = RUBY_DESCRIPTION
@RUBY_ENGINE = RUBY_ENGINE
@RUBY_ENGINE_VERSION = RUBY_ENGINE_VERSION if defined?(RUBY_ENGINE_VERSION)
util_clear_RUBY_VERSION
Object.const_set :RUBY_VERSION, version
- Object.const_set :RUBY_PATCHLEVEL, patchlevel if patchlevel
- Object.const_set :RUBY_REVISION, revision if revision
- Object.const_set :RUBY_DESCRIPTION, description if description
+ Object.const_set :RUBY_PATCHLEVEL, patchlevel
+ Object.const_set :RUBY_REVISION, revision
+ Object.const_set :RUBY_DESCRIPTION, description
Object.const_set :RUBY_ENGINE, engine
Object.const_set :RUBY_ENGINE_VERSION, engine_version if engine_version
end
@@ -1128,8 +1128,7 @@ Also, a list:
defined?(@RUBY_PATCHLEVEL)
Object.const_set :RUBY_REVISION, @RUBY_REVISION if
defined?(@RUBY_REVISION)
- Object.const_set :RUBY_DESCRIPTION, @RUBY_DESCRIPTION if
- defined?(@RUBY_DESCRIPTION)
+ Object.const_set :RUBY_DESCRIPTION, @RUBY_DESCRIPTION
Object.const_set :RUBY_ENGINE, @RUBY_ENGINE
Object.const_set :RUBY_ENGINE_VERSION, @RUBY_ENGINE_VERSION if
defined?(@RUBY_ENGINE_VERSION)
diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb
index a8be078046..0ff8b4a1db 100644
--- a/test/rubygems/test_gem.rb
+++ b/test/rubygems/test_gem.rb
@@ -1106,22 +1106,6 @@ class TestGem < Gem::TestCase
assert_equal Gem::Requirement.default, Gem.env_requirement('qux')
end
- def test_self_ruby_version_with_patchlevel_less_ancient_rubies
- util_set_RUBY_VERSION '1.8.5'
-
- assert_equal Gem::Version.new('1.8.5'), Gem.ruby_version
- ensure
- util_restore_RUBY_VERSION
- end
-
- def test_self_ruby_version_with_release
- util_set_RUBY_VERSION '1.8.6', 287
-
- assert_equal Gem::Version.new('1.8.6.287'), Gem.ruby_version
- ensure
- util_restore_RUBY_VERSION
- end
-
def test_self_ruby_version_with_non_mri_implementations
util_set_RUBY_VERSION '2.5.0', 0, 60928, 'jruby 9.2.0.0 (2.5.0) 2018-05-24 81156a8 OpenJDK 64-Bit Server VM 25.171-b11 on 1.8.0_171-8u171-b11-0ubuntu0.16.04.1-b11 [linux-x86_64]'
diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock
index efee4b2f2c..a936e19db8 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock
+++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock
@@ -261,8 +261,8 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.6.0"
-source = "git+https://github.com/ianks/rb-sys?tag=v0.6.0#1aa5b589e86a14e01aba806511818c19f85d71f6"
+version = "0.7.3"
+source = "git+https://github.com/ianks/rb-sys?tag=v0.7.3#4a5dd9782075fc6e197976eb2188231a388c3c95"
dependencies = [
"bindgen",
"libc",
@@ -271,9 +271,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.5.4"
+version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml
index e0232f729d..d95d1fb2a5 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml
+++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml
@@ -7,4 +7,4 @@ crate-type = ["cdylib"]
[dependencies]
# Needed until bindgen has the `allowlist_file` feature
-rb-sys = { git = "https://github.com/ianks/rb-sys", tag = "v0.6.0" }
+rb-sys = { git = "https://github.com/ianks/rb-sys", tag = "v0.7.3" }
diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
index 9248f7101c..a55ee0dc76 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
+++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock
@@ -254,8 +254,8 @@ dependencies = [
[[package]]
name = "rb-sys"
-version = "0.6.0"
-source = "git+https://github.com/ianks/rb-sys?tag=v0.6.0#1aa5b589e86a14e01aba806511818c19f85d71f6"
+version = "0.7.3"
+source = "git+https://github.com/ianks/rb-sys?tag=v0.7.3#4a5dd9782075fc6e197976eb2188231a388c3c95"
dependencies = [
"bindgen",
"libc",
@@ -264,9 +264,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.5.4"
+version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
index 66a98f3885..0591ebd493 100644
--- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
+++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml
@@ -7,4 +7,4 @@ crate-type = ["cdylib"]
[dependencies]
# Needed until bindgen has the `allowlist_file` feature
-rb-sys = { git = "https://github.com/ianks/rb-sys", tag = "v0.6.0" }
+rb-sys = { git = "https://github.com/ianks/rb-sys", tag = "v0.7.3" }
diff --git a/test/rubygems/test_gem_resolver_installer_set.rb b/test/rubygems/test_gem_resolver_installer_set.rb
index 1b2f0ab637..928a16b9d3 100644
--- a/test/rubygems/test_gem_resolver_installer_set.rb
+++ b/test/rubygems/test_gem_resolver_installer_set.rb
@@ -69,7 +69,7 @@ class TestGemResolverInstallerSet < Gem::TestCase
fetcher.gem 'a', 1
end
- # GitHub has an issue in which it will generate a misleading prerelease output in its RubyGems server API and
+ # Github has an issue in which it will generate a misleading prerelease output in its RubyGems server API and
# returns a 0 version for the gem while it doesn't exist.
@fetcher.data["#{@gem_repo}prerelease_specs.#{Gem.marshal_version}.gz"] = util_gzip(Marshal.dump([
Gem::NameTuple.new('a', Gem::Version.new(0), 'ruby'),