berkeley_library-tind 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +18 -0
  3. data/.gitignore +388 -0
  4. data/.idea/inspectionProfiles/Project_Default.xml +20 -0
  5. data/.idea/misc.xml +4 -0
  6. data/.idea/modules.xml +8 -0
  7. data/.idea/tind.iml +138 -0
  8. data/.idea/vcs.xml +6 -0
  9. data/.rubocop.yml +334 -0
  10. data/.ruby-version +1 -0
  11. data/.simplecov +8 -0
  12. data/.yardopts +1 -0
  13. data/CHANGES.md +58 -0
  14. data/Dockerfile +57 -0
  15. data/Gemfile +3 -0
  16. data/Jenkinsfile +18 -0
  17. data/LICENSE.md +21 -0
  18. data/README.md +73 -0
  19. data/Rakefile +20 -0
  20. data/berkeley_library-tind.gemspec +50 -0
  21. data/bin/tind-export +14 -0
  22. data/docker-compose.yml +15 -0
  23. data/lib/berkeley_library/tind.rb +3 -0
  24. data/lib/berkeley_library/tind/api.rb +1 -0
  25. data/lib/berkeley_library/tind/api/api.rb +132 -0
  26. data/lib/berkeley_library/tind/api/api_exception.rb +131 -0
  27. data/lib/berkeley_library/tind/api/collection.rb +82 -0
  28. data/lib/berkeley_library/tind/api/date_range.rb +67 -0
  29. data/lib/berkeley_library/tind/api/format.rb +32 -0
  30. data/lib/berkeley_library/tind/api/search.rb +100 -0
  31. data/lib/berkeley_library/tind/config.rb +103 -0
  32. data/lib/berkeley_library/tind/export.rb +1 -0
  33. data/lib/berkeley_library/tind/export/column.rb +54 -0
  34. data/lib/berkeley_library/tind/export/column_group.rb +144 -0
  35. data/lib/berkeley_library/tind/export/column_group_list.rb +131 -0
  36. data/lib/berkeley_library/tind/export/column_width_calculator.rb +76 -0
  37. data/lib/berkeley_library/tind/export/config.rb +154 -0
  38. data/lib/berkeley_library/tind/export/csv_exporter.rb +29 -0
  39. data/lib/berkeley_library/tind/export/export.rb +47 -0
  40. data/lib/berkeley_library/tind/export/export_command.rb +168 -0
  41. data/lib/berkeley_library/tind/export/export_exception.rb +8 -0
  42. data/lib/berkeley_library/tind/export/export_format.rb +67 -0
  43. data/lib/berkeley_library/tind/export/exporter.rb +105 -0
  44. data/lib/berkeley_library/tind/export/filter.rb +52 -0
  45. data/lib/berkeley_library/tind/export/no_results_error.rb +7 -0
  46. data/lib/berkeley_library/tind/export/ods_exporter.rb +138 -0
  47. data/lib/berkeley_library/tind/export/row.rb +24 -0
  48. data/lib/berkeley_library/tind/export/row_metrics.rb +18 -0
  49. data/lib/berkeley_library/tind/export/table.rb +175 -0
  50. data/lib/berkeley_library/tind/export/table_metrics.rb +116 -0
  51. data/lib/berkeley_library/tind/marc.rb +1 -0
  52. data/lib/berkeley_library/tind/marc/xml_reader.rb +144 -0
  53. data/lib/berkeley_library/tind/module_info.rb +14 -0
  54. data/lib/berkeley_library/util/arrays.rb +178 -0
  55. data/lib/berkeley_library/util/logging.rb +1 -0
  56. data/lib/berkeley_library/util/ods/spreadsheet.rb +170 -0
  57. data/lib/berkeley_library/util/ods/xml/content_doc.rb +26 -0
  58. data/lib/berkeley_library/util/ods/xml/document_node.rb +57 -0
  59. data/lib/berkeley_library/util/ods/xml/element_node.rb +106 -0
  60. data/lib/berkeley_library/util/ods/xml/loext/table_protection.rb +26 -0
  61. data/lib/berkeley_library/util/ods/xml/manifest/file_entry.rb +42 -0
  62. data/lib/berkeley_library/util/ods/xml/manifest/manifest.rb +73 -0
  63. data/lib/berkeley_library/util/ods/xml/manifest_doc.rb +26 -0
  64. data/lib/berkeley_library/util/ods/xml/namespace.rb +46 -0
  65. data/lib/berkeley_library/util/ods/xml/office/automatic_styles.rb +181 -0
  66. data/lib/berkeley_library/util/ods/xml/office/body.rb +17 -0
  67. data/lib/berkeley_library/util/ods/xml/office/document_content.rb +98 -0
  68. data/lib/berkeley_library/util/ods/xml/office/document_styles.rb +39 -0
  69. data/lib/berkeley_library/util/ods/xml/office/font_face_decls.rb +30 -0
  70. data/lib/berkeley_library/util/ods/xml/office/scripts.rb +17 -0
  71. data/lib/berkeley_library/util/ods/xml/office/spreadsheet.rb +37 -0
  72. data/lib/berkeley_library/util/ods/xml/office/styles.rb +39 -0
  73. data/lib/berkeley_library/util/ods/xml/style/cell_style.rb +58 -0
  74. data/lib/berkeley_library/util/ods/xml/style/column_style.rb +36 -0
  75. data/lib/berkeley_library/util/ods/xml/style/default_style.rb +31 -0
  76. data/lib/berkeley_library/util/ods/xml/style/family.rb +85 -0
  77. data/lib/berkeley_library/util/ods/xml/style/font_face.rb +46 -0
  78. data/lib/berkeley_library/util/ods/xml/style/paragraph_properties.rb +30 -0
  79. data/lib/berkeley_library/util/ods/xml/style/row_style.rb +37 -0
  80. data/lib/berkeley_library/util/ods/xml/style/style.rb +44 -0
  81. data/lib/berkeley_library/util/ods/xml/style/table_cell_properties.rb +40 -0
  82. data/lib/berkeley_library/util/ods/xml/style/table_column_properties.rb +30 -0
  83. data/lib/berkeley_library/util/ods/xml/style/table_properties.rb +25 -0
  84. data/lib/berkeley_library/util/ods/xml/style/table_row_properties.rb +28 -0
  85. data/lib/berkeley_library/util/ods/xml/style/table_style.rb +27 -0
  86. data/lib/berkeley_library/util/ods/xml/style/text_properties.rb +52 -0
  87. data/lib/berkeley_library/util/ods/xml/styles_doc.rb +26 -0
  88. data/lib/berkeley_library/util/ods/xml/table/named_expressions.rb +17 -0
  89. data/lib/berkeley_library/util/ods/xml/table/repeatable.rb +38 -0
  90. data/lib/berkeley_library/util/ods/xml/table/table.rb +193 -0
  91. data/lib/berkeley_library/util/ods/xml/table/table_cell.rb +46 -0
  92. data/lib/berkeley_library/util/ods/xml/table/table_column.rb +43 -0
  93. data/lib/berkeley_library/util/ods/xml/table/table_row.rb +136 -0
  94. data/lib/berkeley_library/util/ods/xml/text/p.rb +118 -0
  95. data/lib/berkeley_library/util/paths.rb +111 -0
  96. data/lib/berkeley_library/util/stringios.rb +30 -0
  97. data/lib/berkeley_library/util/strings.rb +42 -0
  98. data/lib/berkeley_library/util/sys_exits.rb +15 -0
  99. data/lib/berkeley_library/util/times.rb +22 -0
  100. data/lib/berkeley_library/util/uris.rb +44 -0
  101. data/lib/berkeley_library/util/uris/appender.rb +162 -0
  102. data/lib/berkeley_library/util/uris/requester.rb +62 -0
  103. data/lib/berkeley_library/util/uris/validator.rb +32 -0
  104. data/rakelib/bundle.rake +8 -0
  105. data/rakelib/coverage.rake +11 -0
  106. data/rakelib/gem.rake +54 -0
  107. data/rakelib/rubocop.rake +18 -0
  108. data/rakelib/spec.rake +2 -0
  109. data/spec/.rubocop.yml +40 -0
  110. data/spec/berkeley_library/tind/api/api_exception_spec.rb +91 -0
  111. data/spec/berkeley_library/tind/api/api_spec.rb +143 -0
  112. data/spec/berkeley_library/tind/api/collection_spec.rb +74 -0
  113. data/spec/berkeley_library/tind/api/date_range_spec.rb +110 -0
  114. data/spec/berkeley_library/tind/api/format_spec.rb +54 -0
  115. data/spec/berkeley_library/tind/api/search_spec.rb +364 -0
  116. data/spec/berkeley_library/tind/config_spec.rb +86 -0
  117. data/spec/berkeley_library/tind/export/column_group_spec.rb +29 -0
  118. data/spec/berkeley_library/tind/export/column_spec.rb +43 -0
  119. data/spec/berkeley_library/tind/export/config_spec.rb +206 -0
  120. data/spec/berkeley_library/tind/export/export_command_spec.rb +169 -0
  121. data/spec/berkeley_library/tind/export/export_format_spec.rb +59 -0
  122. data/spec/berkeley_library/tind/export/export_matcher.rb +112 -0
  123. data/spec/berkeley_library/tind/export/export_spec.rb +150 -0
  124. data/spec/berkeley_library/tind/export/exporter_spec.rb +125 -0
  125. data/spec/berkeley_library/tind/export/row_spec.rb +118 -0
  126. data/spec/berkeley_library/tind/export/table_spec.rb +322 -0
  127. data/spec/berkeley_library/tind/marc/xml_reader_spec.rb +93 -0
  128. data/spec/berkeley_library/util/arrays_spec.rb +340 -0
  129. data/spec/berkeley_library/util/ods/spreadsheet_spec.rb +124 -0
  130. data/spec/berkeley_library/util/ods/xml/content_doc_spec.rb +121 -0
  131. data/spec/berkeley_library/util/ods/xml/manifest/file_entry_spec.rb +27 -0
  132. data/spec/berkeley_library/util/ods/xml/manifest/manifest_spec.rb +33 -0
  133. data/spec/berkeley_library/util/ods/xml/office/document_content_spec.rb +60 -0
  134. data/spec/berkeley_library/util/ods/xml/style/automatic_styles_spec.rb +37 -0
  135. data/spec/berkeley_library/util/ods/xml/style/family_spec.rb +57 -0
  136. data/spec/berkeley_library/util/ods/xml/table/table_row_spec.rb +179 -0
  137. data/spec/berkeley_library/util/ods/xml/table/table_spec.rb +218 -0
  138. data/spec/berkeley_library/util/paths_spec.rb +90 -0
  139. data/spec/berkeley_library/util/stringios_spec.rb +34 -0
  140. data/spec/berkeley_library/util/strings_spec.rb +27 -0
  141. data/spec/berkeley_library/util/times_spec.rb +39 -0
  142. data/spec/berkeley_library/util/uris_spec.rb +118 -0
  143. data/spec/data/collection-names.txt +438 -0
  144. data/spec/data/collections.json +4827 -0
  145. data/spec/data/disjoint-records.xml +187 -0
  146. data/spec/data/record-184453.xml +58 -0
  147. data/spec/data/record-184458.xml +63 -0
  148. data/spec/data/record-187888.xml +78 -0
  149. data/spec/data/records-api-search-cjk-p1.xml +6381 -0
  150. data/spec/data/records-api-search-cjk-p2.xml +5 -0
  151. data/spec/data/records-api-search-p1.xml +4506 -0
  152. data/spec/data/records-api-search-p2.xml +4509 -0
  153. data/spec/data/records-api-search-p3.xml +4506 -0
  154. data/spec/data/records-api-search-p4.xml +4509 -0
  155. data/spec/data/records-api-search-p5.xml +4506 -0
  156. data/spec/data/records-api-search-p6.xml +2436 -0
  157. data/spec/data/records-api-search-p7.xml +5 -0
  158. data/spec/data/records-api-search.xml +234 -0
  159. data/spec/data/records-manual-search.xml +547 -0
  160. data/spec/spec_helper.rb +30 -0
  161. data/test/profile/table_from_records_profile.rb +46 -0
  162. metadata +585 -0
@@ -0,0 +1,340 @@
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
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+ require 'roo'
3
+
4
+ module BerkeleyLibrary
5
+ module Util
6
+ module ODS
7
+ describe Spreadsheet do
8
+ let(:basename) { File.basename(__FILE__, '.rb') }
9
+ let(:spreadsheet) { Spreadsheet.new }
10
+
11
+ let(:num_cols) { 6 }
12
+ let(:num_rows) { 12 }
13
+
14
+ before(:each) do
15
+ table = spreadsheet.add_table('Table 1')
16
+ num_cols.times { |c| table.add_column("Column #{c}") }
17
+ num_rows.times do |r|
18
+ row = table.add_row
19
+ num_cols.times { |c| row.set_value_at(c, (r * c).to_s) }
20
+ end
21
+ end
22
+
23
+ describe :write_to do
24
+ def check_cell_values(ss)
25
+ aggregate_failures 'cells' do
26
+ num_cols.times do |col|
27
+ # NOTE: spreadsheet rows are 1-indexed, but row 1 is header
28
+ cell_index = [1, 1 + col]
29
+ actual = ss.cell(*cell_index)
30
+ expected = "Column #{col}"
31
+ expect(actual).to eq(expected), "Wrong value at #{cell_index}; expected #{expected.inspect}, was #{actual.inspect}"
32
+
33
+ num_rows.times do |row|
34
+ cell_index = [2 + row, 1 + col]
35
+ actual = ss.cell(*cell_index)
36
+ expected = (row * col).to_s
37
+ expect(actual).to eq(expected), "Wrong value at #{cell_index}; expected #{expected.inspect}, was #{actual.inspect}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ it 'writes to a file' do
44
+ Dir.mktmpdir(basename) do |dir|
45
+ output_path = File.join(dir, "#{basename}.ods")
46
+ spreadsheet.write_to(output_path)
47
+
48
+ ss = Roo::Spreadsheet.open(output_path, file_warning: :warning)
49
+ check_cell_values(ss)
50
+ end
51
+ end
52
+
53
+ it 'writes to a file handle' do
54
+ Dir.mktmpdir(basename) do |dir|
55
+ output_path = File.join(dir, "#{basename}.ods")
56
+ File.open(output_path, 'wb') { |f| spreadsheet.write_to(f) }
57
+
58
+ ss = Roo::Spreadsheet.open(output_path, file_warning: :warning)
59
+ check_cell_values(ss)
60
+ end
61
+ end
62
+
63
+ it 'writes to a StringIO' do
64
+ Dir.mktmpdir(basename) do |dir|
65
+ output_path = File.join(dir, "#{basename}.ods")
66
+ result = StringIO.new.tap { |out| spreadsheet.write_to(out) }.string
67
+ File.open(output_path, 'wb') { |f| f.write(result) }
68
+
69
+ ss = Roo::Spreadsheet.open(output_path, file_warning: :warning)
70
+ check_cell_values(ss)
71
+ end
72
+ end
73
+
74
+ it 'returns a string' do
75
+ Dir.mktmpdir(basename) do |dir|
76
+ output_path = File.join(dir, "#{basename}.ods")
77
+ result = spreadsheet.write_to
78
+ File.open(output_path, 'wb') { |f| f.write(result) }
79
+
80
+ ss = Roo::Spreadsheet.open(output_path, file_warning: :warning)
81
+ check_cell_values(ss)
82
+ end
83
+ end
84
+
85
+ it 'writes a spreadsheet as exploded XML' do
86
+ Dir.mktmpdir(basename) do |dir|
87
+ expected_paths_relative = %w[META-INF/manifest.xml styles.xml content.xml]
88
+ expected_paths_absolute = expected_paths_relative.map do |path_relative|
89
+ joined_path = File.join(dir, path_relative)
90
+ File.absolute_path(joined_path)
91
+ end
92
+
93
+ files_written = spreadsheet.write_to(dir)
94
+ expect(files_written).to match_array(expected_paths_absolute)
95
+
96
+ expected_paths_absolute.each do |path_absolute|
97
+ expect(File.file?(path_absolute)).to eq(true)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ describe :write_exploded do
104
+ it 'writes a spreadsheet as exploded XML' do
105
+ Dir.mktmpdir(basename) do |dir|
106
+ expected_paths_relative = %w[META-INF/manifest.xml styles.xml content.xml]
107
+ expected_paths_absolute = expected_paths_relative.map do |path_relative|
108
+ joined_path = File.join(dir, path_relative)
109
+ File.absolute_path(joined_path)
110
+ end
111
+
112
+ files_written = spreadsheet.write_exploded_to(dir)
113
+ expect(files_written).to match_array(expected_paths_absolute)
114
+
115
+ expected_paths_absolute.each do |path_absolute|
116
+ expect(File.file?(path_absolute)).to eq(true)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end