rubygems-update 2.5.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6942268616ad45a23f4f41e7f073dcf914f004f6
4
- data.tar.gz: f96fe2747ff20777d3d823fc71d2e0311a913ac0
3
+ metadata.gz: 2a8f0806e772b0fd07258556709de623f75d0614
4
+ data.tar.gz: 08f55fd0671659873c7af22435ecfa9e852636ca
5
5
  SHA512:
6
- metadata.gz: eaa189a001aebd337b78364031caa2b0670bba9eda11e994a8b43990618c346f61989dff990b0deb3d451cf2faebb077077b3329e9bda0f1f6878a794e53c617
7
- data.tar.gz: 7dd8fff88d8e65a699fa35999b79502c1428e9bcb8afb4c95fa49748382bb10240abad513242e99c588556e3aec6348976e6cf472cf7e6f765dc5e9c5061c3e5
6
+ metadata.gz: de055f8e3f751b3ab5b3b138a488089df9891df5dc8e97f5cf5a11df67d120cb9e7e2d348a699e1de43bb940484f76dbe76116da02f357355f2c9d9283ddfb14
7
+ data.tar.gz: a2fdc146da6f5f44eecfffe93a2412d04eb7423b96a2cd4fe0983b66f8ca6e7e8ee6c4707d673d7fa87ea607e8bc5102a4d1d52be71d163f7bf1ae21fff1c1da
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,6 +1,37 @@
1
1
  # coding: UTF-8
2
2
 
3
- === 2.5.0
3
+ === 2.5.1 / 2015-12-10
4
+
5
+ Bug fixes:
6
+
7
+ * Ensure platform sorting only uses strings. Affected binary installs on Windows.
8
+ Issue #1369 reported by Ryan Atball (among others).
9
+ Pull request #1375 by Samuel E. Giddins.
10
+ * Revert PR #1332. Unable to reproduce, and nil should be impossible.
11
+ * Gem::Specification#to_fullpath now returns .rb extensions when such a file
12
+ exists. Pull request #1114 by y-yagi.
13
+ * RubyGems now handles Net::HTTPFatalError instead of crashing. Pull
14
+ request #1314 by Samuel E. Giddins.
15
+ * Updated bundled Molinillo to 0.4.0. Pull request #1322, #1396 by Samuel E.
16
+ Giddins.
17
+ * Improved performance of spec loading by reducing likelihood of loading he
18
+ complete specification. Pull request #1373 by Aaron Patterson.
19
+ * Improved caching of requirable files Pull request #1377 by Aaron Patterson.
20
+ * Fixed activation of gems with development dependencies. Pull request #1388
21
+ by Samuel E. Giddins.
22
+ * RubyGems now uses the same Molinillo vendoring strategy as Bundler. Pull
23
+ request #1397 by Samuel E. Giddins.
24
+ * Fixed documentation of Gem::Requirement.parse. Pull request #1398 by
25
+ Juanito Fatas.
26
+ * RubyGems no longer warns when a prerelease gem has prerelease dependencies.
27
+ Pull request #1399 by Samuel E. Giddins.
28
+ * Fixed Gem::Version documentation example. Pull request #1401 by Guilherme
29
+ Goettems Schneider.
30
+ * Updated documentation links to https://. Pull request #1404 by Suriyaa
31
+ Kudo.
32
+ * Fixed double word typo. Pull request #1411 by Jake Worth.
33
+
34
+ === 2.5.0 / 2015-11-03
4
35
 
5
36
  Major enhancements:
6
37
 
@@ -2979,4 +3010,3 @@ See ChangeLog
2979
3010
  === 0.2.0 / 2004-03-14
2980
3011
 
2981
3012
  * Initial public release
2982
-
@@ -233,7 +233,7 @@ test/rubygems/rubygems_plugin.rb
233
233
  test/rubygems/sff/discover.rb
234
234
  test/rubygems/simple_gem.rb
235
235
  test/rubygems/specifications/bar-0.0.2.gemspec
236
- test/rubygems/specifications/foo-0.0.1.gemspec
236
+ test/rubygems/specifications/foo-0.0.1-x86-mswin32.gemspec
237
237
  test/rubygems/ssl_cert.pem
238
238
  test/rubygems/ssl_key.pem
239
239
  test/rubygems/test_bundled_ca.rb
@@ -1,11 +1,11 @@
1
1
  = RubyGems
2
2
 
3
- Homepage: :: http://rubygems.org
3
+ Homepage: :: https://rubygems.org
4
4
  Announcements: :: http://blog.rubygems.org
5
5
  Documentation: :: http://guides.rubygems.org
6
6
  Support: :: http://help.rubygems.org
7
- Source: :: http://github.com/rubygems/rubygems
8
- Bugtracker: :: http://github.com/rubygems/rubygems/issues
7
+ Source: :: https://github.com/rubygems/rubygems
8
+ Bugtracker: :: https://github.com/rubygems/rubygems/issues
9
9
 
10
10
  == DESCRIPTION
11
11
 
data/Rakefile CHANGED
@@ -108,29 +108,18 @@ task :install_test_deps => :clean_env do
108
108
  sh "gem install minitest -v '~> 4.0'"
109
109
  end
110
110
 
111
- namespace :molinillo do
112
- task :namespace do
113
- files = Dir.glob('lib/rubygems/resolver/molinillo/**/*.rb')
114
- sh "sed -i.bak 's/Molinillo/Gem::Resolver::Molinillo/g' #{files.join(' ')}"
115
- sh "sed -i.bak \"s/require 'molinillo/require 'rubygems\\/resolver\\/molinillo\\/lib\\/molinillo/g\" #{files.join(' ')}"
116
- sh "rm #{files.join('.bak ')}.bak"
117
- end
111
+ begin
112
+ require "automatiek"
118
113
 
119
- task :clean do
120
- files = Dir.glob('lib/rubygems/resolver/molinillo*/*', File::FNM_DOTMATCH).reject { |f| %(. .. lib).include? f.split('/').last }
121
- puts files
122
- sh "rm -r #{files.join(' ')}"
114
+ Automatiek::RakeTask.new("molinillo") do |lib|
115
+ lib.download = { :github => "https://github.com/CocoaPods/Molinillo" }
116
+ lib.namespace = "Molinillo"
117
+ lib.prefix = "Gem::Resolver"
118
+ lib.vendor_lib = "lib/rubygems/resolver/molinillo"
123
119
  end
124
-
125
- task :update, [:tag] => [] do |t, args|
126
- tag = args[:tag]
127
- Dir.chdir 'lib/rubygems/resolver' do
128
- sh "rm -rf molinillo"
129
- sh "curl -L https://github.com/CocoaPods/molinillo/archive/#{tag}.tar.gz | tar -xz"
130
- sh "mv Molinillo-* molinillo"
131
- end
132
- Rake::Task['molinillo:namespace'].invoke
133
- Rake::Task['molinillo:clean'].invoke
120
+ rescue LoadError
121
+ namespace :vendor do
122
+ task(:molinillo) { abort "Install the automatiek gem to be able to vendor gems." }
134
123
  end
135
124
  end
136
125
 
@@ -9,7 +9,7 @@ require 'rbconfig'
9
9
  require 'thread'
10
10
 
11
11
  module Gem
12
- VERSION = '2.5.0'
12
+ VERSION = '2.5.1'
13
13
  end
14
14
 
15
15
  # Must be first since it unloads the prelude from 1.9.2
@@ -307,11 +307,10 @@ module Gem
307
307
  # package is not available as a gem, return nil.
308
308
 
309
309
  def self.datadir(gem_name)
310
- # TODO: deprecate and move to Gem::Specification
311
- # and drop the extra ", gem_name" which is uselessly redundant
310
+ # TODO: deprecate
312
311
  spec = @loaded_specs[gem_name]
313
312
  return nil if spec.nil?
314
- File.join spec.full_gem_path, "data", gem_name
313
+ spec.datadir
315
314
  end
316
315
 
317
316
  ##
@@ -37,6 +37,14 @@ class Gem::BasicSpecification
37
37
  File.join(Gem.default_dir, "specifications", "default")
38
38
  end
39
39
 
40
+ ##
41
+ # The path to the gem.build_complete file within the extension install
42
+ # directory.
43
+
44
+ def gem_build_complete_path # :nodoc:
45
+ File.join extension_dir, 'gem.build_complete'
46
+ end
47
+
40
48
  ##
41
49
  # True when the gem has been activated
42
50
 
@@ -50,39 +58,24 @@ class Gem::BasicSpecification
50
58
  # eg: /usr/local/lib/ruby/gems/1.8
51
59
 
52
60
  def base_dir
53
- return Gem.dir unless loaded_from
54
- @base_dir ||= if default_gem? then
55
- File.dirname File.dirname File.dirname loaded_from
56
- else
57
- File.dirname File.dirname loaded_from
58
- end
61
+ raise NotImplementedError
59
62
  end
60
63
 
61
64
  ##
62
65
  # Return true if this spec can require +file+.
63
66
 
64
67
  def contains_requirable_file? file
65
- @contains_requirable_file ||= {}
66
- @contains_requirable_file[file] ||=
67
- begin
68
- if instance_variable_defined?(:@ignored) then
69
- return false
70
- elsif missing_extensions? then
71
- @ignored = true
72
-
73
- warn "Ignoring #{full_name} because its extensions are not built. " +
74
- "Try: gem pristine #{name} --version #{version}"
75
- return false
76
- end
77
-
78
- suffixes = Gem.suffixes
68
+ if @ignored then
69
+ return false
70
+ elsif missing_extensions? then
71
+ @ignored = true
72
+
73
+ warn "Ignoring #{full_name} because its extensions are not built. " +
74
+ "Try: gem pristine #{name} --version #{version}"
75
+ return false
76
+ end
79
77
 
80
- full_require_paths.any? do |dir|
81
- base = "#{dir}/#{file}"
82
- suffixes.any? { |suf| File.file? "#{base}#{suf}" }
83
- end
84
- end ? :yes : :no
85
- @contains_requirable_file[file] == :yes
78
+ have_file? file, Gem.suffixes
86
79
  end
87
80
 
88
81
  def default_gem?
@@ -94,7 +87,7 @@ class Gem::BasicSpecification
94
87
  # Returns full path to the directory where gem's extensions are installed.
95
88
 
96
89
  def extension_dir
97
- @extension_dir ||= File.expand_path File.join(extensions_dir, full_name)
90
+ @extension_dir ||= File.expand_path(File.join(extensions_dir, full_name)).untaint
98
91
  end
99
92
 
100
93
  ##
@@ -110,7 +103,7 @@ class Gem::BasicSpecification
110
103
  # TODO: also, shouldn't it default to full_name if it hasn't been written?
111
104
  path = File.expand_path File.join(gems_dir, full_name)
112
105
  path.untaint
113
- path if File.directory? path
106
+ path
114
107
  end
115
108
 
116
109
  private :find_full_gem_path
@@ -148,12 +141,20 @@ class Gem::BasicSpecification
148
141
  File.join full_gem_path, path.untaint
149
142
  end
150
143
 
151
- full_paths << extension_dir unless @extensions.nil? || @extensions.empty?
144
+ full_paths << extension_dir if have_extensions?
152
145
 
153
146
  full_paths
154
147
  end
155
148
  end
156
149
 
150
+ ##
151
+ # The path to the data directory for this gem.
152
+
153
+ def datadir
154
+ # TODO: drop the extra ", gem_name" which is uselessly redundant
155
+ File.expand_path(File.join(gems_dir, full_name, "data", name)).untaint
156
+ end
157
+
157
158
  ##
158
159
  # Full path of the target library file.
159
160
  # If the file is not in this gem, return nil.
@@ -165,8 +166,8 @@ class Gem::BasicSpecification
165
166
  begin
166
167
  fullpath = nil
167
168
  suffixes = Gem.suffixes
168
- full_require_paths.find do |dir|
169
- suffixes.find do |suf|
169
+ suffixes.find do |suf|
170
+ full_require_paths.find do |dir|
170
171
  File.file?(fullpath = "#{dir}/#{path}#{suf}")
171
172
  end
172
173
  end ? fullpath : nil
@@ -189,8 +190,7 @@ class Gem::BasicSpecification
189
190
  # gem directory. eg: /usr/local/lib/ruby/1.8/gems
190
191
 
191
192
  def gems_dir
192
- # TODO: this logic seems terribly broken, but tests fail if just base_dir
193
- @gems_dir ||= File.join(loaded_from && base_dir || Gem.dir, "gems")
193
+ raise NotImplementedError
194
194
  end
195
195
 
196
196
  def internal_init # :nodoc:
@@ -198,8 +198,7 @@ class Gem::BasicSpecification
198
198
  @extensions_dir = nil
199
199
  @full_gem_path = nil
200
200
  @gem_dir = nil
201
- @gems_dir = nil
202
- @base_dir = nil
201
+ @ignored = nil
203
202
  end
204
203
 
205
204
  ##
@@ -217,7 +216,7 @@ class Gem::BasicSpecification
217
216
  end
218
217
 
219
218
  def raw_require_paths # :nodoc:
220
- Array(@require_paths)
219
+ raise NotImplementedError
221
220
  end
222
221
 
223
222
  ##
@@ -238,7 +237,7 @@ class Gem::BasicSpecification
238
237
  # spec.require_path = '.'
239
238
 
240
239
  def require_paths
241
- return raw_require_paths if @extensions.nil? || @extensions.empty?
240
+ return raw_require_paths unless have_extensions?
242
241
 
243
242
  [extension_dir].concat raw_require_paths
244
243
  end
@@ -250,8 +249,8 @@ class Gem::BasicSpecification
250
249
  def source_paths
251
250
  paths = raw_require_paths.dup
252
251
 
253
- if @extensions then
254
- ext_dirs = @extensions.map do |extension|
252
+ if have_extensions? then
253
+ ext_dirs = extensions.map do |extension|
255
254
  extension.split(File::SEPARATOR, 2).first
256
255
  end.uniq
257
256
 
@@ -307,5 +306,23 @@ class Gem::BasicSpecification
307
306
  raise NotImplementedError
308
307
  end
309
308
 
309
+ private
310
+
311
+ def have_extensions?; !extensions.empty?; end
312
+
313
+ def have_file? file, suffixes
314
+ return true if raw_require_paths.any? do |path|
315
+ base = File.join(gems_dir, full_name, path.untaint, file).untaint
316
+ suffixes.any? { |suf| File.file? base + suf }
317
+ end
318
+
319
+ if have_extensions?
320
+ base = File.join extension_dir, file
321
+ suffixes.any? { |suf| File.file? base + suf }
322
+ else
323
+ false
324
+ end
325
+ end
326
+
310
327
  end
311
328
 
@@ -3,7 +3,7 @@ require 'rubygems/commands/query_command'
3
3
 
4
4
  ##
5
5
  # An alternate to Gem::Commands::QueryCommand that searches for gems starting
6
- # with the the supplied argument.
6
+ # with the supplied argument.
7
7
 
8
8
  class Gem::Commands::ListCommand < Gem::Commands::QueryCommand
9
9
 
@@ -60,9 +60,7 @@ module Kernel
60
60
  #--
61
61
  # TODO request access to the C implementation of this to speed up RubyGems
62
62
 
63
- spec = Gem::Specification.stubs.find { |s|
64
- s.activated? and s.contains_requirable_file? path
65
- }
63
+ spec = Gem::Specification.find_active_stub_by_path path
66
64
 
67
65
  begin
68
66
  RUBYGEMS_ACTIVATION_MONITOR.exit
@@ -391,7 +391,7 @@ class Gem::Installer
391
391
  end
392
392
 
393
393
  ##
394
- # The location of of the spec file that is installed.
394
+ # The location of the spec file that is installed.
395
395
  #
396
396
 
397
397
  def spec_file
@@ -399,7 +399,7 @@ class Gem::Installer
399
399
  end
400
400
 
401
401
  ##
402
- # The location of of the default spec file for default gems.
402
+ # The location of the default spec file for default gems.
403
403
  #
404
404
 
405
405
  def default_spec_file
@@ -185,6 +185,10 @@ class Gem::Request
185
185
 
186
186
  bad_response = true
187
187
  retry
188
+ rescue Net::HTTPFatalError
189
+ verbose "fatal error"
190
+
191
+ raise Gem::RemoteFetcher::FetchError.new('fatal error', @uri)
188
192
  # HACK work around EOFError bug in Net::HTTP
189
193
  # NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
190
194
  # to install gems.
@@ -241,4 +245,3 @@ end
241
245
  require 'rubygems/request/http_pool'
242
246
  require 'rubygems/request/https_pool'
243
247
  require 'rubygems/request/connection_pools'
244
-
@@ -89,9 +89,9 @@ class Gem::Requirement
89
89
  # specification, like <tt>">= 1.2"</tt>, or a simple version number,
90
90
  # like <tt>"1.2"</tt>.
91
91
  #
92
- # parse("> 1.0") # => [">", "1.0"]
93
- # parse("1.0") # => ["=", "1.0"]
94
- # parse(Gem::Version.new("1.0")) # => ["=, "1.0"]
92
+ # parse("> 1.0") # => [">", Gem::Version.new("1.0")]
93
+ # parse("1.0") # => ["=", Gem::Version.new("1.0")]
94
+ # parse(Gem::Version.new("1.0")) # => ["=, Gem::Version.new("1.0")]
95
95
 
96
96
  def self.parse obj
97
97
  return ["=", obj] if Gem::Version === obj
@@ -187,7 +187,7 @@ class Gem::Resolver
187
187
 
188
188
  def resolve
189
189
  locking_dg = Molinillo::DependencyGraph.new
190
- Molinillo::Resolver.new(self, self).resolve(@needed.map { |d| DependencyRequest.new d, nil }, locking_dg).tsort.map(&:payload)
190
+ Molinillo::Resolver.new(self, self).resolve(@needed.map { |d| DependencyRequest.new d, nil }, locking_dg).tsort.map(&:payload).compact
191
191
  rescue Molinillo::VersionConflict => e
192
192
  conflict = e.conflicts.values.first
193
193
  raise Gem::DependencyResolutionError, Conflict.new(conflict.requirement_trees.first.first, conflict.existing, conflict.requirement)
@@ -232,7 +232,7 @@ class Gem::Resolver
232
232
  exc.errors = @set.errors
233
233
  raise exc
234
234
  end
235
- possibles.sort_by { |s| [s.source, s.version, s.platform == Gem::Platform.local.to_s ? 1 : 0] }.
235
+ possibles.sort_by { |s| [s.source, s.version, s.platform.to_s == Gem::Platform.local.to_s ? 1 : 0] }.
236
236
  map { |s| ActivationRequest.new s, dependency, [] }
237
237
  end
238
238
 
@@ -34,40 +34,34 @@ module Gem::Resolver::Molinillo
34
34
  # A directed edge of a {DependencyGraph}
35
35
  # @attr [Vertex] origin The origin of the directed edge
36
36
  # @attr [Vertex] destination The destination of the directed edge
37
- # @attr [Array] requirements The requirements the directed edge represents
38
- Edge = Struct.new(:origin, :destination, :requirements)
37
+ # @attr [Object] requirement The requirement the directed edge represents
38
+ Edge = Struct.new(:origin, :destination, :requirement)
39
39
 
40
- # @return [{String => Vertex}] vertices that have no {Vertex#predecessors},
41
- # keyed by by {Vertex#name}
42
- attr_reader :root_vertices
43
40
  # @return [{String => Vertex}] the vertices of the dependency graph, keyed
44
41
  # by {Vertex#name}
45
42
  attr_reader :vertices
46
- # @return [Set<Edge>] the edges of the dependency graph
47
- attr_reader :edges
48
43
 
49
44
  def initialize
50
45
  @vertices = {}
51
- @edges = Set.new
52
- @root_vertices = {}
53
46
  end
54
47
 
55
48
  # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
56
- # have the correct {Vertex#graph} set
49
+ # are properly copied.
57
50
  def initialize_copy(other)
58
51
  super
59
- @vertices = other.vertices.reduce({}) do |vertices, (name, vertex)|
60
- vertices.tap do |hash|
61
- hash[name] = vertex.dup.tap { |v| v.graph = self }
52
+ @vertices = {}
53
+ traverse = lambda do |new_v, old_v|
54
+ return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
55
+ old_v.outgoing_edges.each do |edge|
56
+ destination = add_vertex(edge.destination.name, edge.destination.payload)
57
+ add_edge_no_circular(new_v, destination, edge.requirement)
58
+ traverse.call(destination, edge.destination)
62
59
  end
63
60
  end
64
- @root_vertices = Hash[@vertices.select { |n, _v| other.root_vertices[n] }]
65
- @edges = other.edges.map do |edge|
66
- Edge.new(
67
- vertex_named(edge.origin.name),
68
- vertex_named(edge.destination.name),
69
- edge.requirements.dup
70
- )
61
+ other.vertices.each do |name, vertex|
62
+ new_vertex = add_vertex(name, vertex.payload, vertex.root?)
63
+ new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
64
+ traverse.call(new_vertex, vertex)
71
65
  end
72
66
  end
73
67
 
@@ -80,7 +74,12 @@ module Gem::Resolver::Molinillo
80
74
  # by a recursive traversal of each {#root_vertices} and its
81
75
  # {Vertex#successors}
82
76
  def ==(other)
83
- root_vertices == other.root_vertices
77
+ return false unless other
78
+ vertices.each do |name, vertex|
79
+ other_vertex = other.vertex_named(name)
80
+ return false unless other_vertex
81
+ return false unless other_vertex.successors.map(&:name).to_set == vertex.successors.map(&:name).to_set
82
+ end
84
83
  end
85
84
 
86
85
  # @param [String] name
@@ -89,15 +88,13 @@ module Gem::Resolver::Molinillo
89
88
  # @param [Object] requirement the requirement that is requiring the child
90
89
  # @return [void]
91
90
  def add_child_vertex(name, payload, parent_names, requirement)
92
- is_root = parent_names.include?(nil)
93
- parent_nodes = parent_names.compact.map { |n| vertex_named(n) }
94
- vertex = vertex_named(name) || if is_root
95
- add_root_vertex(name, payload)
96
- else
97
- add_vertex(name, payload)
98
- end
99
- vertex.payload ||= payload
100
- parent_nodes.each do |parent_node|
91
+ vertex = add_vertex(name, payload)
92
+ parent_names.each do |parent_name|
93
+ unless parent_name
94
+ vertex.root = true
95
+ next
96
+ end
97
+ parent_node = vertex_named(parent_name)
101
98
  add_edge(parent_node, vertex, requirement)
102
99
  end
103
100
  vertex
@@ -106,16 +103,11 @@ module Gem::Resolver::Molinillo
106
103
  # @param [String] name
107
104
  # @param [Object] payload
108
105
  # @return [Vertex] the vertex that was added to `self`
109
- def add_vertex(name, payload)
110
- vertex = vertices[name] ||= Vertex.new(self, name, payload)
111
- vertex.tap { |v| v.payload = payload }
112
- end
113
-
114
- # @param [String] name
115
- # @param [Object] payload
116
- # @return [Vertex] the vertex that was added to `self`
117
- def add_root_vertex(name, payload)
118
- add_vertex(name, payload).tap { |v| root_vertices[name] = v }
106
+ def add_vertex(name, payload, root = false)
107
+ vertex = vertices[name] ||= Vertex.new(name, payload)
108
+ vertex.payload ||= payload
109
+ vertex.root ||= root
110
+ vertex
119
111
  end
120
112
 
121
113
  # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
@@ -123,12 +115,12 @@ module Gem::Resolver::Molinillo
123
115
  # @param [String] name
124
116
  # @return [void]
125
117
  def detach_vertex_named(name)
126
- vertex = vertex_named(name)
127
- return unless vertex
128
- successors = vertex.successors
129
- vertices.delete(name)
130
- edges.reject! { |e| e.origin == vertex || e.destination == vertex }
131
- successors.each { |v| detach_vertex_named(v.name) unless root_vertices[v.name] || v.predecessors.any? }
118
+ return unless vertex = vertices.delete(name)
119
+ vertex.outgoing_edges.each do |e|
120
+ v = e.destination
121
+ v.incoming_edges.delete(e)
122
+ detach_vertex_named(v.name) unless v.root? || v.predecessors.any?
123
+ end
132
124
  end
133
125
 
134
126
  # @param [String] name
@@ -140,7 +132,8 @@ module Gem::Resolver::Molinillo
140
132
  # @param [String] name
141
133
  # @return [Vertex,nil] the root vertex with the given name
142
134
  def root_vertex_named(name)
143
- root_vertices[name]
135
+ vertex = vertex_named(name)
136
+ vertex if vertex && vertex.root?
144
137
  end
145
138
 
146
139
  # Adds a new {Edge} to the dependency graph
@@ -149,18 +142,24 @@ module Gem::Resolver::Molinillo
149
142
  # @param [Object] requirement the requirement that this edge represents
150
143
  # @return [Edge] the added edge
151
144
  def add_edge(origin, destination, requirement)
152
- if origin == destination || destination.path_to?(origin)
145
+ if destination.path_to?(origin)
153
146
  raise CircularDependencyError.new([origin, destination])
154
147
  end
155
- Edge.new(origin, destination, [requirement]).tap { |e| edges << e }
148
+ add_edge_no_circular(origin, destination, requirement)
149
+ end
150
+
151
+ private
152
+
153
+ def add_edge_no_circular(origin, destination, requirement)
154
+ edge = Edge.new(origin, destination, requirement)
155
+ origin.outgoing_edges << edge
156
+ destination.incoming_edges << edge
157
+ edge
156
158
  end
157
159
 
158
160
  # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
159
161
  # {#payload}
160
162
  class Vertex
161
- # @return [DependencyGraph] the graph this vertex is a node of
162
- attr_accessor :graph
163
-
164
163
  # @return [String] the name of the vertex
165
164
  attr_accessor :name
166
165
 
@@ -171,50 +170,62 @@ module Gem::Resolver::Molinillo
171
170
  # this vertex
172
171
  attr_reader :explicit_requirements
173
172
 
174
- # @param [DependencyGraph] graph see {#graph}
173
+ # @return [Boolean] whether the vertex is considered a root vertex
174
+ attr_accessor :root
175
+ alias_method :root?, :root
176
+
175
177
  # @param [String] name see {#name}
176
178
  # @param [Object] payload see {#payload}
177
- def initialize(graph, name, payload)
178
- @graph = graph
179
+ def initialize(name, payload)
179
180
  @name = name
180
181
  @payload = payload
181
182
  @explicit_requirements = []
183
+ @outgoing_edges = []
184
+ @incoming_edges = []
182
185
  end
183
186
 
184
187
  # @return [Array<Object>] all of the requirements that required
185
188
  # this vertex
186
189
  def requirements
187
- incoming_edges.map(&:requirements).flatten + explicit_requirements
190
+ incoming_edges.map(&:requirement) + explicit_requirements
188
191
  end
189
192
 
190
193
  # @return [Array<Edge>] the edges of {#graph} that have `self` as their
191
194
  # {Edge#origin}
192
- def outgoing_edges
193
- graph.edges.select { |e| e.origin.shallow_eql?(self) }
194
- end
195
+ attr_accessor :outgoing_edges
195
196
 
196
197
  # @return [Array<Edge>] the edges of {#graph} that have `self` as their
197
198
  # {Edge#destination}
198
- def incoming_edges
199
- graph.edges.select { |e| e.destination.shallow_eql?(self) }
200
- end
199
+ attr_accessor :incoming_edges
201
200
 
202
- # @return [Set<Vertex>] the vertices of {#graph} that have an edge with
201
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
203
202
  # `self` as their {Edge#destination}
204
203
  def predecessors
205
- incoming_edges.map(&:origin).to_set
204
+ incoming_edges.map(&:origin)
205
+ end
206
+
207
+ # @return [Array<Vertex>] the vertices of {#graph} where `self` is a
208
+ # {#descendent?}
209
+ def recursive_predecessors
210
+ vertices = predecessors
211
+ vertices += vertices.map(&:recursive_predecessors).flatten(1)
212
+ vertices.uniq!
213
+ vertices
206
214
  end
207
215
 
208
- # @return [Set<Vertex>] the vertices of {#graph} that have an edge with
216
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
209
217
  # `self` as their {Edge#origin}
210
218
  def successors
211
- outgoing_edges.map(&:destination).to_set
219
+ outgoing_edges.map(&:destination)
212
220
  end
213
221
 
214
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
222
+ # @return [Array<Vertex>] the vertices of {#graph} where `self` is an
215
223
  # {#ancestor?}
216
224
  def recursive_successors
217
- successors + successors.map(&:recursive_successors).reduce(Set.new, &:+)
225
+ vertices = successors
226
+ vertices += vertices.map(&:recursive_successors).flatten(1)
227
+ vertices.uniq!
228
+ vertices
218
229
  end
219
230
 
220
231
  # @return [String] a string suitable for debugging
@@ -226,7 +237,7 @@ module Gem::Resolver::Molinillo
226
237
  # by a recursive traversal of each {Vertex#successors}
227
238
  def ==(other)
228
239
  shallow_eql?(other) &&
229
- successors == other.successors
240
+ successors.to_set == other.successors.to_set
230
241
  end
231
242
 
232
243
  # @return [Boolean] whether the two vertices are equal, determined
@@ -248,7 +259,7 @@ module Gem::Resolver::Molinillo
248
259
  # dependency graph?
249
260
  # @return true iff there is a path following edges within this {#graph}
250
261
  def path_to?(other)
251
- successors.include?(other) || successors.any? { |v| v.path_to?(other) }
262
+ equal?(other) || successors.any? { |v| v.path_to?(other) }
252
263
  end
253
264
 
254
265
  alias_method :descendent?, :path_to?
@@ -257,7 +268,7 @@ module Gem::Resolver::Molinillo
257
268
  # dependency graph?
258
269
  # @return true iff there is a path following edges within this {#graph}
259
270
  def ancestor?(other)
260
- predecessors.include?(other) || predecessors.any? { |v| v.ancestor?(other) }
271
+ other.path_to?(self)
261
272
  end
262
273
 
263
274
  alias_method :is_reachable_from?, :ancestor?