bundler 2.3.11 → 2.3.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/bundler/build_metadata.rb +2 -2
- data/lib/bundler/current_ruby.rb +1 -0
- data/lib/bundler/definition.rb +1 -18
- data/lib/bundler/dependency.rb +18 -0
- data/lib/bundler/resolver/spec_group.rb +2 -2
- data/lib/bundler/resolver.rb +60 -27
- data/lib/bundler/ruby_version.rb +0 -13
- data/lib/bundler/rubygems_ext.rb +17 -0
- data/lib/bundler/source/metadata.rb +1 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +1 -1
- data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +32 -26
- data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
- data/lib/bundler/vendor/tsort/lib/tsort.rb +318 -319
- data/lib/bundler/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 489c8d7661dcb4d99b7990a44d02dc883d10e31adb0297fa09f52ff502424e63
|
4
|
+
data.tar.gz: d050d525313844234ca93b7c879f7582ff2d0e0a334f33b706bc67039e8511b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 853c3263abfbf6296e2256a5ea8df6860fe71591b25d3c5087839c9c0a0e5b7787b5696e621becb4c825f1429bc6fb1c07ca9b6b87f508910415ff23d2c05015
|
7
|
+
data.tar.gz: e4fe33afda4a3c4ab8ea8b3e6ba458fc335cc76443d1062a674be0093fb87b25dd37c310e53d0c00dca3417c2e20c89c5f4e72b03000e897d4136758ccc2e210
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# 2.3.12 (April 20, 2022)
|
2
|
+
|
3
|
+
## Enhancements:
|
4
|
+
|
5
|
+
- Improve Ruby version resolution conflicts [#5474](https://github.com/rubygems/rubygems/pull/5474)
|
6
|
+
- Stop considering `RUBY_PATCHLEVEL` for resolution [#5472](https://github.com/rubygems/rubygems/pull/5472)
|
7
|
+
- Add modern rubies as valid platform values in Gemfile DSL [#5469](https://github.com/rubygems/rubygems/pull/5469)
|
8
|
+
|
1
9
|
# 2.3.11 (April 7, 2022)
|
2
10
|
|
3
11
|
## Enhancements:
|
@@ -4,8 +4,8 @@ module Bundler
|
|
4
4
|
# Represents metadata from when the Bundler gem was built.
|
5
5
|
module BuildMetadata
|
6
6
|
# begin ivars
|
7
|
-
@built_at = "2022-04-
|
8
|
-
@git_commit_sha = "
|
7
|
+
@built_at = "2022-04-20".freeze
|
8
|
+
@git_commit_sha = "75031e03f4".freeze
|
9
9
|
@release = true
|
10
10
|
# end ivars
|
11
11
|
|
data/lib/bundler/current_ruby.rb
CHANGED
data/lib/bundler/definition.rb
CHANGED
@@ -732,30 +732,13 @@ module Bundler
|
|
732
732
|
|
733
733
|
def metadata_dependencies
|
734
734
|
@metadata_dependencies ||= begin
|
735
|
-
ruby_versions = ruby_version_requirements(@ruby_version)
|
736
735
|
[
|
737
|
-
Dependency.new("Ruby\0",
|
736
|
+
Dependency.new("Ruby\0", RubyVersion.system.gem_version),
|
738
737
|
Dependency.new("RubyGems\0", Gem::VERSION),
|
739
738
|
]
|
740
739
|
end
|
741
740
|
end
|
742
741
|
|
743
|
-
def ruby_version_requirements(ruby_version)
|
744
|
-
return [] unless ruby_version
|
745
|
-
if ruby_version.patchlevel
|
746
|
-
[ruby_version.to_gem_version_with_patchlevel]
|
747
|
-
else
|
748
|
-
ruby_version.versions.map do |version|
|
749
|
-
requirement = Gem::Requirement.new(version)
|
750
|
-
if requirement.exact?
|
751
|
-
"~> #{version}.0"
|
752
|
-
else
|
753
|
-
requirement
|
754
|
-
end
|
755
|
-
end
|
756
|
-
end
|
757
|
-
end
|
758
|
-
|
759
742
|
def expand_dependencies(dependencies, remote = false)
|
760
743
|
deps = []
|
761
744
|
dependencies.each do |dep|
|
data/lib/bundler/dependency.rb
CHANGED
@@ -20,6 +20,9 @@ module Bundler
|
|
20
20
|
:ruby_24 => Gem::Platform::RUBY,
|
21
21
|
:ruby_25 => Gem::Platform::RUBY,
|
22
22
|
:ruby_26 => Gem::Platform::RUBY,
|
23
|
+
:ruby_27 => Gem::Platform::RUBY,
|
24
|
+
:ruby_30 => Gem::Platform::RUBY,
|
25
|
+
:ruby_31 => Gem::Platform::RUBY,
|
23
26
|
:mri => Gem::Platform::RUBY,
|
24
27
|
:mri_18 => Gem::Platform::RUBY,
|
25
28
|
:mri_19 => Gem::Platform::RUBY,
|
@@ -30,6 +33,9 @@ module Bundler
|
|
30
33
|
:mri_24 => Gem::Platform::RUBY,
|
31
34
|
:mri_25 => Gem::Platform::RUBY,
|
32
35
|
:mri_26 => Gem::Platform::RUBY,
|
36
|
+
:mri_27 => Gem::Platform::RUBY,
|
37
|
+
:mri_30 => Gem::Platform::RUBY,
|
38
|
+
:mri_31 => Gem::Platform::RUBY,
|
33
39
|
:rbx => Gem::Platform::RUBY,
|
34
40
|
:truffleruby => Gem::Platform::RUBY,
|
35
41
|
:jruby => Gem::Platform::JAVA,
|
@@ -45,6 +51,9 @@ module Bundler
|
|
45
51
|
:mswin_24 => Gem::Platform::MSWIN,
|
46
52
|
:mswin_25 => Gem::Platform::MSWIN,
|
47
53
|
:mswin_26 => Gem::Platform::MSWIN,
|
54
|
+
:mswin_27 => Gem::Platform::MSWIN,
|
55
|
+
:mswin_30 => Gem::Platform::MSWIN,
|
56
|
+
:mswin_31 => Gem::Platform::MSWIN,
|
48
57
|
:mswin64 => Gem::Platform::MSWIN64,
|
49
58
|
:mswin64_19 => Gem::Platform::MSWIN64,
|
50
59
|
:mswin64_20 => Gem::Platform::MSWIN64,
|
@@ -54,6 +63,9 @@ module Bundler
|
|
54
63
|
:mswin64_24 => Gem::Platform::MSWIN64,
|
55
64
|
:mswin64_25 => Gem::Platform::MSWIN64,
|
56
65
|
:mswin64_26 => Gem::Platform::MSWIN64,
|
66
|
+
:mswin64_27 => Gem::Platform::MSWIN64,
|
67
|
+
:mswin64_30 => Gem::Platform::MSWIN64,
|
68
|
+
:mswin64_31 => Gem::Platform::MSWIN64,
|
57
69
|
:mingw => Gem::Platform::MINGW,
|
58
70
|
:mingw_18 => Gem::Platform::MINGW,
|
59
71
|
:mingw_19 => Gem::Platform::MINGW,
|
@@ -64,6 +76,9 @@ module Bundler
|
|
64
76
|
:mingw_24 => Gem::Platform::MINGW,
|
65
77
|
:mingw_25 => Gem::Platform::MINGW,
|
66
78
|
:mingw_26 => Gem::Platform::MINGW,
|
79
|
+
:mingw_27 => Gem::Platform::MINGW,
|
80
|
+
:mingw_30 => Gem::Platform::MINGW,
|
81
|
+
:mingw_31 => Gem::Platform::MINGW,
|
67
82
|
:x64_mingw => Gem::Platform::X64_MINGW,
|
68
83
|
:x64_mingw_20 => Gem::Platform::X64_MINGW,
|
69
84
|
:x64_mingw_21 => Gem::Platform::X64_MINGW,
|
@@ -72,6 +87,9 @@ module Bundler
|
|
72
87
|
:x64_mingw_24 => Gem::Platform::X64_MINGW,
|
73
88
|
:x64_mingw_25 => Gem::Platform::X64_MINGW,
|
74
89
|
:x64_mingw_26 => Gem::Platform::X64_MINGW,
|
90
|
+
:x64_mingw_27 => Gem::Platform::X64_MINGW,
|
91
|
+
:x64_mingw_30 => Gem::Platform::X64_MINGW,
|
92
|
+
:x64_mingw_31 => Gem::Platform::X64_MINGW,
|
75
93
|
}.freeze
|
76
94
|
|
77
95
|
def initialize(name, version, options = {}, &blk)
|
@@ -97,10 +97,10 @@ module Bundler
|
|
97
97
|
spec = @specs[platform].first
|
98
98
|
return [] if spec.is_a?(LazySpecification)
|
99
99
|
dependencies = []
|
100
|
-
|
100
|
+
unless spec.required_ruby_version.none?
|
101
101
|
dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
|
102
102
|
end
|
103
|
-
|
103
|
+
unless spec.required_rubygems_version.none?
|
104
104
|
dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform)
|
105
105
|
end
|
106
106
|
dependencies
|
data/lib/bundler/resolver.rb
CHANGED
@@ -312,29 +312,66 @@ module Bundler
|
|
312
312
|
|
313
313
|
e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty?
|
314
314
|
|
315
|
-
solver_name = "Bundler"
|
316
|
-
possibility_type = "gem"
|
317
315
|
e.message_with_trees(
|
318
|
-
:
|
319
|
-
|
320
|
-
|
316
|
+
:full_message_for_conflict => lambda do |name, conflict|
|
317
|
+
o = if name.end_with?("\0")
|
318
|
+
String.new("Bundler found conflicting requirements for the #{name} version:")
|
319
|
+
else
|
320
|
+
String.new("Bundler could not find compatible versions for gem \"#{name}\":")
|
321
|
+
end
|
322
|
+
o << %(\n)
|
323
|
+
if conflict.locked_requirement
|
324
|
+
o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
|
325
|
+
o << %( #{SharedHelpers.pretty_dependency(conflict.locked_requirement)}\n)
|
326
|
+
o << %(\n)
|
327
|
+
end
|
328
|
+
o << %( In #{name_for_explicit_dependency_source}:\n)
|
329
|
+
trees = conflict.requirement_trees
|
330
|
+
|
321
331
|
# called first, because we want to reduce the amount of work required to find maximal empty sets
|
322
332
|
trees = trees.uniq {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } }
|
323
333
|
|
324
334
|
# bail out if tree size is too big for Array#combination to make any sense
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
335
|
+
if trees.size <= 15
|
336
|
+
maximal = 1.upto(trees.size).map do |size|
|
337
|
+
trees.map(&:last).flatten(1).combination(size).to_a
|
338
|
+
end.flatten(1).select do |deps|
|
339
|
+
Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
|
340
|
+
end.min_by(&:size)
|
341
|
+
|
342
|
+
trees.reject! {|t| !maximal.include?(t.last) } if maximal
|
343
|
+
|
344
|
+
trees.sort_by! {|t| t.reverse.map(&:name) }
|
345
|
+
end
|
346
|
+
|
347
|
+
metadata_requirements = {}
|
348
|
+
|
349
|
+
o << trees.map do |tree|
|
350
|
+
t = "".dup
|
351
|
+
depth = 2
|
352
|
+
|
353
|
+
base_tree = tree.first
|
354
|
+
base_tree_name = base_tree.name
|
355
|
+
|
356
|
+
if base_tree_name.end_with?("\0")
|
357
|
+
metadata_requirements[base_tree_name] = base_tree
|
358
|
+
t = nil
|
359
|
+
else
|
360
|
+
tree.each do |req|
|
361
|
+
t << " " * depth << SharedHelpers.pretty_dependency(req)
|
362
|
+
unless tree.last == req
|
363
|
+
if spec = conflict.activated_by_name[req.name]
|
364
|
+
t << %( was resolved to #{spec.version}, which)
|
365
|
+
end
|
366
|
+
t << %( depends on)
|
367
|
+
end
|
368
|
+
t << %(\n)
|
369
|
+
depth += 1
|
370
|
+
end
|
371
|
+
end
|
372
|
+
t
|
373
|
+
end.compact.join("\n")
|
374
|
+
|
338
375
|
if name == "bundler"
|
339
376
|
o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
|
340
377
|
|
@@ -355,11 +392,13 @@ module Bundler
|
|
355
392
|
o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n"
|
356
393
|
end
|
357
394
|
end
|
395
|
+
elsif name.end_with?("\0")
|
396
|
+
o << %(\n Current #{name} version:\n #{SharedHelpers.pretty_dependency(metadata_requirements[name])}\n\n)
|
358
397
|
elsif conflict.locked_requirement
|
359
398
|
o << "\n"
|
360
399
|
o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
|
361
400
|
o << %(the gems in your Gemfile, which may resolve the conflict.\n)
|
362
|
-
elsif !conflict.existing
|
401
|
+
elsif !conflict.existing
|
363
402
|
o << "\n"
|
364
403
|
|
365
404
|
relevant_source = conflict.requirement.source || source_for(name)
|
@@ -372,14 +411,8 @@ module Bundler
|
|
372
411
|
|
373
412
|
o << gem_not_found_message(name, conflict.requirement, relevant_source, extra_message)
|
374
413
|
end
|
375
|
-
|
376
|
-
|
377
|
-
:incompatible_version_message_for_conflict => lambda do |name, _conflict|
|
378
|
-
if name.end_with?("\0")
|
379
|
-
%(#{solver_name} found conflicting requirements for the #{name} version:)
|
380
|
-
else
|
381
|
-
%(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
|
382
|
-
end
|
414
|
+
|
415
|
+
o
|
383
416
|
end
|
384
417
|
)
|
385
418
|
end
|
data/lib/bundler/ruby_version.rb
CHANGED
@@ -110,19 +110,6 @@ module Bundler
|
|
110
110
|
@ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version)
|
111
111
|
end
|
112
112
|
|
113
|
-
def to_gem_version_with_patchlevel
|
114
|
-
@gem_version_with_patch ||= begin
|
115
|
-
Gem::Version.create("#{@gem_version}.#{@patchlevel}")
|
116
|
-
rescue ArgumentError
|
117
|
-
@gem_version
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def exact?
|
122
|
-
return @exact if defined?(@exact)
|
123
|
-
@exact = versions.all? {|v| Gem::Requirement.create(v).exact? }
|
124
|
-
end
|
125
|
-
|
126
113
|
private
|
127
114
|
|
128
115
|
def matches?(requirements, version)
|
data/lib/bundler/rubygems_ext.rb
CHANGED
@@ -67,6 +67,23 @@ module Gem
|
|
67
67
|
full_gem_path
|
68
68
|
end
|
69
69
|
|
70
|
+
unless const_defined?(:LATEST_RUBY_WITHOUT_PATCH_VERSIONS)
|
71
|
+
LATEST_RUBY_WITHOUT_PATCH_VERSIONS = Gem::Version.new("2.1")
|
72
|
+
|
73
|
+
alias_method :rg_required_ruby_version=, :required_ruby_version=
|
74
|
+
def required_ruby_version=(req)
|
75
|
+
self.rg_required_ruby_version = req
|
76
|
+
|
77
|
+
@required_ruby_version.requirements.map! do |op, v|
|
78
|
+
if v >= LATEST_RUBY_WITHOUT_PATCH_VERSIONS && v.release.segments.size == 4
|
79
|
+
[op == "~>" ? "=" : op, Gem::Version.new(v.segments.tap {|s| s.delete_at(3) }.join("."))]
|
80
|
+
else
|
81
|
+
[op, v]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
70
87
|
def groups
|
71
88
|
@groups ||= []
|
72
89
|
end
|
@@ -5,7 +5,7 @@ module Bundler
|
|
5
5
|
class Metadata < Source
|
6
6
|
def specs
|
7
7
|
@specs ||= Index.build do |idx|
|
8
|
-
idx << Gem::Specification.new("Ruby\0", RubyVersion.system.
|
8
|
+
idx << Gem::Specification.new("Ruby\0", RubyVersion.system.gem_version)
|
9
9
|
idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.default
|
11
11
|
end
|
@@ -32,7 +32,7 @@ module Bundler::Molinillo
|
|
32
32
|
# all belong to the same graph.
|
33
33
|
# @return [Array<Vertex>] The sorted vertices.
|
34
34
|
def self.tsort(vertices)
|
35
|
-
TSort.tsort(
|
35
|
+
Bundler::TSort.tsort(
|
36
36
|
lambda { |b| vertices.each(&b) },
|
37
37
|
lambda { |v, &b| (v.successors & vertices).each(&b) }
|
38
38
|
)
|
@@ -107,36 +107,42 @@ module Bundler::Molinillo
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
110
|
+
full_message_for_conflict = opts.delete(:full_message_for_conflict) do
|
111
|
+
proc do |name, conflict|
|
112
|
+
o = "\n".dup << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
|
113
|
+
if conflict.locked_requirement
|
114
|
+
o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
|
115
|
+
o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
|
116
|
+
o << %(\n)
|
117
|
+
end
|
118
|
+
o << %( In #{name_for_explicit_dependency_source}:\n)
|
119
|
+
trees = reduce_trees.call(conflict.requirement_trees)
|
120
|
+
|
121
|
+
o << trees.map do |tree|
|
122
|
+
t = ''.dup
|
123
|
+
depth = 2
|
124
|
+
tree.each do |req|
|
125
|
+
t << ' ' * depth << printable_requirement.call(req)
|
126
|
+
unless tree.last == req
|
127
|
+
if spec = conflict.activated_by_name[name_for(req)]
|
128
|
+
t << %( was resolved to #{version_for_spec.call(spec)}, which)
|
129
|
+
end
|
130
|
+
t << %( depends on)
|
128
131
|
end
|
129
|
-
t << %(
|
132
|
+
t << %(\n)
|
133
|
+
depth += 1
|
130
134
|
end
|
131
|
-
t
|
132
|
-
|
133
|
-
end
|
134
|
-
t
|
135
|
-
end.join("\n")
|
135
|
+
t
|
136
|
+
end.join("\n")
|
136
137
|
|
137
|
-
|
138
|
+
additional_message_for_conflict.call(o, name, conflict)
|
138
139
|
|
139
|
-
|
140
|
+
o
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
|
145
|
+
o << full_message_for_conflict.call(name, conflict)
|
140
146
|
end.strip
|
141
147
|
end
|
142
148
|
end
|
@@ -6,24 +6,24 @@
|
|
6
6
|
#
|
7
7
|
|
8
8
|
#
|
9
|
-
# TSort implements topological sorting using Tarjan's algorithm for
|
9
|
+
# Bundler::TSort implements topological sorting using Tarjan's algorithm for
|
10
10
|
# strongly connected components.
|
11
11
|
#
|
12
|
-
# TSort is designed to be able to be used with any object which can be
|
12
|
+
# Bundler::TSort is designed to be able to be used with any object which can be
|
13
13
|
# interpreted as a directed graph.
|
14
14
|
#
|
15
|
-
# TSort requires two methods to interpret an object as a graph,
|
15
|
+
# Bundler::TSort requires two methods to interpret an object as a graph,
|
16
16
|
# tsort_each_node and tsort_each_child.
|
17
17
|
#
|
18
18
|
# * tsort_each_node is used to iterate for all nodes over a graph.
|
19
19
|
# * tsort_each_child is used to iterate for child nodes of a given node.
|
20
20
|
#
|
21
21
|
# The equality of nodes are defined by eql? and hash since
|
22
|
-
# TSort uses Hash internally.
|
22
|
+
# Bundler::TSort uses Hash internally.
|
23
23
|
#
|
24
24
|
# == A Simple Example
|
25
25
|
#
|
26
|
-
# The following example demonstrates how to mix the TSort module into an
|
26
|
+
# The following example demonstrates how to mix the Bundler::TSort module into an
|
27
27
|
# existing class (in this case, Hash). Here, we're treating each key in
|
28
28
|
# the hash as a node in the graph, and so we simply alias the required
|
29
29
|
# #tsort_each_node method to Hash's #each_key method. For each key in the
|
@@ -32,10 +32,10 @@
|
|
32
32
|
# method, which fetches the array of child nodes and then iterates over that
|
33
33
|
# array using the user-supplied block.
|
34
34
|
#
|
35
|
-
# require 'tsort'
|
35
|
+
# require 'bundler/vendor/tsort/lib/tsort'
|
36
36
|
#
|
37
37
|
# class Hash
|
38
|
-
# include TSort
|
38
|
+
# include Bundler::TSort
|
39
39
|
# alias tsort_each_node each_key
|
40
40
|
# def tsort_each_child(node, &block)
|
41
41
|
# fetch(node).each(&block)
|
@@ -52,7 +52,7 @@
|
|
52
52
|
#
|
53
53
|
# A very simple `make' like tool can be implemented as follows:
|
54
54
|
#
|
55
|
-
# require 'tsort'
|
55
|
+
# require 'bundler/vendor/tsort/lib/tsort'
|
56
56
|
#
|
57
57
|
# class Make
|
58
58
|
# def initialize
|
@@ -70,7 +70,7 @@
|
|
70
70
|
# each_strongly_connected_component_from(target) {|ns|
|
71
71
|
# if ns.length != 1
|
72
72
|
# fs = ns.delete_if {|n| Array === n}
|
73
|
-
# raise TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
|
73
|
+
# raise Bundler::TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
|
74
74
|
# end
|
75
75
|
# n = ns.first
|
76
76
|
# if Array === n
|
@@ -93,7 +93,7 @@
|
|
93
93
|
# def tsort_each_child(node, &block)
|
94
94
|
# @dep[node].each(&block)
|
95
95
|
# end
|
96
|
-
# include TSort
|
96
|
+
# include Bundler::TSort
|
97
97
|
# end
|
98
98
|
#
|
99
99
|
# def command(arg)
|
@@ -120,334 +120,333 @@
|
|
120
120
|
# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
|
121
121
|
# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
|
122
122
|
#
|
123
|
-
module Bundler
|
124
|
-
module TSort
|
125
|
-
class Cyclic < StandardError
|
126
|
-
end
|
127
123
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
#
|
132
|
-
# If there is a cycle, TSort::Cyclic is raised.
|
133
|
-
#
|
134
|
-
# class G
|
135
|
-
# include TSort
|
136
|
-
# def initialize(g)
|
137
|
-
# @g = g
|
138
|
-
# end
|
139
|
-
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
140
|
-
# def tsort_each_node(&b) @g.each_key(&b) end
|
141
|
-
# end
|
142
|
-
#
|
143
|
-
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
144
|
-
# p graph.tsort #=> [4, 2, 3, 1]
|
145
|
-
#
|
146
|
-
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
147
|
-
# p graph.tsort # raises TSort::Cyclic
|
148
|
-
#
|
149
|
-
def tsort
|
150
|
-
each_node = method(:tsort_each_node)
|
151
|
-
each_child = method(:tsort_each_child)
|
152
|
-
TSort.tsort(each_node, each_child)
|
153
|
-
end
|
124
|
+
module Bundler::TSort
|
125
|
+
class Cyclic < StandardError
|
126
|
+
end
|
154
127
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
128
|
+
# Returns a topologically sorted array of nodes.
|
129
|
+
# The array is sorted from children to parents, i.e.
|
130
|
+
# the first element has no child and the last node has no parent.
|
131
|
+
#
|
132
|
+
# If there is a cycle, Bundler::TSort::Cyclic is raised.
|
133
|
+
#
|
134
|
+
# class G
|
135
|
+
# include Bundler::TSort
|
136
|
+
# def initialize(g)
|
137
|
+
# @g = g
|
138
|
+
# end
|
139
|
+
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
140
|
+
# def tsort_each_node(&b) @g.each_key(&b) end
|
141
|
+
# end
|
142
|
+
#
|
143
|
+
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
144
|
+
# p graph.tsort #=> [4, 2, 3, 1]
|
145
|
+
#
|
146
|
+
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
147
|
+
# p graph.tsort # raises Bundler::TSort::Cyclic
|
148
|
+
#
|
149
|
+
def tsort
|
150
|
+
each_node = method(:tsort_each_node)
|
151
|
+
each_child = method(:tsort_each_child)
|
152
|
+
Bundler::TSort.tsort(each_node, each_child)
|
153
|
+
end
|
178
154
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
def tsort_each(&block) # :yields: node
|
203
|
-
each_node = method(:tsort_each_node)
|
204
|
-
each_child = method(:tsort_each_child)
|
205
|
-
TSort.tsort_each(each_node, each_child, &block)
|
206
|
-
end
|
155
|
+
# Returns a topologically sorted array of nodes.
|
156
|
+
# The array is sorted from children to parents, i.e.
|
157
|
+
# the first element has no child and the last node has no parent.
|
158
|
+
#
|
159
|
+
# The graph is represented by _each_node_ and _each_child_.
|
160
|
+
# _each_node_ should have +call+ method which yields for each node in the graph.
|
161
|
+
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
162
|
+
#
|
163
|
+
# If there is a cycle, Bundler::TSort::Cyclic is raised.
|
164
|
+
#
|
165
|
+
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
166
|
+
# each_node = lambda {|&b| g.each_key(&b) }
|
167
|
+
# each_child = lambda {|n, &b| g[n].each(&b) }
|
168
|
+
# p Bundler::TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
|
169
|
+
#
|
170
|
+
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
171
|
+
# each_node = lambda {|&b| g.each_key(&b) }
|
172
|
+
# each_child = lambda {|n, &b| g[n].each(&b) }
|
173
|
+
# p Bundler::TSort.tsort(each_node, each_child) # raises Bundler::TSort::Cyclic
|
174
|
+
#
|
175
|
+
def self.tsort(each_node, each_child)
|
176
|
+
tsort_each(each_node, each_child).to_a
|
177
|
+
end
|
207
178
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
179
|
+
# The iterator version of the #tsort method.
|
180
|
+
# <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
|
181
|
+
# modification of _obj_ during the iteration may lead to unexpected results.
|
182
|
+
#
|
183
|
+
# #tsort_each returns +nil+.
|
184
|
+
# If there is a cycle, Bundler::TSort::Cyclic is raised.
|
185
|
+
#
|
186
|
+
# class G
|
187
|
+
# include Bundler::TSort
|
188
|
+
# def initialize(g)
|
189
|
+
# @g = g
|
190
|
+
# end
|
191
|
+
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
192
|
+
# def tsort_each_node(&b) @g.each_key(&b) end
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
196
|
+
# graph.tsort_each {|n| p n }
|
197
|
+
# #=> 4
|
198
|
+
# # 2
|
199
|
+
# # 3
|
200
|
+
# # 1
|
201
|
+
#
|
202
|
+
def tsort_each(&block) # :yields: node
|
203
|
+
each_node = method(:tsort_each_node)
|
204
|
+
each_child = method(:tsort_each_child)
|
205
|
+
Bundler::TSort.tsort_each(each_node, each_child, &block)
|
206
|
+
end
|
225
207
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
208
|
+
# The iterator version of the Bundler::TSort.tsort method.
|
209
|
+
#
|
210
|
+
# The graph is represented by _each_node_ and _each_child_.
|
211
|
+
# _each_node_ should have +call+ method which yields for each node in the graph.
|
212
|
+
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
213
|
+
#
|
214
|
+
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
215
|
+
# each_node = lambda {|&b| g.each_key(&b) }
|
216
|
+
# each_child = lambda {|n, &b| g[n].each(&b) }
|
217
|
+
# Bundler::TSort.tsort_each(each_node, each_child) {|n| p n }
|
218
|
+
# #=> 4
|
219
|
+
# # 2
|
220
|
+
# # 3
|
221
|
+
# # 1
|
222
|
+
#
|
223
|
+
def self.tsort_each(each_node, each_child) # :yields: node
|
224
|
+
return to_enum(__method__, each_node, each_child) unless block_given?
|
234
225
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
# end
|
244
|
-
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
245
|
-
# def tsort_each_node(&b) @g.each_key(&b) end
|
246
|
-
# end
|
247
|
-
#
|
248
|
-
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
249
|
-
# p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
|
250
|
-
#
|
251
|
-
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
252
|
-
# p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
|
253
|
-
#
|
254
|
-
def strongly_connected_components
|
255
|
-
each_node = method(:tsort_each_node)
|
256
|
-
each_child = method(:tsort_each_child)
|
257
|
-
TSort.strongly_connected_components(each_node, each_child)
|
258
|
-
end
|
226
|
+
each_strongly_connected_component(each_node, each_child) {|component|
|
227
|
+
if component.size == 1
|
228
|
+
yield component.first
|
229
|
+
else
|
230
|
+
raise Cyclic.new("topological sort failed: #{component.inspect}")
|
231
|
+
end
|
232
|
+
}
|
233
|
+
end
|
259
234
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
235
|
+
# Returns strongly connected components as an array of arrays of nodes.
|
236
|
+
# The array is sorted from children to parents.
|
237
|
+
# Each elements of the array represents a strongly connected component.
|
238
|
+
#
|
239
|
+
# class G
|
240
|
+
# include Bundler::TSort
|
241
|
+
# def initialize(g)
|
242
|
+
# @g = g
|
243
|
+
# end
|
244
|
+
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
245
|
+
# def tsort_each_node(&b) @g.each_key(&b) end
|
246
|
+
# end
|
247
|
+
#
|
248
|
+
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
249
|
+
# p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
|
250
|
+
#
|
251
|
+
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
252
|
+
# p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
|
253
|
+
#
|
254
|
+
def strongly_connected_components
|
255
|
+
each_node = method(:tsort_each_node)
|
256
|
+
each_child = method(:tsort_each_child)
|
257
|
+
Bundler::TSort.strongly_connected_components(each_node, each_child)
|
258
|
+
end
|
283
259
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
308
|
-
# graph.each_strongly_connected_component {|scc| p scc }
|
309
|
-
# #=> [4]
|
310
|
-
# # [2, 3]
|
311
|
-
# # [1]
|
312
|
-
#
|
313
|
-
def each_strongly_connected_component(&block) # :yields: nodes
|
314
|
-
each_node = method(:tsort_each_node)
|
315
|
-
each_child = method(:tsort_each_child)
|
316
|
-
TSort.each_strongly_connected_component(each_node, each_child, &block)
|
317
|
-
end
|
260
|
+
# Returns strongly connected components as an array of arrays of nodes.
|
261
|
+
# The array is sorted from children to parents.
|
262
|
+
# Each elements of the array represents a strongly connected component.
|
263
|
+
#
|
264
|
+
# The graph is represented by _each_node_ and _each_child_.
|
265
|
+
# _each_node_ should have +call+ method which yields for each node in the graph.
|
266
|
+
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
267
|
+
#
|
268
|
+
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
269
|
+
# each_node = lambda {|&b| g.each_key(&b) }
|
270
|
+
# each_child = lambda {|n, &b| g[n].each(&b) }
|
271
|
+
# p Bundler::TSort.strongly_connected_components(each_node, each_child)
|
272
|
+
# #=> [[4], [2], [3], [1]]
|
273
|
+
#
|
274
|
+
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
275
|
+
# each_node = lambda {|&b| g.each_key(&b) }
|
276
|
+
# each_child = lambda {|n, &b| g[n].each(&b) }
|
277
|
+
# p Bundler::TSort.strongly_connected_components(each_node, each_child)
|
278
|
+
# #=> [[4], [2, 3], [1]]
|
279
|
+
#
|
280
|
+
def self.strongly_connected_components(each_node, each_child)
|
281
|
+
each_strongly_connected_component(each_node, each_child).to_a
|
282
|
+
end
|
318
283
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
284
|
+
# The iterator version of the #strongly_connected_components method.
|
285
|
+
# <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
|
286
|
+
# <tt><em>obj</em>.strongly_connected_components.each</tt>, but
|
287
|
+
# modification of _obj_ during the iteration may lead to unexpected results.
|
288
|
+
#
|
289
|
+
# #each_strongly_connected_component returns +nil+.
|
290
|
+
#
|
291
|
+
# class G
|
292
|
+
# include Bundler::TSort
|
293
|
+
# def initialize(g)
|
294
|
+
# @g = g
|
295
|
+
# end
|
296
|
+
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
297
|
+
# def tsort_each_node(&b) @g.each_key(&b) end
|
298
|
+
# end
|
299
|
+
#
|
300
|
+
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
301
|
+
# graph.each_strongly_connected_component {|scc| p scc }
|
302
|
+
# #=> [4]
|
303
|
+
# # [2]
|
304
|
+
# # [3]
|
305
|
+
# # [1]
|
306
|
+
#
|
307
|
+
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
308
|
+
# graph.each_strongly_connected_component {|scc| p scc }
|
309
|
+
# #=> [4]
|
310
|
+
# # [2, 3]
|
311
|
+
# # [1]
|
312
|
+
#
|
313
|
+
def each_strongly_connected_component(&block) # :yields: nodes
|
314
|
+
each_node = method(:tsort_each_node)
|
315
|
+
each_child = method(:tsort_each_child)
|
316
|
+
Bundler::TSort.each_strongly_connected_component(each_node, each_child, &block)
|
317
|
+
end
|
344
318
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
319
|
+
# The iterator version of the Bundler::TSort.strongly_connected_components method.
|
320
|
+
#
|
321
|
+
# The graph is represented by _each_node_ and _each_child_.
|
322
|
+
# _each_node_ should have +call+ method which yields for each node in the graph.
|
323
|
+
# _each_child_ should have +call+ method which takes a node argument and yields for each child node.
|
324
|
+
#
|
325
|
+
# g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
|
326
|
+
# each_node = lambda {|&b| g.each_key(&b) }
|
327
|
+
# each_child = lambda {|n, &b| g[n].each(&b) }
|
328
|
+
# Bundler::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
|
329
|
+
# #=> [4]
|
330
|
+
# # [2]
|
331
|
+
# # [3]
|
332
|
+
# # [1]
|
333
|
+
#
|
334
|
+
# g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
335
|
+
# each_node = lambda {|&b| g.each_key(&b) }
|
336
|
+
# each_child = lambda {|n, &b| g[n].each(&b) }
|
337
|
+
# Bundler::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
|
338
|
+
# #=> [4]
|
339
|
+
# # [2, 3]
|
340
|
+
# # [1]
|
341
|
+
#
|
342
|
+
def self.each_strongly_connected_component(each_node, each_child) # :yields: nodes
|
343
|
+
return to_enum(__method__, each_node, each_child) unless block_given?
|
356
344
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
# end
|
369
|
-
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
370
|
-
# def tsort_each_node(&b) @g.each_key(&b) end
|
371
|
-
# end
|
372
|
-
#
|
373
|
-
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
374
|
-
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
|
375
|
-
# #=> [4]
|
376
|
-
# # [2]
|
377
|
-
#
|
378
|
-
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
379
|
-
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
|
380
|
-
# #=> [4]
|
381
|
-
# # [2, 3]
|
382
|
-
#
|
383
|
-
def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
|
384
|
-
TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
|
385
|
-
end
|
345
|
+
id_map = {}
|
346
|
+
stack = []
|
347
|
+
each_node.call {|node|
|
348
|
+
unless id_map.include? node
|
349
|
+
each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
|
350
|
+
yield c
|
351
|
+
}
|
352
|
+
end
|
353
|
+
}
|
354
|
+
nil
|
355
|
+
end
|
386
356
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
357
|
+
# Iterates over strongly connected component in the subgraph reachable from
|
358
|
+
# _node_.
|
359
|
+
#
|
360
|
+
# Return value is unspecified.
|
361
|
+
#
|
362
|
+
# #each_strongly_connected_component_from doesn't call #tsort_each_node.
|
363
|
+
#
|
364
|
+
# class G
|
365
|
+
# include Bundler::TSort
|
366
|
+
# def initialize(g)
|
367
|
+
# @g = g
|
368
|
+
# end
|
369
|
+
# def tsort_each_child(n, &b) @g[n].each(&b) end
|
370
|
+
# def tsort_each_node(&b) @g.each_key(&b) end
|
371
|
+
# end
|
372
|
+
#
|
373
|
+
# graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
|
374
|
+
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
|
375
|
+
# #=> [4]
|
376
|
+
# # [2]
|
377
|
+
#
|
378
|
+
# graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
|
379
|
+
# graph.each_strongly_connected_component_from(2) {|scc| p scc }
|
380
|
+
# #=> [4]
|
381
|
+
# # [2, 3]
|
382
|
+
#
|
383
|
+
def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
|
384
|
+
Bundler::TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
|
385
|
+
end
|
410
386
|
|
411
|
-
|
412
|
-
|
413
|
-
|
387
|
+
# Iterates over strongly connected components in a graph.
|
388
|
+
# The graph is represented by _node_ and _each_child_.
|
389
|
+
#
|
390
|
+
# _node_ is the first node.
|
391
|
+
# _each_child_ should have +call+ method which takes a node argument
|
392
|
+
# and yields for each child node.
|
393
|
+
#
|
394
|
+
# Return value is unspecified.
|
395
|
+
#
|
396
|
+
# #Bundler::TSort.each_strongly_connected_component_from is a class method and
|
397
|
+
# it doesn't need a class to represent a graph which includes Bundler::TSort.
|
398
|
+
#
|
399
|
+
# graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
|
400
|
+
# each_child = lambda {|n, &b| graph[n].each(&b) }
|
401
|
+
# Bundler::TSort.each_strongly_connected_component_from(1, each_child) {|scc|
|
402
|
+
# p scc
|
403
|
+
# }
|
404
|
+
# #=> [4]
|
405
|
+
# # [2, 3]
|
406
|
+
# # [1]
|
407
|
+
#
|
408
|
+
def self.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
|
409
|
+
return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
|
414
410
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
minimum_id = child_id if child_id && child_id < minimum_id
|
419
|
-
else
|
420
|
-
sub_minimum_id =
|
421
|
-
TSort.each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
|
422
|
-
yield c
|
423
|
-
}
|
424
|
-
minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
|
425
|
-
end
|
426
|
-
}
|
411
|
+
minimum_id = node_id = id_map[node] = id_map.size
|
412
|
+
stack_length = stack.length
|
413
|
+
stack << node
|
427
414
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
415
|
+
each_child.call(node) {|child|
|
416
|
+
if id_map.include? child
|
417
|
+
child_id = id_map[child]
|
418
|
+
minimum_id = child_id if child_id && child_id < minimum_id
|
419
|
+
else
|
420
|
+
sub_minimum_id =
|
421
|
+
each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
|
422
|
+
yield c
|
423
|
+
}
|
424
|
+
minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
|
432
425
|
end
|
426
|
+
}
|
433
427
|
|
434
|
-
|
428
|
+
if node_id == minimum_id
|
429
|
+
component = stack.slice!(stack_length .. -1)
|
430
|
+
component.each {|n| id_map[n] = nil}
|
431
|
+
yield component
|
435
432
|
end
|
436
433
|
|
437
|
-
|
438
|
-
|
439
|
-
# #tsort_each_node is used to iterate for all nodes over a graph.
|
440
|
-
#
|
441
|
-
def tsort_each_node # :yields: node
|
442
|
-
raise NotImplementedError.new
|
443
|
-
end
|
434
|
+
minimum_id
|
435
|
+
end
|
444
436
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
437
|
+
# Should be implemented by a extended class.
|
438
|
+
#
|
439
|
+
# #tsort_each_node is used to iterate for all nodes over a graph.
|
440
|
+
#
|
441
|
+
def tsort_each_node # :yields: node
|
442
|
+
raise NotImplementedError.new
|
443
|
+
end
|
444
|
+
|
445
|
+
# Should be implemented by a extended class.
|
446
|
+
#
|
447
|
+
# #tsort_each_child is used to iterate for child nodes of _node_.
|
448
|
+
#
|
449
|
+
def tsort_each_child(node) # :yields: child
|
450
|
+
raise NotImplementedError.new
|
452
451
|
end
|
453
452
|
end
|
data/lib/bundler/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bundler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- André Arko
|
@@ -22,7 +22,7 @@ authors:
|
|
22
22
|
autorequire:
|
23
23
|
bindir: exe
|
24
24
|
cert_chain: []
|
25
|
-
date: 2022-04-
|
25
|
+
date: 2022-04-20 00:00:00.000000000 Z
|
26
26
|
dependencies: []
|
27
27
|
description: Bundler manages an application's dependencies through its entire life,
|
28
28
|
across many machines, systematically and repeatably
|
@@ -369,7 +369,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
369
369
|
- !ruby/object:Gem::Version
|
370
370
|
version: 2.5.2
|
371
371
|
requirements: []
|
372
|
-
rubygems_version: 3.3.
|
372
|
+
rubygems_version: 3.3.12
|
373
373
|
signing_key:
|
374
374
|
specification_version: 4
|
375
375
|
summary: The best way to manage your application's dependencies
|