build-dependency 1.5.1 → 1.6.0

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/build/dependency/chain.rb +13 -22
  4. data/lib/build/dependency/partial_chain.rb +18 -21
  5. data/lib/build/dependency/provider.rb +28 -27
  6. data/lib/build/dependency/resolver.rb +12 -21
  7. data/lib/build/dependency/set.rb +27 -20
  8. data/lib/build/dependency/version.rb +7 -20
  9. data/lib/build/dependency/visualization.rb +58 -122
  10. data/lib/build/dependency.rb +9 -24
  11. data/license.md +21 -0
  12. data/readme.md +64 -0
  13. data/releases.md +5 -0
  14. data/test/build/dependency/chain.rb +223 -0
  15. data/test/build/dependency/partial_chain.rb +121 -0
  16. data/test/build/dependency/provider.rb +189 -0
  17. data/test/build/dependency/set.rb +122 -0
  18. data/test/build/dependency/visualization.rb +21 -0
  19. data/test/build/dependency/wildcard.rb +38 -0
  20. data.tar.gz.sig +1 -0
  21. metadata +49 -113
  22. metadata.gz.sig +0 -0
  23. data/.gitignore +0 -23
  24. data/.rspec +0 -4
  25. data/.travis.yml +0 -17
  26. data/Gemfile +0 -14
  27. data/Guardfile +0 -9
  28. data/README.md +0 -214
  29. data/Rakefile +0 -8
  30. data/build-dependency.gemspec +0 -24
  31. data/build_system_rules_and_algorithms.pdf +0 -0
  32. data/full.svg +0 -123
  33. data/partial.svg +0 -93
  34. data/spec/build/dependency/chain_spec.rb +0 -218
  35. data/spec/build/dependency/package.rb +0 -89
  36. data/spec/build/dependency/partial_chain_spec.rb +0 -119
  37. data/spec/build/dependency/provider_spec.rb +0 -123
  38. data/spec/build/dependency/set_spec.rb +0 -87
  39. data/spec/build/dependency/visualization_spec.rb +0 -33
  40. data/spec/build/dependency/wildcard_spec.rb +0 -45
  41. data/spec/spec_helper.rb +0 -12
  42. data/visualization.svg +0 -147
@@ -1,28 +1,13 @@
1
- # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
1
+ # frozen_string_literal: true
20
2
 
21
- require_relative 'dependency/version'
3
+ # Released under the MIT License.
4
+ # Copyright, 2017-2026, by Samuel Williams.
22
5
 
23
- require_relative 'dependency/provider'
6
+ require_relative "dependency/version"
24
7
 
25
- require_relative 'dependency/chain'
26
- require_relative 'dependency/partial_chain'
8
+ require_relative "dependency/provider"
27
9
 
28
- require_relative 'dependency/visualization'
10
+ require_relative "dependency/chain"
11
+ require_relative "dependency/partial_chain"
12
+
13
+ require_relative "dependency/visualization"
data/license.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright, 2017-2026, by Samuel Williams.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/readme.md ADDED
@@ -0,0 +1,64 @@
1
+ # Build::Dependency
2
+
3
+ Build::Dependency provides dependency resolution algorithms.
4
+
5
+ [![Development Status](https://github.com/ioquatix/build-dependency/workflows/Test/badge.svg)](https://github.com/ioquatix/build-dependency/actions?workflow=Test)
6
+
7
+ ## Motivation
8
+
9
+ Build::Dependency helps you resolve complex dependency graphs in your build systems and applications. It supports:
10
+
11
+ - **Full dependency resolution** with automatic ordering
12
+ - **Partial chains** for incremental builds
13
+ - **Private dependencies** that don't leak to dependents
14
+ - **Wildcard matching** for batch dependencies
15
+ - **Mermaid visualization** for diagram generation
16
+
17
+ ## Usage
18
+
19
+ Please see the [project documentation](https://ioquatix.github.io/build-dependency/) for more details.
20
+
21
+ - [Getting Started](https://ioquatix.github.io/build-dependency/guides/getting-started/index) - This guide explains how to use `build-dependency` for dependency resolution in your projects.
22
+
23
+ ## Releases
24
+
25
+ Please see the [project releases](https://ioquatix.github.io/build-dependency/releases/index) for all releases.
26
+
27
+ ### v1.6.0
28
+
29
+ - Change visualization to use Mermaid flowcharts for better readability and diagram generation.
30
+
31
+ ## See Also
32
+
33
+ - [build](https://github.com/ioquatix/build) — General build system using dependency resolution.
34
+ - [teapot](https://github.com/ioquatix/teapot) — Package management using dependency resolution.
35
+
36
+ ## Contributing
37
+
38
+ We welcome contributions to this project.
39
+
40
+ 1. Fork it.
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
42
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
43
+ 4. Push to the branch (`git push origin my-new-feature`).
44
+ 5. Create new Pull Request.
45
+
46
+ ### Running Tests
47
+
48
+ To run the test suite:
49
+
50
+ ``` shell
51
+ bundle exec sus
52
+ ```
53
+
54
+ ### Making Releases
55
+
56
+ Please see the [project releases](https://ioquatix.github.io/build-dependency/releases/index) for all releases.
57
+
58
+ ### Developer Certificate of Origin
59
+
60
+ In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
61
+
62
+ ### Community Guidelines
63
+
64
+ This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
data/releases.md ADDED
@@ -0,0 +1,5 @@
1
+ # Releases
2
+
3
+ ## v1.6.0
4
+
5
+ - Change visualization to use Mermaid flowcharts for better readability and diagram generation.
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2017-2026, by Samuel Williams.
5
+
6
+ require "build/dependency_context"
7
+
8
+ describe Build::Dependency do
9
+ with "valid dependency resolution" do
10
+ let(:a) do
11
+ Build::DependencyContext::Package.new("apple-tree").tap do |package|
12
+ package.provides "apple" do
13
+ fruit ["apple"]
14
+ end
15
+ end
16
+ end
17
+
18
+ let(:b) do
19
+ Build::DependencyContext::Package.new("orange-tree").tap do |package|
20
+ package.provides "orange" do
21
+ fruit ["orange"]
22
+ end
23
+ end
24
+ end
25
+
26
+ let(:c) do
27
+ Build::DependencyContext::Package.new("blender").tap do |package|
28
+ package.provides "fruit-juice" do
29
+ juice ["ice", "cold"]
30
+ end
31
+
32
+ package.depends "apple"
33
+ package.depends "orange"
34
+ end
35
+ end
36
+
37
+ it "should resolve direct dependency chain" do
38
+ chain = Build::Dependency::Chain.expand(["fruit-juice"], [a, b, c])
39
+ expect(chain.ordered.collect(&:provider)).to be == [a, b, c]
40
+ expect(chain.unresolved).to be == []
41
+ end
42
+
43
+ it "should resolve wildcard dependency chain" do
44
+ chain = Build::Dependency::Chain.expand(["fruit-*"], [a, b, c])
45
+ expect(chain.ordered.collect(&:provider)).to be == [a, b, c]
46
+ expect(chain.unresolved).to be == []
47
+ end
48
+
49
+ let(:d) do
50
+ Build::DependencyContext::Package.new("bakery").tap do |package|
51
+ package.provides "pie"
52
+ package.depends "apple"
53
+ end
54
+ end
55
+
56
+ it "shouldn't include unrelated units" do
57
+ chain = Build::Dependency::Chain.expand(["pie"], [a, b, c, d])
58
+
59
+ expect(chain.unresolved).to be == []
60
+ expect(chain.ordered.collect(&:provider)).to be == [a, d]
61
+ end
62
+
63
+ it "should format nicely" do
64
+ chain = Build::Dependency::Chain.expand(["fruit-juice"], [a, b, c])
65
+ resolution = chain.ordered.first
66
+ expect(resolution.to_s).to be == 'resolution "apple-tree" -> "apple"'
67
+ end
68
+ end
69
+
70
+ with "incomplete dependency resolution" do
71
+ it "should report conflicts" do
72
+ apple = Build::DependencyContext::Package.new("apple")
73
+ apple.provides "apple"
74
+ apple.provides "fruit"
75
+
76
+ bananna = Build::DependencyContext::Package.new("bananna")
77
+ bananna.provides "fruit"
78
+
79
+ salad = Build::DependencyContext::Package.new("salad")
80
+ salad.depends "fruit"
81
+ salad.provides "salad"
82
+
83
+ chain = Build::Dependency::Chain.new(["salad"], [apple, bananna, salad])
84
+ expect(chain.unresolved.first).to be == [Build::Dependency::Depends.new("fruit"), salad]
85
+ expect(chain.conflicts).to be == {Build::Dependency::Depends.new("fruit") => [apple, bananna]}
86
+
87
+ chain = Build::Dependency::Chain.new(["salad"], [apple, bananna, salad], ["apple"])
88
+ expect(chain.unresolved).to be == []
89
+ expect(chain.conflicts).to be == {}
90
+ end
91
+ end
92
+
93
+ with "multiple provisions" do
94
+ let(:fruit) do
95
+ Build::DependencyContext::Package.new("fruit").tap do |package|
96
+ package.provides "apple" do
97
+ end
98
+
99
+ package.provides "orange" do
100
+ end
101
+ end
102
+ end
103
+
104
+ let(:salad) do
105
+ Build::DependencyContext::Package.new("salad").tap do |package|
106
+ package.depends "apple"
107
+ package.depends "orange"
108
+ package.provides "salad"
109
+ end
110
+ end
111
+
112
+ let(:lunch) do
113
+ Build::DependencyContext::Package.new("lunch").tap do |package|
114
+ package.depends "apple"
115
+ package.depends "salad"
116
+ package.provides "lunch"
117
+ end
118
+ end
119
+
120
+ let(:chain) {Build::Dependency::Chain.new(["lunch"], [fruit, salad, lunch])}
121
+
122
+ it "should include both provisions" do
123
+ expect(chain.provisions.count).to be == 4
124
+ expect(chain.provisions.collect(&:name)).to be == ["apple", "orange", "salad", "lunch"]
125
+ end
126
+
127
+ it "should include both provisions in partial chain" do
128
+ partial_chain = chain.partial(lunch)
129
+ expect(partial_chain.provisions.count).to be == 3
130
+ expect(partial_chain.provisions.collect(&:name)).to be == ["apple", "orange", "salad"]
131
+ end
132
+ end
133
+
134
+ it "should resolve aliases" do
135
+ apple = Build::DependencyContext::Package.new("apple")
136
+ apple.provides "apple"
137
+ apple.provides :fruit => "apple"
138
+
139
+ bananna = Build::DependencyContext::Package.new("bananna")
140
+ bananna.provides "bananna"
141
+ bananna.provides :fruit => "bananna"
142
+
143
+ salad = Build::DependencyContext::Package.new("salad")
144
+ salad.depends :fruit
145
+ salad.provides "salad"
146
+
147
+ chain = Build::Dependency::Chain.expand(["salad"], [apple, bananna, salad], ["apple"])
148
+ expect(chain.unresolved).to be == []
149
+ expect(chain.conflicts).to be == {}
150
+
151
+ expect(chain.ordered.size).to be == 2
152
+ expect(chain.ordered[0].provider).to be == apple
153
+ expect(chain.ordered[1].provider).to be == salad
154
+ end
155
+
156
+ it "should select dependencies with high priority" do
157
+ bad_apple = Build::DependencyContext::Package.new("bad_apple")
158
+ bad_apple.provides "apple"
159
+ bad_apple.priority = 20
160
+
161
+ good_apple = Build::DependencyContext::Package.new("good_apple")
162
+ good_apple.provides "apple"
163
+ good_apple.priority = 40
164
+
165
+ chain = Build::Dependency::Chain.expand(["apple"], [bad_apple, good_apple])
166
+
167
+ expect(chain.unresolved).to be == []
168
+ expect(chain.conflicts).to be == {}
169
+
170
+ # Should select higher priority package by default:
171
+ expect(chain.ordered).to be == [good_apple.resolution_for(
172
+ Build::Dependency::Depends["apple"]
173
+ )]
174
+ end
175
+
176
+ it "should expose direct dependencies" do
177
+ system = Build::DependencyContext::Package.new("linux")
178
+ system.provides "linux"
179
+ system.provides "clang"
180
+ system.provides system: "linux"
181
+ system.provides compiler: "clang"
182
+
183
+ library = Build::DependencyContext::Package.new("library")
184
+ library.provides "library"
185
+ library.depends :system
186
+ library.depends :compiler
187
+
188
+ application = Build::DependencyContext::Package.new("application")
189
+ application.provides "application"
190
+ application.depends :compiler
191
+ application.depends "library"
192
+
193
+ chain = Build::Dependency::Chain.expand(["application"], [system, library, application])
194
+
195
+ expect(chain.unresolved).to be == []
196
+ expect(chain.conflicts).to be == {}
197
+ expect(chain.ordered).to be == [
198
+ system.resolution_for(Build::Dependency::Depends.new("clang")),
199
+ library.resolution_for(Build::Dependency::Depends.new("library")),
200
+ application.resolution_for(Build::Dependency::Depends.new("application")),
201
+ ]
202
+ end
203
+
204
+ it "should raise UnresolvedDependencyError when expanding with unresolved dependencies" do
205
+ missing = Build::DependencyContext::Package.new("missing")
206
+ missing.provides "missing"
207
+ missing.depends "does-not-exist"
208
+
209
+ expect do
210
+ Build::Dependency::Chain.expand(["missing"], [missing])
211
+ end.to raise_exception(Build::Dependency::UnresolvedDependencyError)
212
+ end
213
+
214
+ it "can freeze a chain" do
215
+ apple = Build::DependencyContext::Package.new("apple")
216
+ apple.provides "apple"
217
+
218
+ chain = Build::Dependency::Chain.new(["apple"], [apple])
219
+
220
+ expect(chain.freeze).to be == chain
221
+ expect(chain).to be(:frozen?)
222
+ end
223
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2017-2026, by Samuel Williams.
5
+
6
+ require "build/dependency_context"
7
+
8
+ describe Build::Dependency::PartialChain do
9
+ with "app chain" do
10
+ include Build::DependencyContext::AppPackages
11
+
12
+ let(:chain) {Build::Dependency::Chain.expand(["app", "lib"], packages)}
13
+
14
+ it "should generate full list of ordered providers" do
15
+ expect(chain.ordered).to be == [
16
+ variant.resolution_for(Build::Dependency::Depends.new("Variant/debug")),
17
+ platform.resolution_for(Build::Dependency::Depends.new("Platform/linux")),
18
+ compiler.resolution_for(Build::Dependency::Depends.new("Language/C++17", private: true)),
19
+ lib.resolution_for(Build::Dependency::Depends.new("lib", private: true)),
20
+ app.resolution_for(Build::Dependency::Depends.new("app")),
21
+ ]
22
+ end
23
+
24
+ it "should generate a full list of provisions" do
25
+ expect(chain.provisions).to be == [
26
+ variant.provision_for(Build::Dependency::Depends.new("Variant/debug")),
27
+ platform.provision_for(Build::Dependency::Depends.new("Platform/linux")),
28
+ compiler.provision_for(Build::Dependency::Depends.new("Language/C++17", private: true)),
29
+ lib.provision_for(Build::Dependency::Depends.new("lib", private: true)),
30
+ compiler.provision_for(Build::Dependency::Depends.new("Language/C++14", private: true)),
31
+ app.provision_for(Build::Dependency::Depends.new("app")),
32
+ lib.provision_for(Build::Dependency::Depends.new("lib")),
33
+ ]
34
+
35
+ # Generate mermaid diagram
36
+ expect(visualization.generate(chain)).to be_a(String)
37
+ end
38
+
39
+ let(:subject) {Build::Dependency::PartialChain.new(chain, app.dependencies)}
40
+
41
+ it "should select app packages" do
42
+ expect(subject.ordered).to be == [
43
+ variant.resolution_for(Build::Dependency::Depends.new("Variant/debug")),
44
+ platform.resolution_for(Build::Dependency::Depends.new("Platform/linux")),
45
+ lib.resolution_for(Build::Dependency::Depends.new("lib", private: true)),
46
+ compiler.resolution_for(Build::Dependency::Depends.new("Language/C++14", private: true)),
47
+ ]
48
+
49
+ # Generate mermaid diagram
50
+ expect(visualization.generate(subject)).to be_a(String)
51
+ end
52
+ end
53
+
54
+ with "private dependencies" do
55
+ let(:a) do
56
+ Build::DependencyContext::Package.new("a").tap do |package|
57
+ package.provides "a"
58
+ end
59
+ end
60
+
61
+ let(:b) do
62
+ Build::DependencyContext::Package.new("b").tap do |package|
63
+ package.provides "b"
64
+ package.depends "a", private: true
65
+ end
66
+ end
67
+
68
+ let(:c) do
69
+ Build::DependencyContext::Package.new("c").tap do |package|
70
+ package.provides "c"
71
+ package.depends "b"
72
+ end
73
+ end
74
+
75
+ let(:d) do
76
+ Build::DependencyContext::Package.new("d").tap do |package|
77
+ package.provides "d"
78
+ package.depends "c"
79
+ end
80
+ end
81
+
82
+ let(:chain) {Build::Dependency::Chain.expand(["d"], [a, b, c, d])}
83
+
84
+ it "should include direct private dependencies" do
85
+ partial_chain = chain.partial(b)
86
+
87
+ expect(partial_chain.ordered.collect(&:provider)).to be == [a]
88
+ end
89
+
90
+ it "shouldn't include nested private dependencies" do
91
+ partial_chain = chain.partial(c)
92
+
93
+ expect(partial_chain.ordered.collect(&:provider)).to be == [b]
94
+ end
95
+
96
+ it "should follow non-private dependencies" do
97
+ partial_chain = chain.partial(d)
98
+
99
+ expect(partial_chain.ordered.collect(&:provider)).to be == [b, c]
100
+ end
101
+
102
+ it "should access underlying chain selection" do
103
+ partial_chain = chain.partial(d)
104
+
105
+ expect(partial_chain.selection).to be == chain.selection
106
+ end
107
+
108
+ it "should access underlying chain providers" do
109
+ partial_chain = chain.partial(d)
110
+
111
+ expect(partial_chain.providers).to be == chain.providers
112
+ end
113
+
114
+ it "can freeze a partial chain" do
115
+ partial_chain = chain.partial(d)
116
+
117
+ expect(partial_chain.freeze).to be == partial_chain
118
+ expect(partial_chain).to be(:frozen?)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2017-2026, by Samuel Williams.
5
+
6
+ require "build/dependency_context"
7
+
8
+ describe Build::Dependency::Provider do
9
+ include Build::DependencyContext::AppPackages
10
+
11
+ let(:provider) do
12
+ Build::DependencyContext::Package.new("test").tap do |package|
13
+ package.depends "a", private: true
14
+ package.depends "b", public: true
15
+ package.depends :variant
16
+
17
+ package.provides "c" do
18
+ puts "Hello World"
19
+ end
20
+
21
+ package.provides platform: "linux"
22
+ end
23
+ end
24
+
25
+ it "should have specified dependencies" do
26
+ expect(provider.dependencies.count).to be == 3
27
+ end
28
+
29
+ it "should have specified provisions" do
30
+ expect(provider.provisions.count).to be == 2
31
+ end
32
+
33
+ with Build::Dependency::Provision do
34
+ let(:subject) {provider.provisions["c"]}
35
+
36
+ it "should have name" do
37
+ expect(subject.name).to be == "c"
38
+ end
39
+
40
+ it "should not be an alias" do
41
+ expect(subject).not.to be(:alias?)
42
+ end
43
+
44
+ it "should format nicely" do
45
+ expect(subject.to_s).to be == 'provides "c"'
46
+ end
47
+ end
48
+
49
+ with "Build::Dependency::Depends (private)" do
50
+ let(:subject) {provider.dependencies["a"]}
51
+
52
+ it "should have a name" do
53
+ expect(subject.name).to be == "a"
54
+ end
55
+
56
+ it "should not be an alias" do
57
+ expect(subject).not.to be(:alias?)
58
+ end
59
+
60
+ it "should format nicely" do
61
+ expect(subject.to_s).to be == "depends on \"a\" #{{private: true}.inspect}"
62
+ end
63
+
64
+ it "should be private" do
65
+ expect(subject).to be(:private?)
66
+ end
67
+
68
+ it "should not be public" do
69
+ expect(subject).not.to be(:public?)
70
+ end
71
+ end
72
+
73
+ with "Build::Dependency::Depends (public)" do
74
+ let(:subject) {provider.dependencies["b"]}
75
+
76
+ it "should be public" do
77
+ expect(subject).to be(:public?)
78
+ end
79
+
80
+ it "should not be private" do
81
+ expect(subject).not.to be(:private?)
82
+ end
83
+ end
84
+
85
+ with "Build::Dependency::Depends (variant)" do
86
+ let(:subject) {provider.dependencies[:variant]}
87
+
88
+ it "should not be public" do
89
+ expect(subject).not.to be(:public?)
90
+ end
91
+
92
+ it "should not be private" do
93
+ expect(subject).not.to be(:private?)
94
+ end
95
+ end
96
+
97
+ with Build::Dependency::Alias do
98
+ let(:subject) {provider.provisions[:platform]}
99
+
100
+ it "should be an alias" do
101
+ expect(subject).to be(:alias?)
102
+ end
103
+
104
+ it "should format nicely" do
105
+ expect(subject.to_s).to be == 'provides :platform -> "linux"'
106
+ end
107
+
108
+ it "should enumerate dependencies" do
109
+ # Create a package with an alias that has dependencies
110
+ pkg = Build::DependencyContext::Package.new("multi-platform")
111
+ pkg.provides :os => ["linux", "darwin"]
112
+
113
+ alias_provision = pkg.provisions[:os]
114
+ expect(alias_provision).to be(:alias?)
115
+
116
+ # Check the raw dependencies array first
117
+ expect(alias_provision.dependencies).to be == ["linux", "darwin"]
118
+
119
+ # Enumerate with a block
120
+ dependencies = []
121
+ alias_provision.each_dependency do |dep|
122
+ dependencies << dep
123
+ end
124
+
125
+ expect(dependencies.size).to be == 2
126
+ expect(dependencies[0]).to be_a(Build::Dependency::Depends)
127
+ expect(dependencies[0].name).to be == "linux"
128
+ expect(dependencies[1]).to be_a(Build::Dependency::Depends)
129
+ expect(dependencies[1].name).to be == "darwin"
130
+ end
131
+ end
132
+
133
+ it "should check dependencies" do
134
+ a_dep = Build::Dependency::Depends.new("a")
135
+ b_dep = Build::Dependency::Depends.new("b")
136
+ missing_dep = Build::Dependency::Depends.new("does-not-exist")
137
+
138
+ expect(provider.dependencies).to be(:include?, a_dep)
139
+ expect(provider.dependencies).to be(:include?, b_dep)
140
+ expect(provider.dependencies).not.to be(:include?, missing_dep)
141
+ end
142
+
143
+ with Build::Dependency::Provision do
144
+ let(:provision) {provider.provisions["c"]}
145
+
146
+ it "should enumerate provider dependencies" do
147
+ # Each provision can enumerate its provider's dependencies
148
+ dependencies = []
149
+ provision.each_dependency do |dep|
150
+ dependencies << dep
151
+ end
152
+
153
+ expect(dependencies.size).to be == 3
154
+ expect(dependencies).to be(:include?, Build::Dependency::Depends.new("a", private: true))
155
+ end
156
+ end
157
+
158
+ with Build::Dependency::Resolution do
159
+ let(:simple_provider) do
160
+ Build::DependencyContext::Package.new("simple").tap do |package|
161
+ package.provides "simple"
162
+ end
163
+ end
164
+
165
+ let(:chain) {Build::Dependency::Chain.expand(["simple"], [simple_provider])}
166
+ let(:resolution) {chain.ordered.first}
167
+
168
+ it "should have name from dependency" do
169
+ expect(resolution.name).to be == "simple"
170
+ end
171
+ end
172
+
173
+ with "Depends without options" do
174
+ let(:simple_dep) {Build::Dependency::Depends.new("simple")}
175
+
176
+ it "should format without options" do
177
+ expect(simple_dep.to_s).to be == 'depends on "simple"'
178
+ end
179
+ end
180
+
181
+ it "can freeze a provider" do
182
+ pkg = Build::DependencyContext::Package.new("frozen")
183
+ pkg.provides "frozen"
184
+ pkg.depends "something"
185
+
186
+ expect(pkg.freeze).to be == pkg
187
+ expect(pkg).to be(:frozen?)
188
+ end
189
+ end