berkeley_library-tind 0.4.0 → 0.5.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +1 -1
  3. data/.idea/inspectionProfiles/Project_Default.xml +18 -0
  4. data/.idea/tind.iml +91 -91
  5. data/.ruby-version +1 -1
  6. data/CHANGES.md +33 -1
  7. data/README.md +15 -1
  8. data/berkeley_library-tind.gemspec +3 -2
  9. data/lib/berkeley_library/tind/api/api.rb +17 -11
  10. data/lib/berkeley_library/tind/api/collection.rb +1 -1
  11. data/lib/berkeley_library/tind/api/search.rb +2 -2
  12. data/lib/berkeley_library/tind/export/exporter.rb +1 -1
  13. data/lib/berkeley_library/tind/export/table.rb +1 -1
  14. data/lib/berkeley_library/tind/export/table_metrics.rb +1 -1
  15. data/lib/berkeley_library/tind/marc/xml_builder.rb +62 -0
  16. data/lib/berkeley_library/tind/marc/xml_reader.rb +32 -19
  17. data/lib/berkeley_library/tind/marc/xml_writer.rb +152 -0
  18. data/lib/berkeley_library/tind/module_info.rb +1 -1
  19. data/lib/berkeley_library/util/files.rb +39 -0
  20. data/lib/berkeley_library/util/ods/spreadsheet.rb +1 -1
  21. data/lib/berkeley_library/util/ods/xml/element_node.rb +1 -1
  22. data/spec/berkeley_library/tind/export/export_spec.rb +3 -1
  23. data/spec/berkeley_library/tind/export/table_spec.rb +2 -0
  24. data/spec/berkeley_library/tind/marc/xml_reader_spec.rb +42 -1
  25. data/spec/berkeley_library/tind/marc/xml_writer_spec.rb +156 -0
  26. data/spec/data/new-records.xml +46 -0
  27. metadata +36 -39
  28. data/Jenkinsfile +0 -18
  29. data/lib/berkeley_library/util/arrays.rb +0 -178
  30. data/lib/berkeley_library/util/logging.rb +0 -1
  31. data/lib/berkeley_library/util/paths.rb +0 -111
  32. data/lib/berkeley_library/util/stringios.rb +0 -30
  33. data/lib/berkeley_library/util/strings.rb +0 -42
  34. data/lib/berkeley_library/util/sys_exits.rb +0 -15
  35. data/lib/berkeley_library/util/times.rb +0 -22
  36. data/lib/berkeley_library/util/uris/appender.rb +0 -162
  37. data/lib/berkeley_library/util/uris/requester.rb +0 -62
  38. data/lib/berkeley_library/util/uris/validator.rb +0 -32
  39. data/lib/berkeley_library/util/uris.rb +0 -44
  40. data/spec/berkeley_library/util/arrays_spec.rb +0 -340
  41. data/spec/berkeley_library/util/paths_spec.rb +0 -90
  42. data/spec/berkeley_library/util/stringios_spec.rb +0 -34
  43. data/spec/berkeley_library/util/strings_spec.rb +0 -27
  44. data/spec/berkeley_library/util/times_spec.rb +0 -39
  45. data/spec/berkeley_library/util/uris_spec.rb +0 -118
@@ -1,162 +0,0 @@
1
- require 'berkeley_library/util/paths'
2
- require 'uri'
3
- require 'typesafe_enum'
4
-
5
- module BerkeleyLibrary
6
- module Util
7
- module URIs
8
-
9
- # Appends the specified paths to the path of the specified URI, removing any extraneous slashes,
10
- # and builds a new URI with that path and the same scheme, host, query, fragment, etc.
11
- # as the original.
12
- class Appender
13
- attr_reader :original_uri, :elements
14
-
15
- # Creates and invokes a new {Appender}.
16
- #
17
- # @param uri [URI, String] the original URI
18
- # @param elements [Array<String, Symbol>] the URI elements to join.
19
- # @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI
20
- def initialize(uri, *elements)
21
- raise ArgumentError, 'uri cannot be nil' unless (@original_uri = URIs.uri_or_nil(uri))
22
-
23
- @elements = elements.map(&:to_s)
24
- @elements.each_with_index do |element, elem_index|
25
- next start_query_at(elem_index) if element.include?('?')
26
- next start_fragment_at(elem_index) if element.include?('#')
27
-
28
- add_element(element)
29
- end
30
- end
31
-
32
- # Returns the new URI.
33
- #
34
- # @return [URI] a new URI appending the joined path elements.
35
- # @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI
36
- def to_uri
37
- original_uri.dup.tap do |new_uri|
38
- new_uri.path = Paths.join(original_uri.path, *path_elements)
39
- new_uri.query = query unless query_elements.empty?
40
- new_uri.fragment = fragment unless fragment_elements.empty?
41
- end
42
- end
43
-
44
- private
45
-
46
- def state
47
- @state ||= :path
48
- end
49
-
50
- def in_query?
51
- state == :query
52
- end
53
-
54
- def in_fragment?
55
- state == :fragment
56
- end
57
-
58
- def query
59
- query_elements.join
60
- end
61
-
62
- def fragment
63
- fragment_elements.join
64
- end
65
-
66
- def path_elements
67
- @path_elements ||= []
68
- end
69
-
70
- def query_elements
71
- @query_elements ||= [].tap { |e| e << original_uri.query if original_uri.query }
72
- end
73
-
74
- def fragment_elements
75
- @fragment_elements ||= [].tap { |e| e << original_uri.fragment if original_uri.fragment }
76
- end
77
-
78
- def start_query_at(elem_index)
79
- raise URI::InvalidComponentError, err_query_after_fragment(elem_index) if in_fragment?
80
- raise URI::InvalidComponentError, err_too_many_queries(elem_index) unless query_elements.empty?
81
-
82
- handle_query_start(elem_index)
83
- @state = :query
84
- end
85
-
86
- def start_fragment_at(elem_index)
87
- raise URI::InvalidComponentError, err_too_many_fragments(elem_index) unless fragment_elements.empty?
88
- raise URI::InvalidComponentError, err_query_after_fragment(elem_index) if query_after_fragment?(elem_index)
89
-
90
- handle_fragment_start(elem_index)
91
- @state = :fragment
92
- end
93
-
94
- def query_after_fragment?(elem_index)
95
- e = elements[elem_index]
96
- e.index('?', e.index('#'))
97
- end
98
-
99
- def add_element(e)
100
- return fragment_elements << e if in_fragment?
101
- return query_elements << e if in_query? || (e.include?('&') && !query_elements.empty?)
102
-
103
- path_elements << e
104
- end
105
-
106
- def handle_query_start(elem_index)
107
- element = elements[elem_index]
108
-
109
- # if there's anything before the '?', we treat that excess as a path element
110
- excess, q_start = split_around(element, element.index('?'))
111
- q_start = push_fragment_start(elem_index, q_start)
112
-
113
- query_elements << q_start
114
- path_elements << excess
115
- end
116
-
117
- # if the fragment starts in the middle of this element, we keep the part before
118
- # the fragment delimiter '#', and push the rest (w/'#') back onto the next element
119
- # to be parsed in the next iteration
120
- def push_fragment_start(elem_index, q_start)
121
- return q_start unless (f_index = q_start.index('#'))
122
-
123
- next_index = elem_index + 1
124
- q_start, q_next = split_around(q_start, f_index) # NOTE: this doesn't return the '#'
125
- elements[next_index] = "##{q_next}#{elements[next_index]}" # so we prepend one here
126
- q_start
127
- end
128
-
129
- def handle_fragment_start(elem_index)
130
- element = elements[elem_index]
131
-
132
- # if there's anything before the '#', we treat that excess as a path element,
133
- # or as a query element if there's a query
134
- excess, f_start = split_around(element, element.index('#'))
135
-
136
- fragment_elements << f_start
137
- if in_query?
138
- query_elements << excess
139
- else
140
- path_elements << excess
141
- end
142
- end
143
-
144
- def split_around(s, i)
145
- [s[0...i], s[(i + 1)..]]
146
- end
147
-
148
- def err_too_many_queries(elem_index)
149
- "#{elements[elem_index].inspect}: URI already has a query string: #{query.inspect}"
150
- end
151
-
152
- def err_query_after_fragment(elem_index)
153
- "#{elements[elem_index].inspect}: Query delimiter '?' cannot follow fragment delimeter '#'"
154
- end
155
-
156
- def err_too_many_fragments(elem_index)
157
- "#{elements[elem_index].inspect}: URI already has a fragment: #{fragment.inspect}"
158
- end
159
- end
160
- end
161
- end
162
- end
@@ -1,62 +0,0 @@
1
- require 'rest-client'
2
- require 'berkeley_library/util/uris/appender'
3
- require 'berkeley_library/util/uris/validator'
4
- require 'berkeley_library/logging'
5
-
6
- module BerkeleyLibrary
7
- module Util
8
- module URIs
9
- module Requester
10
- class << self
11
- include BerkeleyLibrary::Logging
12
-
13
- # Performs a GET request.
14
- #
15
- # @param uri [URI, String] the URI to GET
16
- # @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
17
- # @param headers [Hash] the request headers.
18
- # @return [String] the body as a string.
19
- # @raise [RestClient::Exception] in the event of an error.
20
- def get(uri, params = {}, headers = {})
21
- url_str = url_str_with_params(uri, params)
22
- resp = get_or_raise(url_str, headers)
23
- resp.body
24
- end
25
-
26
- private
27
-
28
- def url_str_with_params(uri, params)
29
- raise ArgumentError, 'uri cannot be nil' unless (url_str = Validator.url_str_or_nil(uri))
30
-
31
- elements = [].tap do |ee|
32
- ee << url_str
33
- ee << '?' unless url_str.include?('?')
34
- ee << URI.encode_www_form(params)
35
- end
36
-
37
- uri = Appender.new(*elements).to_uri
38
- uri.to_s
39
- end
40
-
41
- def get_or_raise(url_str, headers)
42
- resp = RestClient.get(url_str, headers)
43
- begin
44
- return resp if (status = resp.code) == 200
45
-
46
- raise(exception_for(resp, status))
47
- ensure
48
- logger.info("GET #{url_str} returned #{status}")
49
- end
50
- end
51
-
52
- def exception_for(resp, status)
53
- RestClient::RequestFailed.new(resp, status).tap do |ex|
54
- status_message = RestClient::STATUSES[status] || '(Unknown)'
55
- ex.message = "#{status} #{status_message}"
56
- end
57
- end
58
- end
59
- end
60
- end
61
- end
62
- end
@@ -1,32 +0,0 @@
1
- require 'uri'
2
-
3
- module BerkeleyLibrary
4
- module Util
5
- module URIs
6
- module Validator
7
- class << self
8
-
9
- # Returns the specified URL as a URI.
10
- # @param url [String, URI] the URL.
11
- # @return [URI] the URI.
12
- # @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
13
- def uri_or_nil(url)
14
- return unless url
15
-
16
- # noinspection RubyYardReturnMatch
17
- url.is_a?(URI) ? url : URI.parse(url.to_s)
18
- end
19
-
20
- # Returns the specified URL as a string.
21
- # @param url [String, URI] the URL.
22
- # @return [String] the URL.
23
- # @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
24
- def url_str_or_nil(url)
25
- uri = Validator.uri_or_nil(url)
26
- uri.to_s if uri
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,44 +0,0 @@
1
- require 'berkeley_library/util/uris/appender'
2
- require 'berkeley_library/util/uris/requester'
3
- require 'berkeley_library/util/uris/validator'
4
-
5
- module BerkeleyLibrary
6
- module Util
7
- module URIs
8
- class << self
9
- include URIs
10
- end
11
-
12
- # Appends the specified paths to the path of the specified URI, removing any extraneous slashes
13
- # and merging additional query parameters, and returns a new URI with that path and the same scheme,
14
- # host, query, fragment, etc. as the original.
15
- #
16
- # @param uri [URI, String] the original URI
17
- # @param elements [Array<String, Symbol>] the URI elements to join.
18
- # @return [URI] a new URI appending the joined path elements.
19
- # @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI
20
- def append(uri, *elements)
21
- Appender.new(uri, *elements).to_uri
22
- end
23
-
24
- # Performs a GET request.
25
- #
26
- # @param uri [URI, String] the URI to GET
27
- # @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
28
- # @param headers [Hash] the request headers.
29
- # @return [String] the body as a string.
30
- # @raise [RestClient::Exception] in the event of an error.
31
- def get(uri, params = {}, headers = {})
32
- Requester.get(uri, params, headers)
33
- end
34
-
35
- # Returns the specified URL as a URI.
36
- # @param url [String, URI] the URL.
37
- # @return [URI] the URI.
38
- # @raise [URI::InvalidURIError] if `url` cannot be parsed as a URI.
39
- def uri_or_nil(url)
40
- Validator.uri_or_nil(url)
41
- end
42
- end
43
- end
44
- end
@@ -1,340 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'berkeley_library/util/arrays'
4
-
5
- module BerkeleyLibrary::Util
6
- describe Arrays do
7
- describe :ordered_superset do
8
- let(:sup) { %w[a b c d e] }
9
-
10
- it 'returns true for an identical subset' do
11
- expect(Arrays.ordered_superset?(superset: sup, subset: sup.dup)).to eq(true)
12
- end
13
-
14
- it 'returns true for an empty subset' do
15
- expect(Arrays.ordered_superset?(superset: sup, subset: [])).to eq(true)
16
- end
17
-
18
- it 'returns true for an exact sublist' do
19
- subs = [
20
- %w[a b c],
21
- %w[b c d],
22
- %w[c d e]
23
- ]
24
- subs.each do |sub|
25
- expect(Arrays.ordered_superset?(superset: sup, subset: sub)).to eq(true)
26
- end
27
- end
28
-
29
- it 'returns true when the superset interpolates extra elements' do
30
- subs = [
31
- %w[a c e],
32
- %w[b d],
33
- %w[a b d e]
34
- ]
35
- subs.each do |sub|
36
- expect(Arrays.ordered_superset?(superset: sup, subset: sub)).to eq(true)
37
- end
38
- end
39
-
40
- it 'returns false for a too-large subset' do
41
- sub = %w[a b c d e f g]
42
- expect(Arrays.ordered_superset?(superset: sup, subset: sub)).to eq(false)
43
- end
44
-
45
- it 'returns false when extra elements are present' do
46
- subs = [
47
- %w[a b c x],
48
- %w[x b c d],
49
- %w[c d x e]
50
- ]
51
- subs.each do |sub|
52
- expect(Arrays.ordered_superset?(superset: sup, subset: sub)).to eq(false)
53
- end
54
- end
55
- end
56
-
57
- describe :count_while do
58
- it 'returns the count of matching elements' do
59
- a = [1, 3, 5, 2, 4, 6, 7, 11, 13]
60
- expect(Arrays.count_while(values: a, &:odd?)).to eq(3)
61
- end
62
-
63
- it 'returns 0 if the first element does not match' do
64
- a = [2, 4, 6, 7, 11, 13]
65
- expect(Arrays.count_while(values: a, &:odd?)).to eq(0)
66
- end
67
-
68
- it 'returns an enumerator if not passed a block' do
69
- a = [1, 3, 5, 2, 4, 6, 7, 11, 13]
70
- e = Arrays.count_while(values: a)
71
- expect(e.each(&:odd?)).to eq(3)
72
- end
73
-
74
- it 'works on non-arrays' do
75
- a = [1, 3, 5, 2, 4, 6, 7, 11, 13]
76
- e = Enumerator.new { |y| a.each { |x| y << x } }
77
- expect(Arrays.count_while(values: e, &:odd?)).to eq(3)
78
- end
79
- end
80
-
81
- describe :find_indices do
82
- let(:target) { %w[a b c d e] }
83
-
84
- it 'returns identity indices for an identical subset' do
85
- expect(Arrays.find_indices(for_array: target.dup, in_array: target)).to eq([0, 1, 2, 3, 4])
86
- end
87
-
88
- it 'returns an empty array for an empty subset' do
89
- expect(Arrays.find_indices(for_array: [], in_array: target)).to eq([])
90
- end
91
-
92
- it 'returns the expected subindices for an exact sublist' do
93
- sources = {
94
- %w[a b c] => [0, 1, 2],
95
- %w[b c d] => [1, 2, 3],
96
- %w[c d e] => [2, 3, 4]
97
- }
98
- sources.each do |source, expected|
99
- expect(Arrays.find_indices(for_array: source, in_array: target)).to eq(expected)
100
- end
101
- end
102
-
103
- it 'returns nil for a too-large subset' do
104
- source = %w[a b c d e f g]
105
- expect(Arrays.find_indices(for_array: source, in_array: target)).to be_nil
106
- end
107
-
108
- it 'returns nil when extra elements are present' do
109
- sources = [
110
- %w[a b c x],
111
- %w[x b c d],
112
- %w[c d x e]
113
- ]
114
- sources.each do |source|
115
- expect(Arrays.find_indices(for_array: source, in_array: target)).to be_nil
116
- end
117
- end
118
-
119
- it 'takes a comparison block' do
120
- sub = %i[a c e]
121
- expect(Arrays.find_indices(for_array: sub, in_array: target) { |source, target| target == source.to_s }).to eq([0, 2, 4])
122
- end
123
- end
124
-
125
- describe :find_index do
126
- let(:arr) { [0, 2, 4, 6, 4] }
127
-
128
- it 'finds an index based on a value' do
129
- expect(Arrays.find_index(4, in_array: arr)).to eq(2)
130
- expect(Arrays.find_index(4, in_array: arr, start_index: 3)).to eq(4)
131
- end
132
-
133
- it 'finds an index based on a block' do
134
- expect(Arrays.find_index(in_array: arr) { |x| x > 3 }).to eq(2)
135
- expect(Arrays.find_index(in_array: arr, start_index: 3) { |x| x < 5 }).to eq(4)
136
- end
137
-
138
- it 'returns nil if no equal value found' do
139
- expect(Arrays.find_index(7, in_array: arr)).to be_nil
140
- expect(Arrays.find_index(2, in_array: arr, start_index: 2)).to be_nil
141
- end
142
-
143
- it 'returns nil if no matching value found' do
144
- expect(Arrays.find_index(in_array: arr, &:odd?)).to be_nil
145
- expect(Arrays.find_index(in_array: arr, start_index: 2) { |x| x < 4 }).to be_nil
146
- end
147
-
148
- # rubocop:disable Lint/Void
149
- it 'returns an enumerator if given no arguments' do
150
- e = Arrays.find_index(in_array: arr)
151
- expect(e.each { |x| x > 3 }).to eq(2)
152
-
153
- e = Arrays.find_index(in_array: arr, start_index: 3)
154
- expect(e.each { |x| x < 5 }).to eq(4)
155
- end
156
- # rubocop:enable Lint/Void
157
- end
158
-
159
- describe :merge do
160
- it 'merges two arrays' do
161
- a1 = [1, 2, 3]
162
- a2 = [2, 3, 4]
163
- expect(Arrays.merge(a1, a2)).to eq([1, 2, 3, 4])
164
- expect(Arrays.merge(a2, a1)).to eq([1, 2, 3, 4])
165
- end
166
-
167
- it 'merges disjoint arrays' do
168
- a1 = [1, 3, 5]
169
- a2 = [2, 4, 6]
170
- expect(Arrays.merge(a1, a2)).to eq([1, 3, 5, 2, 4, 6])
171
- end
172
-
173
- it 'preserves duplicates' do
174
- a1 = [1, 2, 2, 3, 4, 5]
175
- a2 = [2, 4, 4, 5, 5, 6]
176
-
177
- merged = Arrays.merge(a1, a2)
178
- [a1, a2].each do |a|
179
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
180
- end
181
-
182
- expected = [1, 2, 2, 3, 4, 4, 5, 5, 6]
183
- expect(merged.size).to eq(expected.size)
184
- expect(merged).to eq(expected)
185
- end
186
-
187
- it 'merges gappy arrays' do
188
- a1 = [1, 4, 5, 7, 9]
189
- a2 = [2, 3, 4, 7, 8, 9]
190
-
191
- merged = Arrays.merge(a1, a2)
192
- [a1, a2].each do |a|
193
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
194
- end
195
-
196
- expected = [1, 2, 3, 4, 5, 7, 8, 9]
197
- expect(merged.size).to eq(expected.size)
198
- expect(merged).to eq(expected)
199
- end
200
-
201
- it 'preserves order when merging arrays with duplicates' do
202
- a1 = [1, 3, 2, 2, 4]
203
- a2 = [1, 2, 3, 2, 4]
204
-
205
- merged = Arrays.merge(a1, a2)
206
- [a1, a2].each do |a|
207
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
208
- end
209
-
210
- expected = [1, 2, 3, 2, 2, 4]
211
- expect(merged.size).to eq(expected.size)
212
- expect(merged).to eq(expected)
213
- end
214
-
215
- it 'preserves nil' do
216
- a1 = [1, 3, nil, nil, 4]
217
- a2 = [1, nil, 3, nil, 4]
218
-
219
- merged = Arrays.merge(a1, a2)
220
- [a1, a2].each do |a|
221
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
222
- end
223
-
224
- expected = [1, nil, 3, nil, nil, 4]
225
- expect(merged.size).to eq(expected.size)
226
- expect(merged).to eq(expected)
227
- end
228
-
229
- it 'works with non-comparable types' do
230
- a1 = [1, 3, 'two', 'two', 4]
231
- a2 = [1, 'two', 3, 'two', 4]
232
-
233
- merged = Arrays.merge(a1, a2)
234
- [a1, a2].each do |a|
235
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
236
- end
237
-
238
- expected = [1, 'two', 3, 'two', 'two', 4]
239
- expect(merged.size).to eq(expected.size)
240
- expect(merged).to eq(expected)
241
- end
242
-
243
- it 'returns the larger array if the smaller is already a subarray' do
244
- a1 = [2, 3, 4]
245
- a2 = [1, 2, 3, 4, 5]
246
-
247
- merged = Arrays.merge(a1, a2)
248
- [a1, a2].each do |a|
249
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
250
- end
251
-
252
- expected = a2
253
- expect(merged.size).to eq(expected.size)
254
- expect(merged).to eq(expected)
255
-
256
- expect(Arrays.merge(a2, a1)).to eq(expected)
257
- end
258
-
259
- it 'sorts where sorting preserves order' do
260
- a1 = [1, 2, 3, 4, 5]
261
- a2 = [2, 3, 6, 9]
262
-
263
- merged = Arrays.merge(a1, a2)
264
- [a1, a2].each do |a|
265
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
266
- end
267
-
268
- expected = [1, 2, 3, 4, 5, 6, 9]
269
- expect(merged.size).to eq(expected.size)
270
- expect(merged).to eq(expected)
271
-
272
- expect(Arrays.merge(a2, a1)).to eq(expected)
273
- end
274
-
275
- it "doesn't muck up partial matches" do
276
- a1 = [1, 2, 3, 4, 5]
277
- a2 = [6, 9, 2, 3]
278
-
279
- merged = Arrays.merge(a1, a2)
280
- [a1, a2].each do |a|
281
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
282
- end
283
-
284
- expected = [1, 6, 9, 2, 3, 4, 5]
285
- expect(merged.size).to eq(expected.size)
286
- expect(merged).to eq(expected)
287
-
288
- expect(Arrays.merge(a2, a1)).to eq(expected)
289
- end
290
-
291
- it "doesn't much up disjoints" do
292
- a1 = [1, 2, 3, 4, 5]
293
- a2 = [6, 9]
294
-
295
- merged = Arrays.merge(a1, a2)
296
- [a1, a2].each do |a|
297
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
298
- end
299
-
300
- expected = [1, 2, 3, 4, 5, 6, 9]
301
- expect(merged.size).to eq(expected.size)
302
- expect(merged).to eq(expected)
303
-
304
- expect(Arrays.merge(a2, a1)).to eq(expected)
305
- end
306
-
307
- it 'works on a selection of random values' do
308
- next_int = ->(n) { (n * rand).to_i }
309
- rand_array = -> { (0...next_int.call(10)).map { next_int.call(10) } }
310
- aggregate_failures 'random values' do
311
- 100.times do
312
- a1 = rand_array.call
313
- a2 = rand_array.call
314
-
315
- merged = Arrays.merge(a1, a2)
316
- [a1, a2].each do |a|
317
- expect(Arrays.ordered_superset?(superset: merged, subset: a)).to eq(true), "merge(#{[a1.join, a2.join].inspect}): #{a.join} not found in #{merged.join}"
318
- end
319
- end
320
- end
321
- end
322
-
323
- end
324
-
325
- describe :invert do
326
- it 'inverts an array of ints' do
327
- expect(Arrays.invert([0, 2, 3])).to eq([0, nil, 1, 2])
328
- end
329
-
330
- it 'fails if values are not ints' do
331
- # noinspection RubyYardParamTypeMatch
332
- expect { Arrays.invert(%i[a b c]) }.to raise_error(TypeError)
333
- end
334
-
335
- it 'fails if given duplicate values' do
336
- expect { Arrays.invert([1, 2, 3, 2]) }.to raise_error(ArgumentError)
337
- end
338
- end
339
- end
340
- end