rubygems-update 2.5.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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?