bundler 1.10.6 → 1.11.0.pre.1

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

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +105 -0
  3. data/.rubocop_todo.yml +120 -0
  4. data/.travis.yml +8 -23
  5. data/CHANGELOG.md +69 -0
  6. data/CODE_OF_CONDUCT.md +6 -4
  7. data/DEVELOPMENT.md +4 -5
  8. data/README.md +2 -2
  9. data/Rakefile +70 -87
  10. data/bin/rake +14 -0
  11. data/bin/rspec +10 -0
  12. data/bin/rubocop +11 -0
  13. data/bundler.gemspec +17 -15
  14. data/exe/bundle +20 -0
  15. data/{bin → exe}/bundle_ruby +6 -4
  16. data/exe/bundler +20 -0
  17. data/lib/bundler.rb +98 -119
  18. data/lib/bundler/capistrano.rb +2 -2
  19. data/lib/bundler/cli.rb +85 -74
  20. data/lib/bundler/cli/binstubs.rb +1 -2
  21. data/lib/bundler/cli/cache.rb +0 -1
  22. data/lib/bundler/cli/check.rb +7 -5
  23. data/lib/bundler/cli/clean.rb +0 -1
  24. data/lib/bundler/cli/common.rb +6 -7
  25. data/lib/bundler/cli/config.rb +69 -56
  26. data/lib/bundler/cli/console.rb +8 -8
  27. data/lib/bundler/cli/exec.rb +4 -3
  28. data/lib/bundler/cli/gem.rb +50 -39
  29. data/lib/bundler/cli/init.rb +5 -6
  30. data/lib/bundler/cli/inject.rb +1 -2
  31. data/lib/bundler/cli/install.rb +18 -21
  32. data/lib/bundler/cli/lock.rb +8 -3
  33. data/lib/bundler/cli/open.rb +4 -5
  34. data/lib/bundler/cli/outdated.rb +7 -8
  35. data/lib/bundler/cli/package.rb +1 -1
  36. data/lib/bundler/cli/platform.rb +2 -3
  37. data/lib/bundler/cli/show.rb +9 -9
  38. data/lib/bundler/cli/update.rb +2 -3
  39. data/lib/bundler/cli/viz.rb +1 -2
  40. data/lib/bundler/constants.rb +1 -1
  41. data/lib/bundler/current_ruby.rb +38 -3
  42. data/lib/bundler/definition.rb +83 -88
  43. data/lib/bundler/dep_proxy.rb +11 -9
  44. data/lib/bundler/dependency.rb +26 -11
  45. data/lib/bundler/deployment.rb +2 -2
  46. data/lib/bundler/deprecate.rb +3 -3
  47. data/lib/bundler/dsl.rb +63 -44
  48. data/lib/bundler/env.rb +19 -12
  49. data/lib/bundler/environment.rb +1 -2
  50. data/lib/bundler/errors.rb +82 -0
  51. data/lib/bundler/fetcher.rb +45 -39
  52. data/lib/bundler/fetcher/base.rb +20 -7
  53. data/lib/bundler/fetcher/dependency.rb +5 -5
  54. data/lib/bundler/fetcher/downloader.rb +1 -2
  55. data/lib/bundler/fetcher/index.rb +4 -7
  56. data/lib/bundler/friendly_errors.rb +15 -8
  57. data/lib/bundler/gem_helper.rb +44 -35
  58. data/lib/bundler/gem_helpers.rb +7 -8
  59. data/lib/bundler/gem_remote_fetcher.rb +41 -0
  60. data/lib/bundler/gem_tasks.rb +4 -1
  61. data/lib/bundler/graph.rb +25 -24
  62. data/lib/bundler/index.rb +21 -18
  63. data/lib/bundler/injector.rb +2 -4
  64. data/lib/bundler/inline.rb +3 -3
  65. data/lib/bundler/installer.rb +57 -144
  66. data/lib/bundler/installer/gem_installer.rb +76 -0
  67. data/lib/bundler/installer/parallel_installer.rb +22 -13
  68. data/lib/bundler/installer/standalone.rb +48 -0
  69. data/lib/bundler/lazy_specification.rb +3 -4
  70. data/lib/bundler/lockfile_parser.rb +21 -19
  71. data/lib/bundler/match_platform.rb +4 -4
  72. data/lib/bundler/psyched_yaml.rb +3 -3
  73. data/lib/bundler/remote_specification.rb +1 -1
  74. data/lib/bundler/resolver.rb +93 -88
  75. data/lib/bundler/retry.rb +9 -10
  76. data/lib/bundler/ruby_dsl.rb +1 -1
  77. data/lib/bundler/ruby_version.rb +7 -10
  78. data/lib/bundler/rubygems_ext.rb +32 -27
  79. data/lib/bundler/{gem_installer.rb → rubygems_gem_installer.rb} +2 -2
  80. data/lib/bundler/rubygems_integration.rb +85 -70
  81. data/lib/bundler/runtime.rb +57 -61
  82. data/lib/bundler/settings.rb +27 -26
  83. data/lib/bundler/setup.rb +3 -3
  84. data/lib/bundler/shared_helpers.rb +45 -20
  85. data/lib/bundler/similarity_detector.rb +19 -21
  86. data/lib/bundler/source.rb +4 -5
  87. data/lib/bundler/source/git.rb +29 -31
  88. data/lib/bundler/source/git/git_proxy.rb +52 -26
  89. data/lib/bundler/source/path.rb +25 -28
  90. data/lib/bundler/source/path/installer.rb +4 -4
  91. data/lib/bundler/source/rubygems.rb +62 -48
  92. data/lib/bundler/source/rubygems/remote.rb +3 -3
  93. data/lib/bundler/source_list.rb +4 -4
  94. data/lib/bundler/spec_set.rb +17 -15
  95. data/lib/bundler/ssl_certs/certificate_manager.rb +5 -6
  96. data/lib/bundler/stub_specification.rb +2 -2
  97. data/lib/bundler/templates/Executable +5 -5
  98. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +42 -6
  99. data/lib/bundler/templates/newgem/README.md.tt +1 -1
  100. data/lib/bundler/templates/newgem/Rakefile.tt +4 -2
  101. data/lib/bundler/templates/newgem/bin/setup.tt +2 -1
  102. data/lib/bundler/templates/newgem/newgem.gemspec.tt +2 -2
  103. data/lib/bundler/ui.rb +3 -3
  104. data/lib/bundler/ui/rg_proxy.rb +2 -2
  105. data/lib/bundler/ui/shell.rb +10 -6
  106. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +82 -71
  107. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  108. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +9 -0
  109. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +40 -21
  110. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +8 -0
  111. data/lib/bundler/vendored_molinillo.rb +1 -1
  112. data/lib/bundler/vendored_persistent.rb +3 -3
  113. data/lib/bundler/vendored_thor.rb +2 -2
  114. data/lib/bundler/version.rb +1 -1
  115. data/lib/bundler/vlad.rb +1 -1
  116. data/lib/bundler/worker.rb +4 -5
  117. data/man/bundle-config.ronn +4 -2
  118. data/man/bundle-gem.ronn +77 -0
  119. data/man/bundle-install.ronn +13 -6
  120. data/man/bundle-lock.ronn +47 -0
  121. data/man/bundle.ronn +1 -1
  122. data/man/gemfile.5.ronn +8 -0
  123. data/man/index.txt +1 -0
  124. metadata +37 -8
  125. data/bin/bundle +0 -21
  126. data/bin/bundler +0 -21
@@ -1,4 +1,4 @@
1
- require 'bundler/remote_specification'
1
+ require "bundler/remote_specification"
2
2
 
3
3
  module Bundler
4
4
  class StubSpecification < RemoteSpecification
@@ -20,4 +20,4 @@ module Bundler
20
20
  stub.to_spec
21
21
  end
22
22
  end
23
- end
23
+ end
@@ -6,11 +6,11 @@
6
6
  # this file is here to facilitate running it.
7
7
  #
8
8
 
9
- require 'pathname'
10
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../<%= relative_gemfile_path %>",
9
+ require "pathname"
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../<%= relative_gemfile_path %>",
11
11
  Pathname.new(__FILE__).realpath)
12
12
 
13
- require 'rubygems'
14
- require 'bundler/setup'
13
+ require "rubygems"
14
+ require "bundler/setup"
15
15
 
16
- load Gem.bin_path('<%= spec.name %>', '<%= executable %>')
16
+ load Gem.bin_path("<%= spec.name %>", "<%= executable %>")
@@ -1,13 +1,49 @@
1
1
  # Contributor Code of Conduct
2
2
 
3
- As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
4
7
 
5
- We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
6
12
 
7
- Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
13
+ Examples of unacceptable behavior by participants include:
8
14
 
9
- Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
10
22
 
11
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
12
28
 
13
- This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at <%=config[:email]%>. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
@@ -32,7 +32,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
32
 
33
33
  ## Contributing
34
34
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.<% end %>
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.<% end %>
36
36
  <% if config[:mit] %>
37
37
 
38
38
  ## License
@@ -8,13 +8,11 @@ Rake::TestTask.new(:test) do |t|
8
8
  t.test_files = FileList['test/**/*_test.rb']
9
9
  end
10
10
 
11
- task :default => :test
12
11
  <% elsif config[:test] == 'rspec' -%>
13
12
  require "rspec/core/rake_task"
14
13
 
15
14
  RSpec::Core::RakeTask.new(:spec)
16
15
 
17
- task :default => :spec
18
16
  <% end -%>
19
17
  <% if config[:ext] -%>
20
18
  require "rake/extensiontask"
@@ -24,4 +22,8 @@ task :build => :compile
24
22
  Rake::ExtensionTask.new("<%=config[:underscored_name]%>") do |ext|
25
23
  ext.lib_dir = "lib/<%=config[:namespaced_path]%>"
26
24
  end
25
+
26
+ task :default => [:clobber, :compile, :<%= config[:test_task] %>]
27
+ <% else -%>
28
+ task :default => :<%= config[:test_task] %>
27
29
  <% end -%>
@@ -1,6 +1,7 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
  IFS=$'\n\t'
4
+ set -vx
4
5
 
5
6
  bundle install
6
7
 
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  <%- if config[:ext] -%>
38
38
  spec.add_development_dependency "rake-compiler"
39
39
  <%- end -%>
40
- <%- if config[:test] && config[:test] != "false" -%>
41
- spec.add_development_dependency "<%=config[:test]%>"
40
+ <%- if config[:test] -%>
41
+ spec.add_development_dependency "<%=config[:test]%>", "~> <%=config[:test_framework_version]%>"
42
42
  <%- end -%>
43
43
  end
@@ -1,7 +1,7 @@
1
1
  module Bundler
2
2
  module UI
3
- autoload :RGProxy, 'bundler/ui/rg_proxy'
4
- autoload :Shell, 'bundler/ui/shell'
5
- autoload :Silent, 'bundler/ui/silent'
3
+ autoload :RGProxy, "bundler/ui/rg_proxy"
4
+ autoload :Shell, "bundler/ui/shell"
5
+ autoload :Silent, "bundler/ui/silent"
6
6
  end
7
7
  end
@@ -1,5 +1,5 @@
1
- require 'bundler/ui'
2
- require 'rubygems/user_interaction'
1
+ require "bundler/ui"
2
+ require "rubygems/user_interaction"
3
3
 
4
4
  module Bundler
5
5
  module UI
@@ -1,4 +1,4 @@
1
- require 'bundler/vendored_thor'
1
+ require "bundler/vendored_thor"
2
2
 
3
3
  module Bundler
4
4
  module UI
@@ -12,7 +12,8 @@ module Bundler
12
12
  Thor::Base.shell = Thor::Shell::Basic
13
13
  end
14
14
  @shell = Thor::Base.shell.new
15
- @level = ENV['DEBUG'] ? "debug" : "info"
15
+ @level = ENV["DEBUG"] ? "debug" : "info"
16
+ @warning_history = []
16
17
  end
17
18
 
18
19
  def info(msg, newline = nil)
@@ -24,6 +25,8 @@ module Bundler
24
25
  end
25
26
 
26
27
  def warn(msg, newline = nil)
28
+ return if @warning_history.include? msg
29
+ @warning_history << msg
27
30
  tell_me(msg, :yellow, newline) if level("warn")
28
31
  end
29
32
 
@@ -65,14 +68,15 @@ module Bundler
65
68
  name ? LEVELS.index(name) <= LEVELS.index(@level) : @level
66
69
  end
67
70
 
68
- def trace(e, newline = nil)
69
- return unless debug?
71
+ def trace(e, newline = nil, force = false)
72
+ return unless debug? || force
70
73
  msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}"
71
74
  tell_me(msg, nil, newline)
72
75
  end
73
76
 
74
77
  def silence
75
- old_level, @level = @level, "silent"
78
+ old_level = @level
79
+ @level = "silent"
76
80
  yield
77
81
  ensure
78
82
  @level = old_level
@@ -92,7 +96,7 @@ module Bundler
92
96
 
93
97
  def strip_leading_spaces(text)
94
98
  spaces = text[/\A\s+/, 0]
95
- spaces ? text.gsub(/#{spaces}/, '') : text
99
+ spaces ? text.gsub(/#{spaces}/, "") : text
96
100
  end
97
101
 
98
102
  def word_wrap(text, line_width = @shell.terminal_width)
@@ -34,40 +34,34 @@ module Bundler::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 Bundler::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 Bundler::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 Bundler::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 Bundler::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 Bundler::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 Bundler::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 Bundler::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 Bundler::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 Bundler::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 Bundler::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?