berkeley_library-tind 0.4.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 (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