libis-tools 1.0.5-java

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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +16 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +40 -0
  6. data/Gemfile +7 -0
  7. data/README.md +202 -0
  8. data/Rakefile +11 -0
  9. data/bin/libis_tool +5 -0
  10. data/lib/libis-tools.rb +1 -0
  11. data/lib/libis/tools.rb +25 -0
  12. data/lib/libis/tools/assert.rb +52 -0
  13. data/lib/libis/tools/checksum.rb +106 -0
  14. data/lib/libis/tools/cli/cli_helper.rb +189 -0
  15. data/lib/libis/tools/cli/reorg.rb +416 -0
  16. data/lib/libis/tools/command.rb +133 -0
  17. data/lib/libis/tools/command_line.rb +23 -0
  18. data/lib/libis/tools/config.rb +147 -0
  19. data/lib/libis/tools/config_file.rb +85 -0
  20. data/lib/libis/tools/csv.rb +38 -0
  21. data/lib/libis/tools/deep_struct.rb +71 -0
  22. data/lib/libis/tools/extend/array.rb +16 -0
  23. data/lib/libis/tools/extend/empty.rb +7 -0
  24. data/lib/libis/tools/extend/hash.rb +147 -0
  25. data/lib/libis/tools/extend/kernel.rb +25 -0
  26. data/lib/libis/tools/extend/ostruct.rb +3 -0
  27. data/lib/libis/tools/extend/roo.rb +91 -0
  28. data/lib/libis/tools/extend/string.rb +94 -0
  29. data/lib/libis/tools/extend/struct.rb +29 -0
  30. data/lib/libis/tools/extend/symbol.rb +8 -0
  31. data/lib/libis/tools/logger.rb +130 -0
  32. data/lib/libis/tools/mets_dnx.rb +61 -0
  33. data/lib/libis/tools/mets_file.rb +504 -0
  34. data/lib/libis/tools/mets_objects.rb +547 -0
  35. data/lib/libis/tools/parameter.rb +372 -0
  36. data/lib/libis/tools/spreadsheet.rb +196 -0
  37. data/lib/libis/tools/temp_file.rb +42 -0
  38. data/lib/libis/tools/thread_safe.rb +31 -0
  39. data/lib/libis/tools/version.rb +5 -0
  40. data/lib/libis/tools/xml_document.rb +583 -0
  41. data/libis-tools.gemspec +55 -0
  42. data/spec/assert_spec.rb +65 -0
  43. data/spec/checksum_spec.rb +68 -0
  44. data/spec/command_spec.rb +90 -0
  45. data/spec/config_file_spec.rb +83 -0
  46. data/spec/config_spec.rb +113 -0
  47. data/spec/csv_spec.rb +159 -0
  48. data/spec/data/test-headers.csv +2 -0
  49. data/spec/data/test-headers.tsv +2 -0
  50. data/spec/data/test-noheaders.csv +1 -0
  51. data/spec/data/test-noheaders.tsv +1 -0
  52. data/spec/data/test.data +9 -0
  53. data/spec/data/test.xlsx +0 -0
  54. data/spec/data/test.xml +8 -0
  55. data/spec/data/test.yml +2 -0
  56. data/spec/data/test_config.yml +15 -0
  57. data/spec/deep_struct_spec.rb +138 -0
  58. data/spec/logger_spec.rb +165 -0
  59. data/spec/mets_file_spec.rb +223 -0
  60. data/spec/parameter_container_spec.rb +152 -0
  61. data/spec/parameter_spec.rb +148 -0
  62. data/spec/spec_helper.rb +29 -0
  63. data/spec/spreadsheet_spec.rb +1820 -0
  64. data/spec/temp_file_spec.rb +76 -0
  65. data/spec/test.xsd +20 -0
  66. data/spec/thread_safe_spec.rb +64 -0
  67. data/spec/xmldocument_spec.rb +421 -0
  68. data/test/test_helper.rb +7 -0
  69. data/test/webservices/test_ca_item_info.rb +59 -0
  70. data/test/webservices/test_ca_search.rb +35 -0
  71. metadata +437 -0
@@ -0,0 +1,29 @@
1
+ # require 'codeclimate-test-reporter'
2
+ # ::CodeClimate::TestReporter.start
3
+
4
+ # if !defined?(RUBY_ENGINE) || RUBY_ENGINE != 'jruby'
5
+ require 'coveralls'
6
+ Coveralls.wear!
7
+ # end
8
+
9
+ # noinspection RubyResolve
10
+ require 'bundler/setup'
11
+ # noinspection RubyResolve
12
+ Bundler.setup
13
+
14
+ require 'rspec'
15
+ require 'libis-tools'
16
+
17
+ # RSpec.configure do |config|
18
+ # original_stderr = $stderr
19
+ # original_stdout = $stdout
20
+ # config.before(:all) do
21
+ # # Redirect stderr and stdout
22
+ # $stderr = File.open(File::NULL, 'w')
23
+ # $stdout = File.open(File::NULL, 'w')
24
+ # end
25
+ # config.after(:all) do
26
+ # $stderr = original_stderr
27
+ # $stdout = original_stdout
28
+ # end
29
+ # end
@@ -0,0 +1,1820 @@
1
+ # encoding: utf-8
2
+ require_relative 'spec_helper'
3
+ require 'rspec/matchers'
4
+ require 'libis/tools/spreadsheet'
5
+
6
+ describe 'Libis::Tools::Spreadsheet' do
7
+
8
+ let(:path) {File.absolute_path('data', File.dirname(__FILE__))}
9
+ let(:options) { {} }
10
+ let(:ss) {
11
+ Libis::Tools::Spreadsheet.new(
12
+ File.join(path, file_name),
13
+ { required: required_headers,
14
+ optional: optional_headers
15
+ }.merge(options)
16
+ )
17
+ }
18
+
19
+ let(:optional_headers) {[]}
20
+
21
+ context 'CSV file' do
22
+ context 'with headers' do
23
+ let(:file_name) {'test-headers.csv'}
24
+
25
+ context 'well-formed' do
26
+
27
+ let(:required_headers) {%w'FirstName LastName'}
28
+
29
+ it 'opens correctly' do
30
+ expect {ss}.not_to raise_error
31
+ end
32
+
33
+ it 'contains expected headers' do
34
+ required_headers.each do |header|
35
+ expect(ss.headers).to include header
36
+ end
37
+ expect(ss.headers).to eq %w'FirstName LastName address'
38
+ end
39
+
40
+ it '#shift returns Hash object' do
41
+ row = ss.shift
42
+ expect(row).to be_a Hash
43
+ expect(row['FirstName']).to eq 'John'
44
+ expect(row['LastName']).to eq 'Smith'
45
+ expect(row['address']).to eq 'mystreet 1, myplace'
46
+ expect(row['phone']).to be_nil
47
+ end
48
+
49
+ it '#parse returns Array of Hash objects' do
50
+ rows = ss.parse
51
+ expect(rows).to be_a Array
52
+ expect(rows.size).to eq 1
53
+ row = rows[0]
54
+ expect(row).to be_a Hash
55
+ expect(row['FirstName']).to eq 'John'
56
+ expect(row['LastName']).to eq 'Smith'
57
+ expect(row['address']).to eq 'mystreet 1, myplace'
58
+ expect(row['phone']).to be_nil
59
+ end
60
+
61
+ end
62
+
63
+ context 'not specified' do
64
+
65
+ let(:required_headers) {[]}
66
+
67
+ it 'opens correctly' do
68
+ expect {ss}.not_to raise_error
69
+ end
70
+
71
+ it 'contains expected headers' do
72
+ expect(ss.headers).to eq %w'FirstName LastName address'
73
+ end
74
+
75
+ it '#shift returns Hash object' do
76
+ row = ss.shift
77
+ expect(row).to be_a Hash
78
+ expect(row['FirstName']).to eq 'John'
79
+ expect(row['LastName']).to eq 'Smith'
80
+ expect(row['address']).to eq 'mystreet 1, myplace'
81
+ expect(row['phone']).to be_nil
82
+ end
83
+
84
+ it '#parse returns Array of Hash objects' do
85
+ rows = ss.parse
86
+ expect(rows).to be_a Array
87
+ expect(rows.size).to eq 1
88
+ row = rows[0]
89
+ expect(row).to be_a Hash
90
+ expect(row['FirstName']).to eq 'John'
91
+ expect(row['LastName']).to eq 'Smith'
92
+ expect(row['address']).to eq 'mystreet 1, myplace'
93
+ expect(row['phone']).to be_nil
94
+ end
95
+
96
+ end
97
+
98
+ context 'not well-formed' do
99
+
100
+ let(:required_headers) {%w'FirstName LastName address phone'}
101
+
102
+ it 'throws error when opened' do
103
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["phone"].')
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+ context 'without headers' do
110
+ let(:file_name) {'test-noheaders.csv'}
111
+
112
+ context 'well-formed and strict' do
113
+ let(:required_headers) {%w'FirstName LastName'}
114
+
115
+ it 'opens correctly' do
116
+ expect {ss}.not_to raise_error
117
+ end
118
+
119
+ it 'contains only required headers' do
120
+ required_headers.each do |header|
121
+ expect(ss.headers).to include header
122
+ end
123
+ expect(ss.headers).to eq %w'FirstName LastName'
124
+ end
125
+
126
+ it '#shift returns Hash object' do
127
+ row = ss.shift
128
+ expect(row).to be_a Hash
129
+ expect(row['FirstName']).to eq 'John'
130
+ expect(row['LastName']).to eq 'Smith'
131
+ expect(row['address']).to be_nil
132
+ expect(row['phone']).to be_nil
133
+ end
134
+
135
+ it '#parse returns Array of Hash objects' do
136
+ rows = ss.parse
137
+ expect(rows).to be_a Array
138
+ expect(rows.size).to eq 1
139
+ row = rows[0]
140
+ expect(row).to be_a Hash
141
+ expect(row['FirstName']).to eq 'John'
142
+ expect(row['LastName']).to eq 'Smith'
143
+ expect(row['address']).to be_nil
144
+ expect(row['phone']).to be_nil
145
+ end
146
+
147
+ end
148
+
149
+ context 'well-formed with optional headers' do
150
+ let(:required_headers) {%w'FirstName LastName'}
151
+ let(:optional_headers) {%w'address'}
152
+
153
+ it 'opens correctly' do
154
+ expect {ss}.not_to raise_error
155
+ end
156
+
157
+ it 'contains required and optional headers' do
158
+ required_headers.each do |header|
159
+ expect(ss.headers).to include header
160
+ end
161
+ optional_headers.each do |header|
162
+ expect(ss.headers).to include header
163
+ end
164
+ expect(ss.headers).to eq %w'FirstName LastName address'
165
+ end
166
+
167
+ it '#shift returns Hash object' do
168
+ row = ss.shift
169
+ expect(row).to be_a Hash
170
+ expect(row['FirstName']).to eq 'John'
171
+ expect(row['LastName']).to eq 'Smith'
172
+ expect(row['address']).to eq 'mystreet 1, myplace'
173
+ expect(row['phone']).to be_nil
174
+ end
175
+
176
+ it '#parse returns Array of Hash objects' do
177
+ rows = ss.parse
178
+ expect(rows).to be_a Array
179
+ expect(rows.size).to eq 1
180
+ row = rows[0]
181
+ expect(row).to be_a Hash
182
+ expect(row['FirstName']).to eq 'John'
183
+ expect(row['LastName']).to eq 'Smith'
184
+ expect(row['address']).to eq 'mystreet 1, myplace'
185
+ expect(row['phone']).to be_nil
186
+ end
187
+
188
+ end
189
+
190
+ context 'missing optional headers' do
191
+
192
+ let(:required_headers) {%w'FirstName LastName address'}
193
+ let(:optional_headers) {%w'phone'}
194
+
195
+ it 'opens correctly' do
196
+ expect {ss}.not_to raise_error
197
+ end
198
+
199
+ it 'contains only required headers' do
200
+ required_headers.each do |header|
201
+ expect(ss.headers).to include header
202
+ end
203
+ optional_headers.each do |header|
204
+ expect(ss.headers).not_to include header
205
+ end
206
+ expect(ss.headers).to eq %w'FirstName LastName address'
207
+ end
208
+
209
+ it '#shift returns Hash object' do
210
+ row = ss.shift
211
+ expect(row).to be_a Hash
212
+ expect(row['FirstName']).to eq 'John'
213
+ expect(row['LastName']).to eq 'Smith'
214
+ expect(row['address']).to eq 'mystreet 1, myplace'
215
+ expect(row['phone']).to be_nil
216
+ end
217
+
218
+ it '#parse returns Array of Hash objects' do
219
+ rows = ss.parse
220
+ expect(rows).to be_a Array
221
+ expect(rows.size).to eq 1
222
+ row = rows[0]
223
+ expect(row).to be_a Hash
224
+ expect(row['FirstName']).to eq 'John'
225
+ expect(row['LastName']).to eq 'Smith'
226
+ expect(row['address']).to eq 'mystreet 1, myplace'
227
+ expect(row['phone']).to be_nil
228
+ end
229
+
230
+ end
231
+
232
+ context 'missing required header' do
233
+ let(:required_headers) {%w'FirstName LastName address phone'}
234
+
235
+ it 'throws error when opened' do
236
+ expect {ss}.to raise_error(RuntimeError, 'Sheet does not contain enough columns.')
237
+ end
238
+
239
+ end
240
+
241
+ end
242
+
243
+ end
244
+
245
+ context 'TSV file' do
246
+
247
+ let(:options) { {
248
+ col_sep: "\t",
249
+ extension: 'csv'
250
+ }}
251
+
252
+ context 'with headers' do
253
+
254
+ let(:file_name) {'test-headers.tsv'}
255
+
256
+ context 'well-formed' do
257
+
258
+ let(:required_headers) {%w'FirstName LastName'}
259
+
260
+ it 'opens correctly' do
261
+ expect {ss}.not_to raise_error
262
+ end
263
+
264
+ it 'contains expected headers' do
265
+ required_headers.each do |header|
266
+ expect(ss.headers).to include header
267
+ end
268
+ expect(ss.headers).to eq %w'FirstName LastName address'
269
+ end
270
+
271
+ it '#shift returns Hash object' do
272
+ row = ss.shift
273
+ expect(row).to be_a Hash
274
+ expect(row['FirstName']).to eq 'John'
275
+ expect(row['LastName']).to eq 'Smith'
276
+ expect(row['address']).to eq 'mystreet 1, myplace'
277
+ expect(row['phone']).to be_nil
278
+ end
279
+
280
+ it '#parse returns Array of Hash objects' do
281
+ rows = ss.parse
282
+ expect(rows).to be_a Array
283
+ expect(rows.size).to eq 1
284
+ row = rows[0]
285
+ expect(row).to be_a Hash
286
+ expect(row['FirstName']).to eq 'John'
287
+ expect(row['LastName']).to eq 'Smith'
288
+ expect(row['address']).to eq 'mystreet 1, myplace'
289
+ expect(row['phone']).to be_nil
290
+ end
291
+
292
+ end
293
+
294
+ context 'not specified' do
295
+
296
+ let(:required_headers) {[]}
297
+
298
+ it 'opens correctly' do
299
+ expect {ss}.not_to raise_error
300
+ end
301
+
302
+ it 'contains expected headers' do
303
+ expect(ss.headers).to eq %w'FirstName LastName address'
304
+ end
305
+
306
+ it '#shift returns Hash object' do
307
+ row = ss.shift
308
+ expect(row).to be_a Hash
309
+ expect(row['FirstName']).to eq 'John'
310
+ expect(row['LastName']).to eq 'Smith'
311
+ expect(row['address']).to eq 'mystreet 1, myplace'
312
+ expect(row['phone']).to be_nil
313
+ end
314
+
315
+ it '#parse returns Array of Hash objects' do
316
+ rows = ss.parse
317
+ expect(rows).to be_a Array
318
+ expect(rows.size).to eq 1
319
+ row = rows[0]
320
+ expect(row).to be_a Hash
321
+ expect(row['FirstName']).to eq 'John'
322
+ expect(row['LastName']).to eq 'Smith'
323
+ expect(row['address']).to eq 'mystreet 1, myplace'
324
+ expect(row['phone']).to be_nil
325
+ end
326
+
327
+ end
328
+
329
+ context 'not well-formed' do
330
+
331
+ let(:required_headers) {%w'FirstName LastName address phone'}
332
+
333
+ it 'throws error when opened' do
334
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["phone"].')
335
+ end
336
+ end
337
+
338
+ end
339
+
340
+ context 'without headers' do
341
+ let(:file_name) {'test-noheaders.tsv'}
342
+
343
+ context 'well-formed and strict' do
344
+ let(:required_headers) {%w'FirstName LastName'}
345
+
346
+ it 'opens correctly' do
347
+ expect {ss}.not_to raise_error
348
+ end
349
+
350
+ it 'contains only required headers' do
351
+ required_headers.each do |header|
352
+ expect(ss.headers).to include header
353
+ end
354
+ expect(ss.headers).to eq %w'FirstName LastName'
355
+ end
356
+
357
+ it '#shift returns Hash object' do
358
+ row = ss.shift
359
+ expect(row).to be_a Hash
360
+ expect(row['FirstName']).to eq 'John'
361
+ expect(row['LastName']).to eq 'Smith'
362
+ expect(row['address']).to be_nil
363
+ expect(row['phone']).to be_nil
364
+ end
365
+
366
+ it '#parse returns Array of Hash objects' do
367
+ rows = ss.parse
368
+ expect(rows).to be_a Array
369
+ expect(rows.size).to eq 1
370
+ row = rows[0]
371
+ expect(row).to be_a Hash
372
+ expect(row['FirstName']).to eq 'John'
373
+ expect(row['LastName']).to eq 'Smith'
374
+ expect(row['address']).to be_nil
375
+ expect(row['phone']).to be_nil
376
+ end
377
+
378
+ end
379
+
380
+ context 'well-formed with optional headers' do
381
+ let(:required_headers) {%w'FirstName LastName'}
382
+ let(:optional_headers) {%w'address'}
383
+
384
+ it 'opens correctly' do
385
+ expect {ss}.not_to raise_error
386
+ end
387
+
388
+ it 'contains required and optional headers' do
389
+ required_headers.each do |header|
390
+ expect(ss.headers).to include header
391
+ end
392
+ optional_headers.each do |header|
393
+ expect(ss.headers).to include header
394
+ end
395
+ expect(ss.headers).to eq %w'FirstName LastName address'
396
+ end
397
+
398
+ it '#shift returns Hash object' do
399
+ row = ss.shift
400
+ expect(row).to be_a Hash
401
+ expect(row['FirstName']).to eq 'John'
402
+ expect(row['LastName']).to eq 'Smith'
403
+ expect(row['address']).to eq 'mystreet 1, myplace'
404
+ expect(row['phone']).to be_nil
405
+ end
406
+
407
+ it '#parse returns Array of Hash objects' do
408
+ rows = ss.parse
409
+ expect(rows).to be_a Array
410
+ expect(rows.size).to eq 1
411
+ row = rows[0]
412
+ expect(row).to be_a Hash
413
+ expect(row['FirstName']).to eq 'John'
414
+ expect(row['LastName']).to eq 'Smith'
415
+ expect(row['address']).to eq 'mystreet 1, myplace'
416
+ expect(row['phone']).to be_nil
417
+ end
418
+
419
+ end
420
+
421
+ context 'missing optional headers' do
422
+
423
+ let(:required_headers) {%w'FirstName LastName address'}
424
+ let(:optional_headers) {%w'phone'}
425
+
426
+ it 'opens correctly' do
427
+ expect {ss}.not_to raise_error
428
+ end
429
+
430
+ it 'contains only required headers' do
431
+ required_headers.each do |header|
432
+ expect(ss.headers).to include header
433
+ end
434
+ optional_headers.each do |header|
435
+ expect(ss.headers).not_to include header
436
+ end
437
+ expect(ss.headers).to eq %w'FirstName LastName address'
438
+ end
439
+
440
+ it '#shift returns Hash object' do
441
+ row = ss.shift
442
+ expect(row).to be_a Hash
443
+ expect(row['FirstName']).to eq 'John'
444
+ expect(row['LastName']).to eq 'Smith'
445
+ expect(row['address']).to eq 'mystreet 1, myplace'
446
+ expect(row['phone']).to be_nil
447
+ end
448
+
449
+ it '#parse returns Array of Hash objects' do
450
+ rows = ss.parse
451
+ expect(rows).to be_a Array
452
+ expect(rows.size).to eq 1
453
+ row = rows[0]
454
+ expect(row).to be_a Hash
455
+ expect(row['FirstName']).to eq 'John'
456
+ expect(row['LastName']).to eq 'Smith'
457
+ expect(row['address']).to eq 'mystreet 1, myplace'
458
+ expect(row['phone']).to be_nil
459
+ end
460
+
461
+ end
462
+
463
+ context 'missing required header' do
464
+ let(:required_headers) {%w'FirstName LastName address phone'}
465
+
466
+ it 'throws error when opened' do
467
+ expect {ss}.to raise_error(RuntimeError, 'Sheet does not contain enough columns.')
468
+ end
469
+
470
+ end
471
+
472
+ end
473
+
474
+ end
475
+
476
+ context 'XLSX file' do
477
+
478
+ let(:real_headers) {%w'Date Amount Code Remark'}
479
+ # noinspection RubyStringKeysInHashInspection
480
+ let(:header_row) {{'Date' => 'Date', 'Amount' => 'Amount', 'Code' => 'Code', 'Remark' => 'Remark'}}
481
+ # noinspection RubyStringKeysInHashInspection
482
+ let(:first_data_row) {{'Date' => Date.new(2016, 05, 10), 'Amount' => 1270.0, 'Code' => 1, 'Remark' => 'a'}}
483
+ # noinspection RubyStringKeysInHashInspection
484
+ let(:data_row_13) {{'Date' => Date.new(2016, 7, 1), 'Amount' => 3705.0, 'Code' => 3, 'Remark' => 'b'}}
485
+ let(:size_with_headers) { 18 }
486
+ let(:size_without_headers) { 17 }
487
+
488
+ context 'with headers' do
489
+ let(:file_name) {'test.xlsx|Expenses'}
490
+
491
+ context 'well-formed' do
492
+
493
+ let(:required_headers) {%w'Date Amount'}
494
+
495
+ it 'opens correctly' do
496
+ expect {ss}.not_to raise_error
497
+ end
498
+
499
+ it 'contains expected headers' do
500
+ required_headers.each do |header|
501
+ expect(ss.headers).to include header
502
+ end
503
+ expect(ss.headers).to eq real_headers
504
+ end
505
+
506
+ it 'each returns header and data rows' do
507
+ expect(ss.each.count).to eq size_with_headers
508
+ expect(ss.each.first).to eq header_row
509
+ end
510
+
511
+ it '#shift returns Hash object' do
512
+ row = ss.shift
513
+ expect(row).to be_a Hash
514
+ expect(row['Date']).to eq first_data_row['Date']
515
+ expect(row['Amount']).to eq first_data_row['Amount']
516
+ expect(row['Code']).to eq first_data_row['Code']
517
+ expect(row['Remark']).to eq first_data_row['Remark']
518
+ expect(row['dummy']).to be_nil
519
+ end
520
+
521
+ it '#parse returns Array of Hash objects' do
522
+ rows = ss.parse
523
+ expect(rows).to be_a Array
524
+ expect(rows.size).to eq size_without_headers
525
+ row = rows[0]
526
+ expect(row).to be_a Hash
527
+ expect(row['Date']).to eq first_data_row['Date']
528
+ expect(row['Amount']).to eq first_data_row['Amount']
529
+ expect(row['Code']).to eq first_data_row['Code']
530
+ expect(row['Remark']).to eq first_data_row['Remark']
531
+ expect(row['dummy']).to be_nil
532
+ row = rows[13]
533
+ expect(row).to be_a Hash
534
+ expect(row['Date']).to eq data_row_13['Date']
535
+ expect(row['Amount']).to eq data_row_13['Amount']
536
+ expect(row['Code']).to eq data_row_13['Code']
537
+ expect(row['Remark']).to eq data_row_13['Remark']
538
+ expect(row['dummy']).to be_nil
539
+ end
540
+
541
+ end
542
+
543
+ context 'not specified' do
544
+
545
+ let(:required_headers) {[]}
546
+
547
+
548
+ it 'opens correctly' do
549
+ expect {ss}.not_to raise_error
550
+ end
551
+
552
+ it 'contains expected headers' do
553
+ required_headers.each do |header|
554
+ expect(ss.headers).to include header
555
+ end
556
+ expect(ss.headers).to eq real_headers
557
+ end
558
+
559
+ it 'each returns header and data rows' do
560
+ expect(ss.each.count).to eq size_with_headers
561
+ expect(ss.each.first).to eq header_row
562
+ end
563
+
564
+ it '#shift returns Hash object' do
565
+ row = ss.shift
566
+ expect(row).to be_a Hash
567
+ expect(row['Date']).to eq first_data_row['Date']
568
+ expect(row['Amount']).to eq first_data_row['Amount']
569
+ expect(row['Code']).to eq first_data_row['Code']
570
+ expect(row['Remark']).to eq first_data_row['Remark']
571
+ expect(row['dummy']).to be_nil
572
+ end
573
+
574
+ it '#parse returns Array of Hash objects' do
575
+ rows = ss.parse
576
+ expect(rows).to be_a Array
577
+ expect(rows.size).to eq size_without_headers
578
+ row = rows[0]
579
+ expect(row).to be_a Hash
580
+ expect(row['Date']).to eq first_data_row['Date']
581
+ expect(row['Amount']).to eq first_data_row['Amount']
582
+ expect(row['Code']).to eq first_data_row['Code']
583
+ expect(row['Remark']).to eq first_data_row['Remark']
584
+ expect(row['dummy']).to be_nil
585
+ row = rows[13]
586
+ expect(row).to be_a Hash
587
+ expect(row['Date']).to eq data_row_13['Date']
588
+ expect(row['Amount']).to eq data_row_13['Amount']
589
+ expect(row['Code']).to eq data_row_13['Code']
590
+ expect(row['Remark']).to eq data_row_13['Remark']
591
+ expect(row['dummy']).to be_nil
592
+ end
593
+
594
+ end
595
+
596
+ context 'not well-formed' do
597
+
598
+ let(:required_headers) {%w'Date dummy1 Amount dummy2'}
599
+
600
+ it 'throws error when opened' do
601
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["dummy1", "dummy2"].')
602
+ end
603
+ end
604
+
605
+ end
606
+
607
+ context 'without headers' do
608
+ let(:file_name) {'test.xlsx|ExpensesNoHeaders'}
609
+
610
+ context 'well-formed and strict' do
611
+ let(:required_headers) {%w'Date Amount'}
612
+
613
+ it 'opens correctly' do
614
+ expect {ss}.not_to raise_error
615
+ end
616
+
617
+ it 'contains only required headers' do
618
+ required_headers.each do |header|
619
+ expect(ss.headers).to include header
620
+ end
621
+ expect(ss.headers).to eq required_headers
622
+ end
623
+
624
+ it 'each returns header and data rows' do
625
+ expect(ss.each.count).to eq size_with_headers
626
+ expect(ss.each.first.keys).to eq required_headers
627
+ end
628
+
629
+ it '#shift returns Hash object' do
630
+ row = ss.shift
631
+ expect(row).to be_a Hash
632
+ expect(row['Date']).to eq first_data_row['Date']
633
+ expect(row['Amount']).to eq first_data_row['Amount']
634
+ expect(row['Code']).to be_nil
635
+ expect(row['Remark']).to be_nil
636
+ expect(row['dummy']).to be_nil
637
+ end
638
+
639
+ it '#parse returns Array of Hash objects' do
640
+ rows = ss.parse
641
+ expect(rows).to be_a Array
642
+ expect(rows.size).to eq size_without_headers
643
+ row = rows[0]
644
+ expect(row).to be_a Hash
645
+ expect(row['Date']).to eq first_data_row['Date']
646
+ expect(row['Amount']).to eq first_data_row['Amount']
647
+ expect(row['Code']).to be_nil
648
+ expect(row['Remark']).to be_nil
649
+ expect(row['dummy']).to be_nil
650
+ row = rows[13]
651
+ expect(row).to be_a Hash
652
+ expect(row['Date']).to eq data_row_13['Date']
653
+ expect(row['Amount']).to eq data_row_13['Amount']
654
+ expect(row['Code']).to be_nil
655
+ expect(row['Remark']).to be_nil
656
+ expect(row['dummy']).to be_nil
657
+ end
658
+
659
+ end
660
+
661
+ context 'well-formed with optional headers' do
662
+ let(:required_headers) {%w'Date Amount'}
663
+ let(:optional_headers) {%w'Code'}
664
+
665
+ it 'opens correctly' do
666
+ expect {ss}.not_to raise_error
667
+ end
668
+
669
+ it 'contains required and optional headers' do
670
+ required_headers.each do |header|
671
+ expect(ss.headers).to include header
672
+ end
673
+ optional_headers.each do |header|
674
+ expect(ss.headers).to include header
675
+ end
676
+ expect(ss.headers).to eq required_headers + optional_headers
677
+ end
678
+
679
+ it 'each returns header and data rows' do
680
+ expect(ss.each.count).to eq size_with_headers
681
+ expect(ss.each.first.keys).to eq required_headers + optional_headers
682
+ end
683
+
684
+ it '#shift returns Hash object' do
685
+ row = ss.shift
686
+ expect(row).to be_a Hash
687
+ expect(row['Date']).to eq first_data_row['Date']
688
+ expect(row['Amount']).to eq first_data_row['Amount']
689
+ expect(row['Code']).to eq first_data_row['Code']
690
+ expect(row['Remark']).to be_nil
691
+ expect(row['dummy']).to be_nil
692
+ end
693
+
694
+ it '#parse returns Array of Hash objects' do
695
+ rows = ss.parse
696
+ expect(rows).to be_a Array
697
+ expect(rows.size).to eq size_without_headers
698
+ row = rows[0]
699
+ expect(row).to be_a Hash
700
+ expect(row['Date']).to eq first_data_row['Date']
701
+ expect(row['Amount']).to eq first_data_row['Amount']
702
+ expect(row['Code']).to eq first_data_row['Code']
703
+ expect(row['Remark']).to be_nil
704
+ expect(row['dummy']).to be_nil
705
+ row = rows[13]
706
+ expect(row).to be_a Hash
707
+ expect(row['Date']).to eq data_row_13['Date']
708
+ expect(row['Amount']).to eq data_row_13['Amount']
709
+ expect(row['Code']).to eq data_row_13['Code']
710
+ expect(row['Remark']).to be_nil
711
+ expect(row['dummy']).to be_nil
712
+ end
713
+
714
+ end
715
+
716
+ context 'missing optional headers' do
717
+
718
+ let(:required_headers) {%w'Date Amount Code Remark'}
719
+ let(:optional_headers) {%w'dummy'}
720
+
721
+ it 'opens correctly' do
722
+ expect {ss}.not_to raise_error
723
+ end
724
+
725
+ it 'contains only required headers' do
726
+ required_headers.each do |header|
727
+ expect(ss.headers).to include header
728
+ end
729
+ optional_headers.each do |header|
730
+ expect(ss.headers).not_to include header
731
+ end
732
+ expect(ss.headers).to eq required_headers
733
+ end
734
+
735
+ it 'each returns header and data rows' do
736
+ expect(ss.each.count).to eq size_with_headers
737
+ expect(ss.each.first.keys).to eq required_headers
738
+ end
739
+
740
+ it '#shift returns Hash object' do
741
+ row = ss.shift
742
+ expect(row).to be_a Hash
743
+ expect(row['Date']).to eq first_data_row['Date']
744
+ expect(row['Amount']).to eq first_data_row['Amount']
745
+ expect(row['Code']).to eq first_data_row['Code']
746
+ expect(row['Remark']).to eq first_data_row['Remark']
747
+ expect(row['dummy']).to be_nil
748
+ end
749
+
750
+ it '#parse returns Array of Hash objects' do
751
+ rows = ss.parse
752
+ expect(rows).to be_a Array
753
+ expect(rows.size).to eq size_without_headers
754
+ row = rows[0]
755
+ expect(row).to be_a Hash
756
+ expect(row['Date']).to eq first_data_row['Date']
757
+ expect(row['Amount']).to eq first_data_row['Amount']
758
+ expect(row['Code']).to eq first_data_row['Code']
759
+ expect(row['Remark']).to eq first_data_row['Remark']
760
+ expect(row['dummy']).to be_nil
761
+ row = rows[13]
762
+ expect(row).to be_a Hash
763
+ expect(row['Date']).to eq data_row_13['Date']
764
+ expect(row['Amount']).to eq data_row_13['Amount']
765
+ expect(row['Code']).to eq data_row_13['Code']
766
+ expect(row['Remark']).to eq data_row_13['Remark']
767
+ expect(row['dummy']).to be_nil
768
+ end
769
+
770
+ end
771
+
772
+ context 'missing required header' do
773
+ let(:required_headers) {%w'Date Amount Code Remark dummy'}
774
+
775
+ it 'throws error when opened' do
776
+ expect {ss}.to raise_error(RuntimeError, 'Sheet does not contain enough columns.')
777
+ end
778
+
779
+ end
780
+
781
+ end
782
+
783
+ context 'blank rows with headers' do
784
+ let(:file_name) {'test.xlsx|ExpensesBlankRows'}
785
+
786
+ context 'well-formed' do
787
+
788
+ let(:required_headers) {%w'Date Amount'}
789
+
790
+ it 'opens correctly' do
791
+ expect {ss}.not_to raise_error
792
+ end
793
+
794
+ it 'contains expected headers' do
795
+ required_headers.each do |header|
796
+ expect(ss.headers).to include header
797
+ end
798
+ expect(ss.headers).to eq real_headers
799
+ end
800
+
801
+ it 'each returns header and data rows' do
802
+ expect(ss.each.count).to eq size_with_headers
803
+ expect(ss.each.first).to eq header_row
804
+ end
805
+
806
+ it '#shift returns Hash object' do
807
+ row = ss.shift
808
+ expect(row).to be_a Hash
809
+ expect(row['Date']).to eq first_data_row['Date']
810
+ expect(row['Amount']).to eq first_data_row['Amount']
811
+ expect(row['Code']).to eq first_data_row['Code']
812
+ expect(row['Remark']).to eq first_data_row['Remark']
813
+ expect(row['dummy']).to be_nil
814
+ end
815
+
816
+ it '#parse returns Array of Hash objects' do
817
+ rows = ss.parse
818
+ expect(rows).to be_a Array
819
+ expect(rows.size).to eq size_without_headers
820
+ row = rows[0]
821
+ expect(row).to be_a Hash
822
+ expect(row['Date']).to eq first_data_row['Date']
823
+ expect(row['Amount']).to eq first_data_row['Amount']
824
+ expect(row['Code']).to eq first_data_row['Code']
825
+ expect(row['Remark']).to eq first_data_row['Remark']
826
+ expect(row['dummy']).to be_nil
827
+ row = rows[13]
828
+ expect(row).to be_a Hash
829
+ expect(row['Date']).to eq data_row_13['Date']
830
+ expect(row['Amount']).to eq data_row_13['Amount']
831
+ expect(row['Code']).to eq data_row_13['Code']
832
+ expect(row['Remark']).to eq data_row_13['Remark']
833
+ expect(row['dummy']).to be_nil
834
+ end
835
+
836
+ end
837
+
838
+ context 'not specified' do
839
+
840
+ let(:required_headers) {[]}
841
+
842
+ it 'opens correctly' do
843
+ expect {ss}.not_to raise_error
844
+ end
845
+
846
+ it 'contains expected headers' do
847
+ required_headers.each do |header|
848
+ expect(ss.headers).to include header
849
+ end
850
+ expect(ss.headers).to eq real_headers
851
+ end
852
+
853
+ it 'each returns header and data rows' do
854
+ expect(ss.each.count).to eq size_with_headers
855
+ expect(ss.each.first).to eq header_row
856
+ end
857
+
858
+ it '#shift returns Hash object' do
859
+ row = ss.shift
860
+ expect(row).to be_a Hash
861
+ expect(row['Date']).to eq first_data_row['Date']
862
+ expect(row['Amount']).to eq first_data_row['Amount']
863
+ expect(row['Code']).to eq first_data_row['Code']
864
+ expect(row['Remark']).to eq first_data_row['Remark']
865
+ expect(row['dummy']).to be_nil
866
+ end
867
+
868
+ it '#parse returns Array of Hash objects' do
869
+ rows = ss.parse
870
+ expect(rows).to be_a Array
871
+ expect(rows.size).to eq size_without_headers
872
+ row = rows[0]
873
+ expect(row).to be_a Hash
874
+ expect(row['Date']).to eq first_data_row['Date']
875
+ expect(row['Amount']).to eq first_data_row['Amount']
876
+ expect(row['Code']).to eq first_data_row['Code']
877
+ expect(row['Remark']).to eq first_data_row['Remark']
878
+ expect(row['dummy']).to be_nil
879
+ row = rows[13]
880
+ expect(row).to be_a Hash
881
+ expect(row['Date']).to eq data_row_13['Date']
882
+ expect(row['Amount']).to eq data_row_13['Amount']
883
+ expect(row['Code']).to eq data_row_13['Code']
884
+ expect(row['Remark']).to eq data_row_13['Remark']
885
+ expect(row['dummy']).to be_nil
886
+ end
887
+
888
+ end
889
+
890
+ context 'not well-formed' do
891
+
892
+ let(:required_headers) {%w'Date dummy1 Amount dummy2'}
893
+
894
+ it 'throws error when opened' do
895
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["dummy1", "dummy2"].')
896
+ end
897
+ end
898
+
899
+ end
900
+
901
+ context 'blank rows without headers' do
902
+ let(:file_name) {'test.xlsx|ExpensesBlankRowsNoHeaders'}
903
+
904
+ context 'well-formed and strict' do
905
+ let(:required_headers) {%w'Date Amount'}
906
+
907
+ it 'opens correctly' do
908
+ expect {ss}.not_to raise_error
909
+ end
910
+
911
+ it 'contains only required headers' do
912
+ required_headers.each do |header|
913
+ expect(ss.headers).to include header
914
+ end
915
+ expect(ss.headers).to eq required_headers
916
+ end
917
+
918
+ it 'each returns header and data rows' do
919
+ expect(ss.each.count).to eq size_with_headers
920
+ expect(ss.each.first.keys).to eq required_headers
921
+ end
922
+
923
+ it '#shift returns Hash object' do
924
+ row = ss.shift
925
+ expect(row).to be_a Hash
926
+ expect(row['Date']).to eq first_data_row['Date']
927
+ expect(row['Amount']).to eq first_data_row['Amount']
928
+ expect(row['Code']).to be_nil
929
+ expect(row['Remark']).to be_nil
930
+ expect(row['dummy']).to be_nil
931
+ end
932
+
933
+ it '#parse returns Array of Hash objects' do
934
+ rows = ss.parse
935
+ expect(rows).to be_a Array
936
+ expect(rows.size).to eq size_without_headers
937
+ row = rows[0]
938
+ expect(row).to be_a Hash
939
+ expect(row['Date']).to eq first_data_row['Date']
940
+ expect(row['Amount']).to eq first_data_row['Amount']
941
+ expect(row['Code']).to be_nil
942
+ expect(row['Remark']).to be_nil
943
+ expect(row['dummy']).to be_nil
944
+ row = rows[13]
945
+ expect(row).to be_a Hash
946
+ expect(row['Date']).to eq data_row_13['Date']
947
+ expect(row['Amount']).to eq data_row_13['Amount']
948
+ expect(row['Code']).to be_nil
949
+ expect(row['Remark']).to be_nil
950
+ expect(row['dummy']).to be_nil
951
+ end
952
+
953
+ end
954
+
955
+ context 'well-formed with optional headers' do
956
+ let(:required_headers) {%w'Date Amount'}
957
+ let(:optional_headers) {%w'Code'}
958
+
959
+ it 'opens correctly' do
960
+ expect {ss}.not_to raise_error
961
+ end
962
+
963
+ it 'contains required and optional headers' do
964
+ required_headers.each do |header|
965
+ expect(ss.headers).to include header
966
+ end
967
+ optional_headers.each do |header|
968
+ expect(ss.headers).to include header
969
+ end
970
+ expect(ss.headers).to eq required_headers + optional_headers
971
+ end
972
+
973
+ it 'each returns header and data rows' do
974
+ expect(ss.each.count).to eq size_with_headers
975
+ expect(ss.each.first.keys).to eq required_headers + optional_headers
976
+ end
977
+
978
+ it '#shift returns Hash object' do
979
+ row = ss.shift
980
+ expect(row).to be_a Hash
981
+ expect(row['Date']).to eq first_data_row['Date']
982
+ expect(row['Amount']).to eq first_data_row['Amount']
983
+ expect(row['Code']).to eq first_data_row['Code']
984
+ expect(row['Remark']).to be_nil
985
+ expect(row['dummy']).to be_nil
986
+ end
987
+
988
+ it '#parse returns Array of Hash objects' do
989
+ rows = ss.parse
990
+ expect(rows).to be_a Array
991
+ expect(rows.size).to eq size_without_headers
992
+ row = rows[0]
993
+ expect(row).to be_a Hash
994
+ expect(row['Date']).to eq first_data_row['Date']
995
+ expect(row['Amount']).to eq first_data_row['Amount']
996
+ expect(row['Code']).to eq first_data_row['Code']
997
+ expect(row['Remark']).to be_nil
998
+ expect(row['dummy']).to be_nil
999
+ row = rows[13]
1000
+ expect(row).to be_a Hash
1001
+ expect(row['Date']).to eq data_row_13['Date']
1002
+ expect(row['Amount']).to eq data_row_13['Amount']
1003
+ expect(row['Code']).to eq data_row_13['Code']
1004
+ expect(row['Remark']).to be_nil
1005
+ expect(row['dummy']).to be_nil
1006
+ end
1007
+
1008
+ end
1009
+
1010
+ context 'missing optional headers' do
1011
+
1012
+ let(:required_headers) {%w'Date Amount Code Remark'}
1013
+ let(:optional_headers) {%w'dummy'}
1014
+
1015
+ it 'opens correctly' do
1016
+ expect {ss}.not_to raise_error
1017
+ end
1018
+
1019
+ it 'contains only required headers' do
1020
+ required_headers.each do |header|
1021
+ expect(ss.headers).to include header
1022
+ end
1023
+ optional_headers.each do |header|
1024
+ expect(ss.headers).not_to include header
1025
+ end
1026
+ expect(ss.headers).to eq required_headers
1027
+ end
1028
+
1029
+ it 'each returns header and data rows' do
1030
+ expect(ss.each.count).to eq size_with_headers
1031
+ expect(ss.each.first.keys).to eq required_headers
1032
+ end
1033
+
1034
+ it '#shift returns Hash object' do
1035
+ row = ss.shift
1036
+ expect(row).to be_a Hash
1037
+ expect(row['Date']).to eq first_data_row['Date']
1038
+ expect(row['Amount']).to eq first_data_row['Amount']
1039
+ expect(row['Code']).to eq first_data_row['Code']
1040
+ expect(row['Remark']).to eq first_data_row['Remark']
1041
+ expect(row['dummy']).to be_nil
1042
+ end
1043
+
1044
+ it '#parse returns Array of Hash objects' do
1045
+ rows = ss.parse
1046
+ expect(rows).to be_a Array
1047
+ expect(rows.size).to eq size_without_headers
1048
+ row = rows[0]
1049
+ expect(row).to be_a Hash
1050
+ expect(row['Date']).to eq first_data_row['Date']
1051
+ expect(row['Amount']).to eq first_data_row['Amount']
1052
+ expect(row['Code']).to eq first_data_row['Code']
1053
+ expect(row['Remark']).to eq first_data_row['Remark']
1054
+ expect(row['dummy']).to be_nil
1055
+ row = rows[13]
1056
+ expect(row).to be_a Hash
1057
+ expect(row['Date']).to eq data_row_13['Date']
1058
+ expect(row['Amount']).to eq data_row_13['Amount']
1059
+ expect(row['Code']).to eq data_row_13['Code']
1060
+ expect(row['Remark']).to eq data_row_13['Remark']
1061
+ expect(row['dummy']).to be_nil
1062
+ end
1063
+
1064
+ end
1065
+
1066
+ context 'missing required header' do
1067
+ let(:required_headers) {%w'Date Amount Code Remark dummy'}
1068
+
1069
+ it 'throws error when opened' do
1070
+ expect {ss}.to raise_error(RuntimeError, 'Sheet does not contain enough columns.')
1071
+ end
1072
+
1073
+ end
1074
+
1075
+ end
1076
+
1077
+ context 'blank columns with headers' do
1078
+ let(:file_name) {'test.xlsx|ExpensesBlankColumns'}
1079
+
1080
+ context 'well-formed' do
1081
+
1082
+ let(:required_headers) {%w'Date Amount'}
1083
+
1084
+ it 'opens correctly' do
1085
+ expect {ss}.not_to raise_error
1086
+ end
1087
+
1088
+ it 'contains expected headers' do
1089
+ required_headers.each do |header|
1090
+ expect(ss.headers).to include header
1091
+ end
1092
+ expect(ss.headers).to eq real_headers
1093
+ end
1094
+
1095
+ it 'each returns header and data rows' do
1096
+ expect(ss.each.count).to eq size_with_headers
1097
+ expect(ss.each.first).to eq header_row
1098
+ end
1099
+
1100
+ it '#shift returns Hash object' do
1101
+ row = ss.shift
1102
+ expect(row).to be_a Hash
1103
+ expect(row['Date']).to eq first_data_row['Date']
1104
+ expect(row['Amount']).to eq first_data_row['Amount']
1105
+ expect(row['Code']).to eq first_data_row['Code']
1106
+ expect(row['Remark']).to eq first_data_row['Remark']
1107
+ expect(row['dummy']).to be_nil
1108
+ end
1109
+
1110
+ it '#parse returns Array of Hash objects' do
1111
+ rows = ss.parse
1112
+ expect(rows).to be_a Array
1113
+ expect(rows.size).to eq size_without_headers
1114
+ row = rows[0]
1115
+ expect(row).to be_a Hash
1116
+ expect(row['Date']).to eq first_data_row['Date']
1117
+ expect(row['Amount']).to eq first_data_row['Amount']
1118
+ expect(row['Code']).to eq first_data_row['Code']
1119
+ expect(row['Remark']).to eq first_data_row['Remark']
1120
+ expect(row['dummy']).to be_nil
1121
+ row = rows[13]
1122
+ expect(row).to be_a Hash
1123
+ expect(row['Date']).to eq data_row_13['Date']
1124
+ expect(row['Amount']).to eq data_row_13['Amount']
1125
+ expect(row['Code']).to eq data_row_13['Code']
1126
+ expect(row['Remark']).to eq data_row_13['Remark']
1127
+ expect(row['dummy']).to be_nil
1128
+ end
1129
+
1130
+ end
1131
+
1132
+ context 'not specified' do
1133
+
1134
+ let(:required_headers) {[]}
1135
+
1136
+ it 'opens correctly' do
1137
+ expect {ss}.not_to raise_error
1138
+ end
1139
+
1140
+ it 'contains expected headers' do
1141
+ required_headers.each do |header|
1142
+ expect(ss.headers).to include header
1143
+ end
1144
+ expect(ss.headers).to eq real_headers
1145
+ end
1146
+
1147
+ it 'each returns header and data rows' do
1148
+ expect(ss.each.count).to eq size_with_headers
1149
+ expect(ss.each.first).to eq header_row
1150
+ end
1151
+
1152
+ it '#shift returns Hash object' do
1153
+ row = ss.shift
1154
+ expect(row).to be_a Hash
1155
+ expect(row['Date']).to eq first_data_row['Date']
1156
+ expect(row['Amount']).to eq first_data_row['Amount']
1157
+ expect(row['Code']).to eq first_data_row['Code']
1158
+ expect(row['Remark']).to eq first_data_row['Remark']
1159
+ expect(row['dummy']).to be_nil
1160
+ end
1161
+
1162
+ it '#parse returns Array of Hash objects' do
1163
+ rows = ss.parse
1164
+ expect(rows).to be_a Array
1165
+ expect(rows.size).to eq size_without_headers
1166
+ row = rows[0]
1167
+ expect(row).to be_a Hash
1168
+ expect(row['Date']).to eq first_data_row['Date']
1169
+ expect(row['Amount']).to eq first_data_row['Amount']
1170
+ expect(row['Code']).to eq first_data_row['Code']
1171
+ expect(row['Remark']).to eq first_data_row['Remark']
1172
+ expect(row['dummy']).to be_nil
1173
+ row = rows[13]
1174
+ expect(row).to be_a Hash
1175
+ expect(row['Date']).to eq data_row_13['Date']
1176
+ expect(row['Amount']).to eq data_row_13['Amount']
1177
+ expect(row['Code']).to eq data_row_13['Code']
1178
+ expect(row['Remark']).to eq data_row_13['Remark']
1179
+ expect(row['dummy']).to be_nil
1180
+ end
1181
+
1182
+ end
1183
+
1184
+ context 'not well-formed' do
1185
+
1186
+ let(:required_headers) {%w'Date dummy1 Amount dummy2'}
1187
+
1188
+ it 'throws error when opened' do
1189
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["dummy1", "dummy2"].')
1190
+ end
1191
+ end
1192
+
1193
+ end
1194
+
1195
+ context 'blank columns without headers' do
1196
+ let(:file_name) {'test.xlsx|ExpensesBlankColumnsNoHeaders'}
1197
+
1198
+ context 'well-formed and strict' do
1199
+ let(:required_headers) {%w'Date Amount'}
1200
+
1201
+ it 'opens correctly' do
1202
+ expect {ss}.not_to raise_error
1203
+ end
1204
+
1205
+ it 'contains only required headers' do
1206
+ required_headers.each do |header|
1207
+ expect(ss.headers).to include header
1208
+ end
1209
+ expect(ss.headers).to eq required_headers
1210
+ end
1211
+
1212
+ it 'each returns header and data rows' do
1213
+ expect(ss.each.count).to eq size_with_headers
1214
+ expect(ss.each.first.keys).to eq required_headers
1215
+ end
1216
+
1217
+ it '#shift returns Hash object' do
1218
+ row = ss.shift
1219
+ expect(row).to be_a Hash
1220
+ expect(row['Date']).to eq first_data_row['Date']
1221
+ expect(row['Amount']).to eq first_data_row['Amount']
1222
+ expect(row['Code']).to be_nil
1223
+ expect(row['Remark']).to be_nil
1224
+ expect(row['dummy']).to be_nil
1225
+ end
1226
+
1227
+ it '#parse returns Array of Hash objects' do
1228
+ rows = ss.parse
1229
+ expect(rows).to be_a Array
1230
+ expect(rows.size).to eq size_without_headers
1231
+ row = rows[0]
1232
+ expect(row).to be_a Hash
1233
+ expect(row['Date']).to eq first_data_row['Date']
1234
+ expect(row['Amount']).to eq first_data_row['Amount']
1235
+ expect(row['Code']).to be_nil
1236
+ expect(row['Remark']).to be_nil
1237
+ expect(row['dummy']).to be_nil
1238
+ row = rows[13]
1239
+ expect(row).to be_a Hash
1240
+ expect(row['Date']).to eq data_row_13['Date']
1241
+ expect(row['Amount']).to eq data_row_13['Amount']
1242
+ expect(row['Code']).to be_nil
1243
+ expect(row['Remark']).to be_nil
1244
+ expect(row['dummy']).to be_nil
1245
+ end
1246
+
1247
+ end
1248
+
1249
+ context 'well-formed with optional headers' do
1250
+ let(:required_headers) {%w'Date Amount'}
1251
+ let(:optional_headers) {%w'Code'}
1252
+
1253
+ it 'opens correctly' do
1254
+ expect {ss}.not_to raise_error
1255
+ end
1256
+
1257
+ it 'contains required and optional headers' do
1258
+ required_headers.each do |header|
1259
+ expect(ss.headers).to include header
1260
+ end
1261
+ optional_headers.each do |header|
1262
+ expect(ss.headers).to include header
1263
+ end
1264
+ expect(ss.headers).to eq required_headers + optional_headers
1265
+ end
1266
+
1267
+ it 'each returns header and data rows' do
1268
+ expect(ss.each.count).to eq size_with_headers
1269
+ expect(ss.each.first.keys).to eq required_headers + optional_headers
1270
+ end
1271
+
1272
+ it '#shift returns Hash object' do
1273
+ row = ss.shift
1274
+ expect(row).to be_a Hash
1275
+ expect(row['Date']).to eq first_data_row['Date']
1276
+ expect(row['Amount']).to eq first_data_row['Amount']
1277
+ expect(row['Code']).to eq first_data_row['Code']
1278
+ expect(row['Remark']).to be_nil
1279
+ expect(row['dummy']).to be_nil
1280
+ end
1281
+
1282
+ it '#parse returns Array of Hash objects' do
1283
+ rows = ss.parse
1284
+ expect(rows).to be_a Array
1285
+ expect(rows.size).to eq size_without_headers
1286
+ row = rows[0]
1287
+ expect(row).to be_a Hash
1288
+ expect(row['Date']).to eq first_data_row['Date']
1289
+ expect(row['Amount']).to eq first_data_row['Amount']
1290
+ expect(row['Code']).to eq first_data_row['Code']
1291
+ expect(row['Remark']).to be_nil
1292
+ expect(row['dummy']).to be_nil
1293
+ row = rows[13]
1294
+ expect(row).to be_a Hash
1295
+ expect(row['Date']).to eq data_row_13['Date']
1296
+ expect(row['Amount']).to eq data_row_13['Amount']
1297
+ expect(row['Code']).to eq data_row_13['Code']
1298
+ expect(row['Remark']).to be_nil
1299
+ expect(row['dummy']).to be_nil
1300
+ end
1301
+
1302
+ end
1303
+
1304
+ context 'missing optional headers' do
1305
+
1306
+ let(:required_headers) {%w'Date Amount Code Remark'}
1307
+ let(:optional_headers) {%w'dummy'}
1308
+
1309
+ it 'opens correctly' do
1310
+ expect {ss}.not_to raise_error
1311
+ end
1312
+
1313
+ it 'contains only required headers' do
1314
+ required_headers.each do |header|
1315
+ expect(ss.headers).to include header
1316
+ end
1317
+ optional_headers.each do |header|
1318
+ expect(ss.headers).not_to include header
1319
+ end
1320
+ expect(ss.headers).to eq required_headers
1321
+ end
1322
+
1323
+ it 'each returns header and data rows' do
1324
+ expect(ss.each.count).to eq size_with_headers
1325
+ expect(ss.each.first.keys).to eq required_headers
1326
+ end
1327
+
1328
+ it '#shift returns Hash object' do
1329
+ row = ss.shift
1330
+ expect(row).to be_a Hash
1331
+ expect(row['Date']).to eq first_data_row['Date']
1332
+ expect(row['Amount']).to eq first_data_row['Amount']
1333
+ expect(row['Code']).to eq first_data_row['Code']
1334
+ expect(row['Remark']).to eq first_data_row['Remark']
1335
+ expect(row['dummy']).to be_nil
1336
+ end
1337
+
1338
+ it '#parse returns Array of Hash objects' do
1339
+ rows = ss.parse
1340
+ expect(rows).to be_a Array
1341
+ expect(rows.size).to eq size_without_headers
1342
+ row = rows[0]
1343
+ expect(row).to be_a Hash
1344
+ expect(row['Date']).to eq first_data_row['Date']
1345
+ expect(row['Amount']).to eq first_data_row['Amount']
1346
+ expect(row['Code']).to eq first_data_row['Code']
1347
+ expect(row['Remark']).to eq first_data_row['Remark']
1348
+ expect(row['dummy']).to be_nil
1349
+ row = rows[13]
1350
+ expect(row).to be_a Hash
1351
+ expect(row['Date']).to eq data_row_13['Date']
1352
+ expect(row['Amount']).to eq data_row_13['Amount']
1353
+ expect(row['Code']).to eq data_row_13['Code']
1354
+ expect(row['Remark']).to eq data_row_13['Remark']
1355
+ expect(row['dummy']).to be_nil
1356
+ end
1357
+
1358
+ end
1359
+
1360
+ context 'missing required header' do
1361
+ let(:required_headers) {%w'Date Amount Code Remark dummy'}
1362
+
1363
+ it 'throws error when opened' do
1364
+ expect {ss}.to raise_error(RuntimeError, 'Sheet does not contain enough columns.')
1365
+ end
1366
+
1367
+ end
1368
+
1369
+ end
1370
+
1371
+ context 'blank row and columns with headers' do
1372
+ let(:file_name) {'test.xlsx|ExpensesBlankRowsAndColumns'}
1373
+
1374
+ context 'well-formed' do
1375
+
1376
+ let(:required_headers) {%w'Date Amount'}
1377
+
1378
+ it 'opens correctly' do
1379
+ expect {ss}.not_to raise_error
1380
+ end
1381
+
1382
+ it 'contains expected headers' do
1383
+ required_headers.each do |header|
1384
+ expect(ss.headers).to include header
1385
+ end
1386
+ expect(ss.headers).to eq real_headers
1387
+ end
1388
+
1389
+ it 'each returns header and data rows' do
1390
+ expect(ss.each.count).to eq size_with_headers
1391
+ expect(ss.each.first).to eq header_row
1392
+ end
1393
+
1394
+ it '#shift returns Hash object' do
1395
+ row = ss.shift
1396
+ expect(row).to be_a Hash
1397
+ expect(row['Date']).to eq first_data_row['Date']
1398
+ expect(row['Amount']).to eq first_data_row['Amount']
1399
+ expect(row['Code']).to eq first_data_row['Code']
1400
+ expect(row['Remark']).to eq first_data_row['Remark']
1401
+ expect(row['dummy']).to be_nil
1402
+ end
1403
+
1404
+ it '#parse returns Array of Hash objects' do
1405
+ rows = ss.parse
1406
+ expect(rows).to be_a Array
1407
+ expect(rows.size).to eq size_without_headers
1408
+ row = rows[0]
1409
+ expect(row).to be_a Hash
1410
+ expect(row['Date']).to eq first_data_row['Date']
1411
+ expect(row['Amount']).to eq first_data_row['Amount']
1412
+ expect(row['Code']).to eq first_data_row['Code']
1413
+ expect(row['Remark']).to eq first_data_row['Remark']
1414
+ expect(row['dummy']).to be_nil
1415
+ row = rows[13]
1416
+ expect(row).to be_a Hash
1417
+ expect(row['Date']).to eq data_row_13['Date']
1418
+ expect(row['Amount']).to eq data_row_13['Amount']
1419
+ expect(row['Code']).to eq data_row_13['Code']
1420
+ expect(row['Remark']).to eq data_row_13['Remark']
1421
+ expect(row['dummy']).to be_nil
1422
+ end
1423
+
1424
+ end
1425
+
1426
+ context 'not specified' do
1427
+
1428
+ let(:required_headers) {[]}
1429
+
1430
+ it 'opens correctly' do
1431
+ expect {ss}.not_to raise_error
1432
+ end
1433
+
1434
+ it 'contains expected headers' do
1435
+ required_headers.each do |header|
1436
+ expect(ss.headers).to include header
1437
+ end
1438
+ expect(ss.headers).to eq real_headers
1439
+ end
1440
+
1441
+ it 'each returns header and data rows' do
1442
+ expect(ss.each.count).to eq size_with_headers
1443
+ expect(ss.each.first).to eq header_row
1444
+ end
1445
+
1446
+ it '#shift returns Hash object' do
1447
+ row = ss.shift
1448
+ expect(row).to be_a Hash
1449
+ expect(row['Date']).to eq first_data_row['Date']
1450
+ expect(row['Amount']).to eq first_data_row['Amount']
1451
+ expect(row['Code']).to eq first_data_row['Code']
1452
+ expect(row['Remark']).to eq first_data_row['Remark']
1453
+ expect(row['dummy']).to be_nil
1454
+ end
1455
+
1456
+ it '#parse returns Array of Hash objects' do
1457
+ rows = ss.parse
1458
+ expect(rows).to be_a Array
1459
+ expect(rows.size).to eq size_without_headers
1460
+ row = rows[0]
1461
+ expect(row).to be_a Hash
1462
+ expect(row['Date']).to eq first_data_row['Date']
1463
+ expect(row['Amount']).to eq first_data_row['Amount']
1464
+ expect(row['Code']).to eq first_data_row['Code']
1465
+ expect(row['Remark']).to eq first_data_row['Remark']
1466
+ expect(row['dummy']).to be_nil
1467
+ row = rows[13]
1468
+ expect(row).to be_a Hash
1469
+ expect(row['Date']).to eq data_row_13['Date']
1470
+ expect(row['Amount']).to eq data_row_13['Amount']
1471
+ expect(row['Code']).to eq data_row_13['Code']
1472
+ expect(row['Remark']).to eq data_row_13['Remark']
1473
+ expect(row['dummy']).to be_nil
1474
+ end
1475
+
1476
+ end
1477
+
1478
+ context 'not well-formed' do
1479
+
1480
+ let(:required_headers) {%w'Date dummy1 Amount dummy2'}
1481
+
1482
+ it 'throws error when opened' do
1483
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["dummy1", "dummy2"].')
1484
+ end
1485
+ end
1486
+
1487
+ end
1488
+
1489
+ context 'blank row and columns without headers' do
1490
+ let(:file_name) {'test.xlsx|ExpensesBlankRowsAndColumnsNoH'}
1491
+
1492
+ context 'well-formed and strict' do
1493
+ let(:required_headers) {%w'Date Amount'}
1494
+
1495
+ it 'opens correctly' do
1496
+ expect {ss}.not_to raise_error
1497
+ end
1498
+
1499
+ it 'contains only required headers' do
1500
+ required_headers.each do |header|
1501
+ expect(ss.headers).to include header
1502
+ end
1503
+ expect(ss.headers).to eq required_headers
1504
+ end
1505
+
1506
+ it 'each returns header and data rows' do
1507
+ expect(ss.each.count).to eq size_with_headers
1508
+ expect(ss.each.first.keys).to eq required_headers
1509
+ end
1510
+
1511
+ it '#shift returns Hash object' do
1512
+ row = ss.shift
1513
+ expect(row).to be_a Hash
1514
+ expect(row['Date']).to eq first_data_row['Date']
1515
+ expect(row['Amount']).to eq first_data_row['Amount']
1516
+ expect(row['Code']).to be_nil
1517
+ expect(row['Remark']).to be_nil
1518
+ expect(row['dummy']).to be_nil
1519
+ end
1520
+
1521
+ it '#parse returns Array of Hash objects' do
1522
+ rows = ss.parse
1523
+ expect(rows).to be_a Array
1524
+ expect(rows.size).to eq size_without_headers
1525
+ row = rows[0]
1526
+ expect(row).to be_a Hash
1527
+ expect(row['Date']).to eq first_data_row['Date']
1528
+ expect(row['Amount']).to eq first_data_row['Amount']
1529
+ expect(row['Code']).to be_nil
1530
+ expect(row['Remark']).to be_nil
1531
+ expect(row['dummy']).to be_nil
1532
+ row = rows[13]
1533
+ expect(row).to be_a Hash
1534
+ expect(row['Date']).to eq data_row_13['Date']
1535
+ expect(row['Amount']).to eq data_row_13['Amount']
1536
+ expect(row['Code']).to be_nil
1537
+ expect(row['Remark']).to be_nil
1538
+ expect(row['dummy']).to be_nil
1539
+ end
1540
+
1541
+ end
1542
+
1543
+ context 'well-formed with optional headers' do
1544
+ let(:required_headers) {%w'Date Amount'}
1545
+ let(:optional_headers) {%w'Code'}
1546
+
1547
+ it 'opens correctly' do
1548
+ expect {ss}.not_to raise_error
1549
+ end
1550
+
1551
+ it 'contains required and optional headers' do
1552
+ required_headers.each do |header|
1553
+ expect(ss.headers).to include header
1554
+ end
1555
+ optional_headers.each do |header|
1556
+ expect(ss.headers).to include header
1557
+ end
1558
+ expect(ss.headers).to eq required_headers + optional_headers
1559
+ end
1560
+
1561
+ it 'each returns header and data rows' do
1562
+ expect(ss.each.count).to eq size_with_headers
1563
+ expect(ss.each.first.keys).to eq required_headers + optional_headers
1564
+ end
1565
+
1566
+ it '#shift returns Hash object' do
1567
+ row = ss.shift
1568
+ expect(row).to be_a Hash
1569
+ expect(row['Date']).to eq first_data_row['Date']
1570
+ expect(row['Amount']).to eq first_data_row['Amount']
1571
+ expect(row['Code']).to eq first_data_row['Code']
1572
+ expect(row['Remark']).to be_nil
1573
+ expect(row['dummy']).to be_nil
1574
+ end
1575
+
1576
+ it '#parse returns Array of Hash objects' do
1577
+ rows = ss.parse
1578
+ expect(rows).to be_a Array
1579
+ expect(rows.size).to eq size_without_headers
1580
+ row = rows[0]
1581
+ expect(row).to be_a Hash
1582
+ expect(row['Date']).to eq first_data_row['Date']
1583
+ expect(row['Amount']).to eq first_data_row['Amount']
1584
+ expect(row['Code']).to eq first_data_row['Code']
1585
+ expect(row['Remark']).to be_nil
1586
+ expect(row['dummy']).to be_nil
1587
+ row = rows[13]
1588
+ expect(row).to be_a Hash
1589
+ expect(row['Date']).to eq data_row_13['Date']
1590
+ expect(row['Amount']).to eq data_row_13['Amount']
1591
+ expect(row['Code']).to eq data_row_13['Code']
1592
+ expect(row['Remark']).to be_nil
1593
+ expect(row['dummy']).to be_nil
1594
+ end
1595
+
1596
+ end
1597
+
1598
+ context 'missing optional headers' do
1599
+
1600
+ let(:required_headers) {%w'Date Amount Code Remark'}
1601
+ let(:optional_headers) {%w'dummy'}
1602
+
1603
+ it 'opens correctly' do
1604
+ expect {ss}.not_to raise_error
1605
+ end
1606
+
1607
+ it 'contains only required headers' do
1608
+ required_headers.each do |header|
1609
+ expect(ss.headers).to include header
1610
+ end
1611
+ optional_headers.each do |header|
1612
+ expect(ss.headers).not_to include header
1613
+ end
1614
+ expect(ss.headers).to eq required_headers
1615
+ end
1616
+
1617
+ it 'each returns header and data rows' do
1618
+ expect(ss.each.count).to eq size_with_headers
1619
+ expect(ss.each.first.keys).to eq required_headers
1620
+ end
1621
+
1622
+ it '#shift returns Hash object' do
1623
+ row = ss.shift
1624
+ expect(row).to be_a Hash
1625
+ expect(row['Date']).to eq first_data_row['Date']
1626
+ expect(row['Amount']).to eq first_data_row['Amount']
1627
+ expect(row['Code']).to eq first_data_row['Code']
1628
+ expect(row['Remark']).to eq first_data_row['Remark']
1629
+ expect(row['dummy']).to be_nil
1630
+ end
1631
+
1632
+ it '#parse returns Array of Hash objects' do
1633
+ rows = ss.parse
1634
+ expect(rows).to be_a Array
1635
+ expect(rows.size).to eq size_without_headers
1636
+ row = rows[0]
1637
+ expect(row).to be_a Hash
1638
+ expect(row['Date']).to eq first_data_row['Date']
1639
+ expect(row['Amount']).to eq first_data_row['Amount']
1640
+ expect(row['Code']).to eq first_data_row['Code']
1641
+ expect(row['Remark']).to eq first_data_row['Remark']
1642
+ expect(row['dummy']).to be_nil
1643
+ row = rows[13]
1644
+ expect(row).to be_a Hash
1645
+ expect(row['Date']).to eq data_row_13['Date']
1646
+ expect(row['Amount']).to eq data_row_13['Amount']
1647
+ expect(row['Code']).to eq data_row_13['Code']
1648
+ expect(row['Remark']).to eq data_row_13['Remark']
1649
+ expect(row['dummy']).to be_nil
1650
+ end
1651
+
1652
+ end
1653
+
1654
+ context 'missing required header' do
1655
+ let(:required_headers) {%w'Date Amount Code Remark dummy'}
1656
+
1657
+ it 'throws error when opened' do
1658
+ expect {ss}.to raise_error(RuntimeError, 'Sheet does not contain enough columns.')
1659
+ end
1660
+
1661
+ end
1662
+
1663
+ end
1664
+
1665
+ context 'Only headers' do
1666
+ let(:file_name) {'test.xlsx|ExpensesOnlyHeaders'}
1667
+
1668
+ context 'well-formed' do
1669
+
1670
+ let(:required_headers) {%w'Date Amount'}
1671
+
1672
+ it 'opens correctly' do
1673
+ expect {ss}.not_to raise_error
1674
+ end
1675
+
1676
+ it 'contains expected headers' do
1677
+ required_headers.each do |header|
1678
+ expect(ss.headers).to include header
1679
+ end
1680
+ expect(ss.headers).to eq real_headers
1681
+ end
1682
+
1683
+ it 'each returns header and data rows' do
1684
+ expect(ss.each.count).to be 1
1685
+ expect(ss.each.first).to eq header_row
1686
+ end
1687
+
1688
+ it '#shift returns nil' do
1689
+ row = ss.shift
1690
+ expect(row).to be_nil
1691
+ end
1692
+
1693
+ it '#parse returns empty Array of Hash objects' do
1694
+ rows = ss.parse
1695
+ expect(rows).to be_a Array
1696
+ # noinspection RubyResolve
1697
+ expect(rows).to be_empty
1698
+ expect(rows.size).to eq 0
1699
+ end
1700
+
1701
+ end
1702
+
1703
+ context 'not specified' do
1704
+
1705
+ let(:required_headers) {[]}
1706
+
1707
+ it 'opens correctly' do
1708
+ expect {ss}.not_to raise_error
1709
+ end
1710
+
1711
+ it 'contains expected headers' do
1712
+ required_headers.each do |header|
1713
+ expect(ss.headers).to include header
1714
+ end
1715
+ expect(ss.headers).to eq %w'Date Amount Code Remark'
1716
+ end
1717
+
1718
+ it '#shift returns nil' do
1719
+ row = ss.shift
1720
+ expect(row).to be_nil
1721
+ end
1722
+
1723
+ it '#parse returns empty Array of Hash objects' do
1724
+ rows = ss.parse
1725
+ expect(rows).to be_a Array
1726
+ # noinspection RubyResolve
1727
+ expect(rows).to be_empty
1728
+ expect(rows.size).to eq 0
1729
+ end
1730
+
1731
+ end
1732
+
1733
+ context 'not well-formed' do
1734
+
1735
+ let(:required_headers) {%w'Date dummy1 Amount dummy2'}
1736
+
1737
+ it 'throws error when opened' do
1738
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["dummy1", "dummy2"].')
1739
+ end
1740
+ end
1741
+
1742
+ end
1743
+
1744
+ context 'Only headers with blank rows and columns' do
1745
+ let(:file_name) {'test.xlsx|ExpensesOnlyHeadersBlankRowsAndColumns'}
1746
+
1747
+ context 'well-formed' do
1748
+
1749
+ let(:required_headers) {%w'Date Amount'}
1750
+
1751
+ it 'opens correctly' do
1752
+ expect {ss}.not_to raise_error
1753
+ end
1754
+
1755
+ it 'contains expected headers' do
1756
+ required_headers.each do |header|
1757
+ expect(ss.headers).to include header
1758
+ end
1759
+ expect(ss.headers).to eq %w'Date Amount Code Remark'
1760
+ end
1761
+
1762
+ it '#shift returns nil' do
1763
+ row = ss.shift
1764
+ expect(row).to be_nil
1765
+ end
1766
+
1767
+ it '#parse returns empty Array of Hash objects' do
1768
+ rows = ss.parse
1769
+ expect(rows).to be_a Array
1770
+ # noinspection RubyResolve
1771
+ expect(rows).to be_empty
1772
+ expect(rows.size).to eq 0
1773
+ end
1774
+
1775
+ end
1776
+
1777
+ context 'not specified' do
1778
+
1779
+ let(:required_headers) {[]}
1780
+
1781
+ it 'opens correctly' do
1782
+ expect {ss}.not_to raise_error
1783
+ end
1784
+
1785
+ it 'contains expected headers' do
1786
+ required_headers.each do |header|
1787
+ expect(ss.headers).to include header
1788
+ end
1789
+ expect(ss.headers).to eq %w'Date Amount Code Remark'
1790
+ end
1791
+
1792
+ it '#shift returns nil' do
1793
+ row = ss.shift
1794
+ expect(row).to be_nil
1795
+ end
1796
+
1797
+ it '#parse returns empty Array of Hash objects' do
1798
+ rows = ss.parse
1799
+ expect(rows).to be_a Array
1800
+ # noinspection RubyResolve
1801
+ expect(rows).to be_empty
1802
+ expect(rows.size).to eq 0
1803
+ end
1804
+
1805
+ end
1806
+
1807
+ context 'not well-formed' do
1808
+
1809
+ let(:required_headers) {%w'Date dummy1 Amount dummy2'}
1810
+
1811
+ it 'throws error when opened' do
1812
+ expect {ss}.to raise_error(RuntimeError, 'Headers not found: ["dummy1", "dummy2"].')
1813
+ end
1814
+ end
1815
+
1816
+ end
1817
+
1818
+ end
1819
+
1820
+ end