gem_metadata 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ require 'rspec/collection_matchers'
21
+ require 'temporary_directory'
22
+
23
+ World(GodObject::TemporaryDirectory::Helper.new(name_prefix: 'gem_metadata_cucumber'))
24
+
25
+ After do
26
+ ensure_absence_of_temporary_directory
27
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GemDependencies
21
+ def gem_dependencies
22
+ @gem_dependencies ||= []
23
+ end
24
+
25
+ def create_gem_dependency(name:, gemspec_content: gemspec_for(gem_name: name))
26
+ gem_directory = temporary_directory / name
27
+ gem_directory.mkdir
28
+
29
+ gemspec_file = gem_directory / "#{name}.gemspec"
30
+ gemspec_file.write(gemspec_content)
31
+
32
+ gem_dependencies << name
33
+
34
+ gem_directory
35
+ end
36
+
37
+ def gemspec_for(gem_name:, additional_content: nil)
38
+ <<-GEMSPEC
39
+ Gem::Specification.new do |gem|
40
+ gem.name = '#{gem_name}'
41
+ gem.version = '1.0.0'
42
+
43
+ gem.summary = 'This serves as an example for a gem.'
44
+ gem.description = 'This serves as an example for a gem.'
45
+
46
+ gem.authors = %w{somebody}
47
+ gem.email = %w{somebody@example.org}
48
+ gem.homepage = 'http://example.org'
49
+
50
+ #{additional_content}
51
+ end
52
+ GEMSPEC
53
+ end
54
+ end
55
+
56
+ World(GemDependencies)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module Project
21
+ def project_root_directory
22
+ @project_root_directory ||= Pathname.new(__dir__) / '..' / '..'
23
+ end
24
+ end
25
+
26
+ World(Project)
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module SeparateEnvironmentEvaluation
21
+ class ExecutionResult
22
+ attr_reader :return_value, :console_output
23
+
24
+ def initialize(process_status: $CHILD_STATUS, console_output:)
25
+ @process_status = process_status
26
+ @console_output = console_output
27
+ end
28
+
29
+ def success?
30
+ @process_status.success?
31
+ end
32
+ end
33
+
34
+ class ObjectExecutionResult < ExecutionResult
35
+ def object_output
36
+ fail "Execution failed" unless success?
37
+
38
+ Marshal.load(@console_output)
39
+ end
40
+ end
41
+
42
+ def evaluation_result
43
+ @evaluation_result ||= @execution_result.object_output
44
+ end
45
+
46
+ def write_code_as_function_into_file(code)
47
+ code_file = temporary_directory / 'code.rb'
48
+ code_file.write(<<~CODE)
49
+ def code_to_execute
50
+ #{code}
51
+ end
52
+ CODE
53
+
54
+ code_file
55
+ end
56
+
57
+ def evaluate_in_separate_environment(command)
58
+ output = execute_in_separate_environment(command)
59
+
60
+ @execution_result = ObjectExecutionResult.new(console_output: output)
61
+ end
62
+ end
63
+
64
+ World(SeparateEnvironmentEvaluation)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ require 'English'
21
+
22
+ module SeparateEnvironmentExecution
23
+ def execute_in_separate_environment(command)
24
+ Bundler.with_clean_env do
25
+ Dir.chdir(temporary_directory) do
26
+ @output = `#{command}`
27
+ end
28
+ end
29
+ end
30
+
31
+ def create_gemfile(include_gems: [])
32
+ gemfile = temporary_directory / 'Gemfile'
33
+
34
+ gemfile.open('w') do |io|
35
+ io.puts(%(gem 'gem_metadata', path: '#{project_root_directory}'))
36
+
37
+ include_gems.each do |gem_name|
38
+ io.puts(%(gem '#{gem_name}', path: '#{gem_name}'))
39
+ end
40
+ end
41
+
42
+ gemfile
43
+ end
44
+ end
45
+
46
+ World(SeparateEnvironmentExecution)
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ require 'English'
21
+ require_relative 'lib/god_object/gem_metadata/version'
22
+
23
+ Gem::Specification.new do |gem|
24
+ gem.name = 'gem_metadata'
25
+ gem.version = GodObject::GemMetadata::VERSION.dup
26
+ gem.authors = ['Alexander E. Fischer']
27
+ gem.email = ['aef@godobject.net']
28
+ gem.description = <<-DESCRIPTION
29
+ GemMetadata is a Ruby library that allows to filter and access gems by custom
30
+ metadata keys that their specifications contain.
31
+ DESCRIPTION
32
+ gem.summary = 'Filter and access gems depending on metadata they contain'
33
+ gem.homepage = 'https://www.godobject.net/'
34
+ gem.license = 'ISC'
35
+ gem.has_rdoc = 'yard'
36
+ gem.extra_rdoc_files = %w(HISTORY.md LICENSE.md)
37
+ gem.rubyforge_project = nil
38
+
39
+ `git ls-files 2> /dev/null`
40
+
41
+ if $CHILD_STATUS.success?
42
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
43
+ else
44
+ gem.files = `ls -1`.split($OUTPUT_RECORD_SEPARATOR)
45
+ end
46
+
47
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
48
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
49
+ gem.require_paths = %w(lib)
50
+
51
+ gem.required_ruby_version = '>= 2.3.0'
52
+
53
+ gem.add_development_dependency('rake')
54
+ gem.add_development_dependency('bundler')
55
+ gem.add_development_dependency('rspec', '~> 3.5')
56
+ gem.add_development_dependency('rspec-collection_matchers', '~> 1.1')
57
+ gem.add_development_dependency('cucumber', '~> 2.4')
58
+ gem.add_development_dependency('temporary_directory', '= 0.1.0')
59
+ gem.add_development_dependency('simplecov')
60
+ gem.add_development_dependency('pry')
61
+ gem.add_development_dependency('yard')
62
+ gem.add_development_dependency('kramdown')
63
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ require_relative 'god_object/gem_metadata'
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module GemMetadata
22
+ end
23
+ end
24
+
25
+ require_relative 'gem_metadata/version'
26
+ require_relative 'gem_metadata/service'
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject::GemMetadata
21
+ class Service
22
+ def initialize(gems: ::Gem.loaded_specs.values)
23
+ @gems = gems
24
+ end
25
+
26
+ def find_gems_providing(metadata_key)
27
+ @gems.select { |gem| gem.metadata.key?(metadata_key) }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module GemMetadata
22
+
23
+ # The currently loaded version.
24
+ #
25
+ # Using Semantic Versioning (2.0.0) rules
26
+ # @see http://semver.org/spec/v2.0.0.html
27
+ VERSION = '0.1.0'
28
+
29
+ end
30
+ end
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+ =begin
3
+ Copyright Alexander E. Fischer <aef@godobject.net>, 2016
4
+
5
+ This file is part of GemMetadata.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject::GemMetadata
21
+
22
+ describe Service do
23
+ shared_context 'only one gem was provided at construction' do
24
+ let(:constructor_arguments) { [gems: gems] }
25
+ let(:gems) { [gem_specification] }
26
+ let(:gem_specification) { instance_spy(::Gem::Specification, :specification, name: gem_name).as_null_object }
27
+ let(:gem_name) { 'some_gem' }
28
+ end
29
+
30
+ shared_context 'two gems were provided at construction' do
31
+ let(:constructor_arguments) { [gems: gems] }
32
+ let(:gems) { [first_gem_specification, second_gem_specification] }
33
+ let(:first_gem_specification) { instance_spy(::Gem::Specification, :first_specification, name: first_gem_name).as_null_object }
34
+ let(:first_gem_name) { 'some_gem' }
35
+
36
+ let(:second_gem_specification) { instance_spy(::Gem::Specification, :second_specification, name: second_gem_name).as_null_object }
37
+ let(:second_gem_name) { 'other_gem' }
38
+ end
39
+
40
+ let(:service) { described_class.new(*constructor_arguments) }
41
+
42
+ describe '.new' do
43
+ subject(:method_call) { described_class.new(*arguments) }
44
+
45
+ context 'when called without any arguments' do
46
+ let(:arguments) { [] }
47
+
48
+ before(:example) { allow(::Gem).to receive(:loaded_specs).and_return({}) }
49
+
50
+ it 'acquires the currently loaded gems from Rubygems' do
51
+ expect(::Gem).to receive(:loaded_specs)
52
+
53
+ method_call
54
+ end
55
+
56
+ it { is_expected.to be_an described_class }
57
+ end
58
+
59
+ context 'when called with gems' do
60
+ include_context 'two gems were provided at construction'
61
+
62
+ let(:arguments) { [gems: gems] }
63
+
64
+ it { is_expected.to be_an described_class }
65
+ end
66
+ end
67
+
68
+ describe '#find_gems_providing' do
69
+ subject(:method_call) { service.find_gems_providing(*arguments) }
70
+
71
+ context 'when called without any arguments' do
72
+ include_context 'only one gem was provided at construction'
73
+
74
+ let(:arguments) { [] }
75
+
76
+ specify { expect { method_call }.to raise_error ArgumentError, /wrong number of arguments/ }
77
+ end
78
+
79
+ context 'when called with a metadata key' do
80
+ let(:arguments) { [metadata_key] }
81
+ let(:metadata_key) { 'some key' }
82
+
83
+ context 'in case only one gem that does not contain metadata was provided at construction' do
84
+ include_context 'only one gem was provided at construction'
85
+
86
+ let(:metadata) { {} }
87
+
88
+ before(:example) do
89
+ allow(gem_specification).to receive(:metadata).and_return(metadata)
90
+ end
91
+
92
+ it 'requests the metadata from the gem specification' do
93
+ method_call
94
+
95
+ expect(gem_specification).to have_received(:metadata).with(no_args)
96
+ end
97
+
98
+ it { is_expected.to eq [] }
99
+ end
100
+
101
+ context 'in case only one gem that does contain non-matching metadata was provided at construction' do
102
+ include_context 'only one gem was provided at construction'
103
+
104
+ let(:metadata) do
105
+ { 'other key' => '' }
106
+ end
107
+
108
+ before(:example) do
109
+ allow(gem_specification).to receive(:metadata).and_return(metadata)
110
+ end
111
+
112
+ it 'requests the metadata from the gem specification' do
113
+ method_call
114
+
115
+ expect(gem_specification).to have_received(:metadata).with(no_args)
116
+ end
117
+
118
+ it { is_expected.to eq [] }
119
+ end
120
+
121
+ context 'in case only one gem that does contain matching metadata was provided at construction' do
122
+ include_context 'only one gem was provided at construction'
123
+
124
+ let(:metadata) do
125
+ { metadata_key => '' }
126
+ end
127
+
128
+ before(:example) do
129
+ allow(gem_specification).to receive(:metadata).and_return(metadata)
130
+ end
131
+
132
+ it 'requests the metadata from the gem specification' do
133
+ method_call
134
+
135
+ expect(gem_specification).to have_received(:metadata).with(no_args)
136
+ end
137
+
138
+ it { is_expected.to be_an Array }
139
+ it { is_expected.to have(1).item }
140
+
141
+ describe 'first item' do
142
+ subject(:item) { method_call[0] }
143
+
144
+ it 'is the gem specification' do
145
+ expect(item).to be gem_specification
146
+ end
147
+ end
148
+ end
149
+
150
+ context 'in case one gem containg metadata and one without were provided at construction' do
151
+ include_context 'two gems were provided at construction'
152
+
153
+ let(:first_metadata) { {} }
154
+ let(:second_metadata) do
155
+ { metadata_key => '' }
156
+ end
157
+
158
+ before(:example) do
159
+ allow(first_gem_specification).to receive(:metadata).and_return(first_metadata)
160
+ allow(second_gem_specification).to receive(:metadata).and_return(second_metadata)
161
+ end
162
+
163
+ it 'requests the metadata from the first gem specification' do
164
+ method_call
165
+
166
+ expect(first_gem_specification).to have_received(:metadata).with(no_args)
167
+ end
168
+
169
+ it 'requests the metadata from the second gem specification' do
170
+ method_call
171
+
172
+ expect(second_gem_specification).to have_received(:metadata).with(no_args)
173
+ end
174
+
175
+ it { is_expected.to be_an Array }
176
+ it { is_expected.to have(1).item }
177
+
178
+ describe 'first item' do
179
+ subject(:item) { method_call[0] }
180
+
181
+ it 'is the second gem specification' do
182
+ expect(item).to be second_gem_specification
183
+ end
184
+ end
185
+ end
186
+
187
+ context 'in case two gems containg matching metadata were provided at construction' do
188
+ include_context 'two gems were provided at construction'
189
+
190
+ let(:first_metadata) do
191
+ { metadata_key => '' }
192
+ end
193
+
194
+ let(:second_metadata) do
195
+ { metadata_key => '' }
196
+ end
197
+
198
+ before(:example) do
199
+ allow(first_gem_specification).to receive(:metadata).and_return(first_metadata)
200
+ allow(second_gem_specification).to receive(:metadata).and_return(second_metadata)
201
+ end
202
+
203
+ it 'requests the metadata from the first gem specification' do
204
+ method_call
205
+
206
+ expect(first_gem_specification).to have_received(:metadata).with(no_args)
207
+ end
208
+
209
+ it 'requests the metadata from the second gem specification' do
210
+ method_call
211
+
212
+ expect(second_gem_specification).to have_received(:metadata).with(no_args)
213
+ end
214
+
215
+ it { is_expected.to be_an Array }
216
+ it { is_expected.to have(2).item }
217
+
218
+ describe 'first item' do
219
+ subject(:item) { method_call[0] }
220
+
221
+ it 'is the first gem specification' do
222
+ expect(item).to be first_gem_specification
223
+ end
224
+ end
225
+
226
+ describe 'second item' do
227
+ subject(:item) { method_call[1] }
228
+
229
+ it 'is the second gem specification' do
230
+ expect(item).to be second_gem_specification
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
237
+
238
+ end