roo 2.3.0 → 2.10.1

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 (95) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +17 -0
  3. data/.github/issue_template.md +16 -0
  4. data/.github/pull_request_template.md +14 -0
  5. data/.github/workflows/pull-request.yml +15 -0
  6. data/.github/workflows/ruby.yml +34 -0
  7. data/.gitignore +4 -0
  8. data/.rubocop.yml +186 -0
  9. data/CHANGELOG.md +148 -0
  10. data/Gemfile +4 -4
  11. data/LICENSE +2 -0
  12. data/README.md +84 -27
  13. data/Rakefile +1 -1
  14. data/lib/roo/base.rb +111 -237
  15. data/lib/roo/constants.rb +5 -3
  16. data/lib/roo/csv.rb +106 -85
  17. data/lib/roo/errors.rb +2 -0
  18. data/lib/roo/excelx/cell/base.rb +26 -12
  19. data/lib/roo/excelx/cell/boolean.rb +9 -6
  20. data/lib/roo/excelx/cell/date.rb +7 -7
  21. data/lib/roo/excelx/cell/datetime.rb +50 -44
  22. data/lib/roo/excelx/cell/empty.rb +3 -2
  23. data/lib/roo/excelx/cell/number.rb +60 -47
  24. data/lib/roo/excelx/cell/string.rb +3 -3
  25. data/lib/roo/excelx/cell/time.rb +17 -16
  26. data/lib/roo/excelx/cell.rb +11 -7
  27. data/lib/roo/excelx/comments.rb +3 -3
  28. data/lib/roo/excelx/coordinate.rb +11 -4
  29. data/lib/roo/excelx/extractor.rb +20 -3
  30. data/lib/roo/excelx/format.rb +38 -31
  31. data/lib/roo/excelx/images.rb +26 -0
  32. data/lib/roo/excelx/relationships.rb +12 -4
  33. data/lib/roo/excelx/shared.rb +10 -3
  34. data/lib/roo/excelx/shared_strings.rb +113 -9
  35. data/lib/roo/excelx/sheet.rb +49 -10
  36. data/lib/roo/excelx/sheet_doc.rb +101 -48
  37. data/lib/roo/excelx/styles.rb +4 -4
  38. data/lib/roo/excelx/workbook.rb +8 -3
  39. data/lib/roo/excelx.rb +85 -42
  40. data/lib/roo/formatters/base.rb +15 -0
  41. data/lib/roo/formatters/csv.rb +84 -0
  42. data/lib/roo/formatters/matrix.rb +23 -0
  43. data/lib/roo/formatters/xml.rb +31 -0
  44. data/lib/roo/formatters/yaml.rb +40 -0
  45. data/lib/roo/helpers/default_attr_reader.rb +20 -0
  46. data/lib/roo/helpers/weak_instance_cache.rb +41 -0
  47. data/lib/roo/open_office.rb +41 -27
  48. data/lib/roo/spreadsheet.rb +8 -2
  49. data/lib/roo/tempdir.rb +24 -0
  50. data/lib/roo/utils.rb +76 -26
  51. data/lib/roo/version.rb +1 -1
  52. data/lib/roo.rb +5 -0
  53. data/roo.gemspec +22 -12
  54. data/spec/lib/roo/base_spec.rb +65 -3
  55. data/spec/lib/roo/csv_spec.rb +19 -0
  56. data/spec/lib/roo/excelx/cell/time_spec.rb +15 -0
  57. data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
  58. data/spec/lib/roo/excelx/sheet_doc_spec.rb +11 -0
  59. data/spec/lib/roo/excelx_spec.rb +237 -5
  60. data/spec/lib/roo/openoffice_spec.rb +2 -2
  61. data/spec/lib/roo/spreadsheet_spec.rb +1 -1
  62. data/spec/lib/roo/strict_spec.rb +43 -0
  63. data/spec/lib/roo/utils_spec.rb +22 -9
  64. data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
  65. data/spec/lib/roo_spec.rb +0 -0
  66. data/spec/spec_helper.rb +2 -7
  67. data/test/excelx/cell/test_attr_reader_default.rb +72 -0
  68. data/test/excelx/cell/test_base.rb +6 -2
  69. data/test/excelx/cell/test_boolean.rb +1 -3
  70. data/test/excelx/cell/test_date.rb +1 -6
  71. data/test/excelx/cell/test_datetime.rb +7 -10
  72. data/test/excelx/cell/test_empty.rb +12 -2
  73. data/test/excelx/cell/test_number.rb +28 -4
  74. data/test/excelx/cell/test_string.rb +21 -3
  75. data/test/excelx/cell/test_time.rb +7 -10
  76. data/test/excelx/test_coordinate.rb +51 -0
  77. data/test/formatters/test_csv.rb +136 -0
  78. data/test/formatters/test_matrix.rb +76 -0
  79. data/test/formatters/test_xml.rb +78 -0
  80. data/test/formatters/test_yaml.rb +20 -0
  81. data/test/helpers/test_accessing_files.rb +81 -0
  82. data/test/helpers/test_comments.rb +43 -0
  83. data/test/helpers/test_formulas.rb +9 -0
  84. data/test/helpers/test_labels.rb +103 -0
  85. data/test/helpers/test_sheets.rb +55 -0
  86. data/test/helpers/test_styles.rb +62 -0
  87. data/test/roo/test_base.rb +182 -0
  88. data/test/roo/test_csv.rb +88 -0
  89. data/test/roo/test_excelx.rb +360 -0
  90. data/test/roo/test_libre_office.rb +9 -0
  91. data/test/roo/test_open_office.rb +289 -0
  92. data/test/test_helper.rb +129 -14
  93. data/test/test_roo.rb +60 -1765
  94. metadata +91 -21
  95. data/.travis.yml +0 -14
@@ -127,10 +127,22 @@ describe Roo::Base do
127
127
  end
128
128
  end
129
129
 
130
- describe '#row' do
131
- it 'should return the specified row' do
130
+ describe "#row" do
131
+ it "should return the specified row" do
132
132
  expect(spreadsheet.row(12)).to eq([41.0, 42.0, 43.0, 44.0, 45.0, nil, nil])
133
- expect(spreadsheet.row(16)).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil])
133
+ expect(spreadsheet.row(16)).to eq([nil, '"Hello world!"', "forty-three", "forty-four", "forty-five", nil, nil])
134
+ end
135
+
136
+ it "should return the specified row if default_sheet is set by a string" do
137
+ spreadsheet.default_sheet = "my_sheet"
138
+ expect(spreadsheet.row(12)).to eq([41.0, 42.0, 43.0, 44.0, 45.0, nil, nil])
139
+ expect(spreadsheet.row(16)).to eq([nil, '"Hello world!"', "forty-three", "forty-four", "forty-five", nil, nil])
140
+ end
141
+
142
+ it "should return the specified row if default_sheet is set by an integer" do
143
+ spreadsheet.default_sheet = 0
144
+ expect(spreadsheet.row(12)).to eq([41.0, 42.0, 43.0, 44.0, 45.0, nil, nil])
145
+ expect(spreadsheet.row(16)).to eq([nil, '"Hello world!"', "forty-three", "forty-four", "forty-five", nil, nil])
134
146
  end
135
147
  end
136
148
 
@@ -146,6 +158,11 @@ describe Roo::Base do
146
158
  expect { spreadsheet.row_with([/Missing Header/]) }.to \
147
159
  raise_error(Roo::HeaderRowNotFoundError)
148
160
  end
161
+
162
+ it 'returns missing headers' do
163
+ expect { spreadsheet.row_with([/Header/, /Missing Header 1/, /Missing Header 2/]) }.to \
164
+ raise_error(Roo::HeaderRowNotFoundError, '[/Missing Header 1/, /Missing Header 2/]')
165
+ end
149
166
  end
150
167
  end
151
168
 
@@ -165,6 +182,26 @@ describe Roo::Base do
165
182
  end
166
183
  end
167
184
 
185
+ describe '#each_with_pagename' do
186
+ context 'when block given' do
187
+ it 'iterate with sheet and sheet_name' do
188
+ sheet_names = []
189
+ spreadsheet.each_with_pagename do |sheet_name, sheet|
190
+ sheet_names << sheet_name
191
+ end
192
+ expect(sheet_names).to eq ['my_sheet', 'blank sheet']
193
+ end
194
+ end
195
+
196
+ context 'when called without block' do
197
+ it 'should return an enumerator with all the rows' do
198
+ each_with_pagename = spreadsheet.each_with_pagename
199
+ expect(each_with_pagename).to be_a(Enumerator)
200
+ expect(each_with_pagename.to_a.last).to eq([spreadsheet.default_sheet, spreadsheet])
201
+ end
202
+ end
203
+ end
204
+
168
205
  describe '#each' do
169
206
  it 'should return an enumerator with all the rows' do
170
207
  each = spreadsheet.each
@@ -173,6 +210,31 @@ describe Roo::Base do
173
210
  end
174
211
  end
175
212
 
213
+ describe "#default_sheet=" do
214
+ it "should correctly set the default sheet if passed a string" do
215
+ spreadsheet.default_sheet = "my_sheet"
216
+ expect(spreadsheet.default_sheet).to eq("my_sheet")
217
+ end
218
+
219
+ it "should correctly set the default sheet if passed an integer" do
220
+ spreadsheet.default_sheet = 0
221
+ expect(spreadsheet.default_sheet).to eq("my_sheet")
222
+ end
223
+
224
+ it "should correctly set the default sheet if passed an integer for the second sheet" do
225
+ spreadsheet.default_sheet = 1
226
+ expect(spreadsheet.default_sheet).to eq("blank sheet")
227
+ end
228
+
229
+ it "should raise an error if passed a sheet that does not exist as an integer" do
230
+ expect { spreadsheet.default_sheet = 10 }.to raise_error RangeError
231
+ end
232
+
233
+ it "should raise an error if passed a sheet that does not exist as a string" do
234
+ expect { spreadsheet.default_sheet = "does_not_exist" }.to raise_error RangeError
235
+ end
236
+ end
237
+
176
238
  describe '#to_yaml' do
177
239
  it 'should convert the spreadsheet to yaml' do
178
240
  expect(spreadsheet.to_yaml({}, 5, 1, 5, 1)).to eq("--- \n" + yaml_entry(5, 1, 'date', '1961-11-21'))
@@ -10,6 +10,13 @@ describe Roo::CSV do
10
10
  end
11
11
  end
12
12
 
13
+ describe '.new with stream' do
14
+ let(:csv) { Roo::CSV.new(File.read(path)) }
15
+ it 'creates an instance' do
16
+ expect(csv).to be_a(Roo::CSV)
17
+ end
18
+ end
19
+
13
20
  describe '#parse' do
14
21
  subject do
15
22
  csv.parse(options)
@@ -59,4 +66,16 @@ describe Roo::CSV do
59
66
  end
60
67
  end
61
68
  end
69
+
70
+ describe '#set_value' do
71
+ it 'returns the cell value' do
72
+ expect(csv.set_value('A', 1, 'some-value', nil)).to eq('some-value')
73
+ end
74
+ end
75
+
76
+ describe '#set_type' do
77
+ it 'returns the cell type' do
78
+ expect(csv.set_type('A', 1, 'some-type', nil)).to eq('some-type')
79
+ end
80
+ end
62
81
  end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Roo::Excelx::Cell::Time do
4
+ it "should set the cell value to the correct number of seconds" do
5
+ value = 0.05513888888888888 # '1:19:24'
6
+ excelx_type = [:numeric_or_formula, "h:mm:ss"]
7
+ base_timestamp = Date.new(1899, 12, 30).to_time.to_i
8
+ time_cell = Roo::Excelx::Cell::Time.new(value, nil, excelx_type, 1, nil, base_timestamp, nil)
9
+ expect(time_cell.value).to eq(1*60*60 + 19*60 + 24) # '1:19:24' in seconds
10
+ # use case from https://github.com/roo-rb/roo/issues/310
11
+ value = 0.523761574074074 # '12:34:13' in seconds
12
+ time_cell = Roo::Excelx::Cell::Time.new(value, nil, excelx_type, 1, nil, base_timestamp, nil)
13
+ expect(time_cell.value).to eq(12*60*60 + 34*60 + 13) # 12:34:13 in seconds
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Roo::Excelx::Relationships do
6
+ subject(:relationships) { Roo::Excelx::Relationships.new Roo::Excelx.new(path).rels_files[0] }
7
+
8
+ describe "#include_type?" do
9
+ [
10
+ ["with hyperlink type", "test/files/link.xlsx", true, false],
11
+ ["with nil path", "test/files/Bibelbund.xlsx", false, false],
12
+ ["with comments type", "test/files/comments-google.xlsx", false, true],
13
+ ].each do |context_desc, file_path, hyperlink_value, comments_value|
14
+ context context_desc do
15
+ let(:path) { file_path }
16
+
17
+ it "should return #{hyperlink_value} for hyperlink" do
18
+ expect(subject.include_type?("hyperlink")).to be hyperlink_value
19
+ end
20
+
21
+ it "should return #{hyperlink_value} for link" do
22
+ expect(subject.include_type?("link")).to be hyperlink_value
23
+ end
24
+
25
+ it "should return false for hypelink" do
26
+ expect(subject.include_type?("hypelink")).to be false
27
+ end
28
+
29
+ it "should return false for coment" do
30
+ expect(subject.include_type?("coment")).to be false
31
+ end
32
+
33
+ it "should return #{comments_value} for comments" do
34
+ expect(subject.include_type?("comments")).to be comments_value
35
+ end
36
+
37
+ it "should return #{comments_value} for comment" do
38
+ expect(subject.include_type?("comment")).to be comments_value
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Roo::Excelx::SheetDoc do
6
+ subject(:blank_children) { Roo::Excelx.new("test/files/blank_children.xlsx") }
7
+
8
+ example "#last_row" do
9
+ expect(subject.last_row).to eq 3
10
+ end
11
+ end
@@ -6,6 +6,18 @@ describe Roo::Excelx do
6
6
  Roo::Excelx.new(path)
7
7
  end
8
8
 
9
+ describe 'Constants' do
10
+ describe 'ERROR_VALUES' do
11
+ it 'returns all possible errorr values' do
12
+ expect(described_class::ERROR_VALUES).to eq(%w(#N/A #REF! #NAME? #DIV/0! #NULL! #VALUE! #NUM!).to_set)
13
+ end
14
+
15
+ it 'is a set' do
16
+ expect(described_class::ERROR_VALUES).to be_an_instance_of(Set)
17
+ end
18
+ end
19
+ end
20
+
9
21
  describe '.new' do
10
22
  let(:path) { 'test/files/numeric-link.xlsx' }
11
23
 
@@ -44,7 +56,6 @@ describe Roo::Excelx do
44
56
  expect(subject).to be_a(Roo::Excelx)
45
57
  end
46
58
  end
47
-
48
59
  end
49
60
 
50
61
  describe '#cell' do
@@ -75,6 +86,14 @@ describe Roo::Excelx do
75
86
  end
76
87
  end
77
88
 
89
+ describe 'for a workbook with hidden sheets' do
90
+ let(:path) { 'test/files/hidden_sheets.xlsx' }
91
+
92
+ it 'returns the cell contents from the visible sheet' do
93
+ expect(Roo::Excelx.new(path, only_visible_sheets: true).cell('A', 1)).to eq "visible sheet 1"
94
+ end
95
+ end
96
+
78
97
  describe '#parse' do
79
98
  let(:path) { 'test/files/numeric-link.xlsx' }
80
99
 
@@ -140,6 +159,22 @@ describe Roo::Excelx do
140
159
  it 'returns the expected result' do
141
160
  expect(subject.sheet_for("Tabelle1").instance_variable_get("@name")).to eq "Tabelle1"
142
161
  end
162
+
163
+ it 'returns the expected result when passed a number' do
164
+ expect(subject.sheet_for(0).instance_variable_get("@name")).to eq "Tabelle1"
165
+ end
166
+
167
+ it 'returns the expected result when passed a number that is not the first sheet' do
168
+ expect(subject.sheet_for(1).instance_variable_get("@name")).to eq "Name of Sheet 2"
169
+ end
170
+
171
+ it "should raise an error if passed a sheet that does not exist as an integer" do
172
+ expect { subject.sheet_for(10) }.to raise_error RangeError
173
+ end
174
+
175
+ it "should raise an error if passed a sheet that does not exist as a string" do
176
+ expect { subject.sheet_for("does_not_exist") }.to raise_error RangeError
177
+ end
143
178
  end
144
179
 
145
180
  describe '#row' do
@@ -283,6 +318,52 @@ describe Roo::Excelx do
283
318
  end
284
319
  end
285
320
 
321
+ describe '#formatted_value' do
322
+ context 'contains zero-padded numbers' do
323
+ let(:path) { 'test/files/zero-padded-number.xlsx' }
324
+
325
+ it 'returns a zero-padded number' do
326
+ expect(subject.formatted_value(4, 1)).to eq '05010'
327
+ end
328
+ end
329
+
330
+ context 'contains US currency' do
331
+ let(:path) { 'test/files/currency-us.xlsx' }
332
+
333
+ it 'returns a zero-padded number' do
334
+ expect(subject.formatted_value(4, 1)).to eq '$20.51'
335
+ end
336
+ end
337
+
338
+ context 'contains euro currency' do
339
+ let(:path) { 'test/files/currency-euro.xlsx' }
340
+
341
+ it 'returns a zero-padded number' do
342
+ expect(subject.formatted_value(4, 1)).to eq '€20.51'
343
+ end
344
+ end
345
+
346
+ context 'contains uk currency' do
347
+ let(:path) { 'test/files/currency-uk.xlsx' }
348
+
349
+ it 'returns a zero-padded number' do
350
+ expect(subject.formatted_value(4, 1)).to eq '£20.51'
351
+ end
352
+ end
353
+ end
354
+
355
+ describe '#row' do
356
+ context 'integers with leading zero'
357
+ let(:path) { 'test/files/number_with_zero_prefix.xlsx' }
358
+
359
+ it 'returns base 10 integer' do
360
+ (1..50).each do |row_index|
361
+ range_start = (row_index - 1) * 20 + 1
362
+ expect(subject.row(row_index)).to eq (range_start..(range_start+19)).to_a
363
+ end
364
+ end
365
+ end
366
+
286
367
  describe '#excelx_format' do
287
368
  let(:path) { 'test/files/style.xlsx' }
288
369
 
@@ -330,14 +411,50 @@ describe Roo::Excelx do
330
411
  expect(subject.hyperlink?(1, 1)).to eq true
331
412
  expect(subject.hyperlink?(1, 2)).to eq false
332
413
  end
414
+
415
+ context 'defined on cell range' do
416
+ let(:path) { 'test/files/cell-range-link.xlsx' }
417
+
418
+ it 'returns the expected result' do
419
+ [[false]*3, *[[true, true, false]]*4, [false]*3].each.with_index(1) do |row, row_index|
420
+ row.each.with_index(1) do |value, col_index|
421
+ expect(subject.hyperlink?(row_index, col_index)).to eq(value)
422
+ end
423
+ end
424
+ end
425
+ end
333
426
  end
334
427
 
335
428
  describe '#hyperlink' do
336
- let(:path) { 'test/files/link.xlsx' }
429
+ context 'defined on cell range' do
430
+ let(:path) { 'test/files/cell-range-link.xlsx' }
337
431
 
338
- it 'returns the expected result' do
339
- expect(subject.hyperlink(1, 1)).to eq "http://www.google.com"
340
- expect(subject.hyperlink(1, 2)).to eq nil
432
+ it 'returns the expected result' do
433
+ link = "http://www.google.com"
434
+ [[nil]*3, *[[link, link, nil]]*4, [nil]*3].each.with_index(1) do |row, row_index|
435
+ row.each.with_index(1) do |value, col_index|
436
+ expect(subject.hyperlink(row_index, col_index)).to eq(value)
437
+ end
438
+ end
439
+ end
440
+ end
441
+
442
+ context 'without location' do
443
+ let(:path) { 'test/files/link.xlsx' }
444
+
445
+ it 'returns the expected result' do
446
+ expect(subject.hyperlink(1, 1)).to eq "http://www.google.com"
447
+ expect(subject.hyperlink(1, 2)).to eq nil
448
+ end
449
+ end
450
+
451
+ context 'with location' do
452
+ let(:path) { 'test/files/link_with_location.xlsx' }
453
+
454
+ it 'returns the expected result' do
455
+ expect(subject.hyperlink(1, 1)).to eq "http://www.google.com/#hey"
456
+ expect(subject.hyperlink(1, 2)).to eq nil
457
+ end
341
458
  end
342
459
  end
343
460
 
@@ -458,10 +575,125 @@ describe Roo::Excelx do
458
575
  end
459
576
  end
460
577
 
578
+ describe '#html_strings' do
579
+ describe "HTML Parsing Enabling" do
580
+ let(:path) { 'test/files/html_strings_formatting.xlsx' }
581
+
582
+ it 'returns the expected result' do
583
+ expect(subject.excelx_value(1, 1, "Sheet1")).to eq("This has no formatting.")
584
+ expect(subject.excelx_value(2, 1, "Sheet1")).to eq("<html>This has<b> bold </b>formatting.</html>")
585
+ expect(subject.excelx_value(2, 2, "Sheet1")).to eq("<html>This has <i>italics</i> formatting.</html>")
586
+ expect(subject.excelx_value(2, 3, "Sheet1")).to eq("<html>This has <u>underline</u> format.</html>")
587
+ expect(subject.excelx_value(2, 4, "Sheet1")).to eq("<html>Superscript. x<sup>123</sup></html>")
588
+ expect(subject.excelx_value(2, 5, "Sheet1")).to eq("<html>SubScript. T<sub>j</sub></html>")
589
+
590
+ expect(subject.excelx_value(3, 1, "Sheet1")).to eq("<html>Bold, italics <b><i>together</i></b>.</html>")
591
+ expect(subject.excelx_value(3, 2, "Sheet1")).to eq("<html>Bold, Underline <b><u>together</u></b>.</html>")
592
+ expect(subject.excelx_value(3, 3, "Sheet1")).to eq("<html>Bold, Superscript. <b>x</b><sup><b>N</b></sup></html>")
593
+ expect(subject.excelx_value(3, 4, "Sheet1")).to eq("<html>Bold, Subscript. <b>T</b><sub><b>abc</b></sub></html>")
594
+ expect(subject.excelx_value(3, 5, "Sheet1")).to eq("<html>Italics, Underline <i><u>together</u></i>.</html>")
595
+ expect(subject.excelx_value(3, 6, "Sheet1")).to eq("<html>Italics, Superscript. <i>X</i><sup><i>abc</i></sup></html>")
596
+ expect(subject.excelx_value(3, 7, "Sheet1")).to eq("<html>Italics, Subscript. <i>B</i><sub><i>efg</i></sub></html>")
597
+ expect(subject.excelx_value(4, 1, "Sheet1")).to eq("<html>Bold, italics underline,<b><i><u> together</u></i></b>.</html>")
598
+ expect(subject.excelx_value(4, 2, "Sheet1")).to eq("<html>Bold, italics, superscript. <b>X</b><sup><b><i>abc</i></b></sup><b><i>123</i></b></html>")
599
+ expect(subject.excelx_value(4, 3, "Sheet1")).to eq("<html>Bold, Italics, subscript. <b><i>Mg</i></b><sub><b><i>ha</i></b></sub><b><i>2</i></b></html>")
600
+ expect(subject.excelx_value(4, 4, "Sheet1")).to eq("<html>Bold, Underline, superscript. <b><u>AB</u></b><sup><b><u>C12</u></b></sup><b><u>3</u></b></html>")
601
+ expect(subject.excelx_value(4, 5, "Sheet1")).to eq("<html>Bold, Underline, subscript. <b><u>Good</u></b><sub><b><u>XYZ</u></b></sub></html>")
602
+ expect(subject.excelx_value(4, 6, "Sheet1")).to eq("<html>Italics, Underline, superscript. <i><u>Up</u></i><sup><i><u>swing</u></i></sup></html>")
603
+ expect(subject.excelx_value(4, 7, "Sheet1")).to eq("<html>Italics, Underline, subscript. <i><u>T</u></i><sub><i><u>swing</u></i></sub></html>")
604
+ expect(subject.excelx_value(5, 1, "Sheet1")).to eq("<html>Bold, italics, underline, superscript. <b><i><u>GHJK</u></i></b><sup><b><i><u>190</u></i></b></sup><b><i><u>4</u></i></b></html>")
605
+ expect(subject.excelx_value(5, 2, "Sheet1")).to eq("<html>Bold, italics, underline, subscript. <b><i><u>Mike</u></i></b><sub><b><i><u>drop</u></i></b></sub></html>")
606
+ expect(subject.excelx_value(6, 1, "Sheet1")).to eq("See that regular html tags do not create html tags.\n<ol>\n <li> Denver Broncos </li>\n <li> Carolina Panthers </li>\n <li> New England Patriots</li>\n <li>Arizona Panthers</li>\n</ol>")
607
+ expect(subject.excelx_value(7, 1, "Sheet1")).to eq("<html>Does create html tags when formatting is used..\n<ol>\n <li> <b>Denver Broncos</b> </li>\n <li> <i>Carolina Panthers </i></li>\n <li> <u>New England Patriots</u></li>\n <li>Arizona Panthers</li>\n</ol></html>")
608
+ end
609
+ end
610
+ end
611
+
461
612
  describe '_x000D_' do
462
613
  let(:path) { 'test/files/x000D.xlsx' }
463
614
  it 'does not contain _x000D_' do
464
615
  expect(subject.cell(2, 9)).not_to include('_x000D_')
465
616
  end
466
617
  end
618
+
619
+ describe 'opening a file with a chart sheet' do
620
+ let(:path) { 'test/files/chart_sheet.xlsx' }
621
+ it 'should not raise' do
622
+ expect{ subject }.to_not raise_error
623
+ end
624
+ end
625
+
626
+ describe 'opening a file with white space in the styles.xml' do
627
+ let(:path) { 'test/files/style_nodes_with_white_spaces.xlsx' }
628
+ subject(:xlsx) do
629
+ Roo::Spreadsheet.open(path, expand_merged_ranges: true, extension: :xlsx)
630
+ end
631
+ it 'should properly recognize formats' do
632
+ expect(subject.sheet(0).excelx_format(2,1)).to eq 'm/d/yyyy" "h:mm:ss" "AM/PM'
633
+ end
634
+ end
635
+
636
+ describe 'opening a file with filters' do
637
+ let(:path) { 'test/files/wrong_coordinates.xlsx' }
638
+ subject(:xlsx) do
639
+ Roo::Spreadsheet.open(path)
640
+ end
641
+
642
+ it 'should properly extract defined_names' do
643
+ expect(subject.sheet(0).workbook.defined_names.length).to eq(1)
644
+ end
645
+ end
646
+
647
+ describe 'images' do
648
+ let(:path) { 'test/files/images.xlsx' }
649
+
650
+ it 'returns array of images from default sheet' do
651
+ expect(subject.images).to be_kind_of(Array)
652
+ expect(subject.images.size).to eql(19)
653
+ end
654
+
655
+ it 'returns empty array if there is no images on the sheet' do
656
+ expect(subject.images("Sheet2")).to eql([])
657
+ end
658
+ end
659
+ end
660
+
661
+ describe 'Roo::Excelx with options set' do
662
+ subject(:xlsx) do
663
+ Roo::Excelx.new(path, disable_html_wrapper: true)
664
+ end
665
+
666
+ describe '#html_strings' do
667
+ describe "HTML Parsing Disabled" do
668
+ let(:path) { 'test/files/html_strings_formatting.xlsx' }
669
+
670
+ it 'returns the expected result' do
671
+ expect(subject.excelx_value(1, 1, "Sheet1")).to eq("This has no formatting.")
672
+ expect(subject.excelx_value(2, 1, "Sheet1")).to eq("This has bold formatting.")
673
+ expect(subject.excelx_value(2, 2, "Sheet1")).to eq("This has italics formatting.")
674
+ expect(subject.excelx_value(2, 3, "Sheet1")).to eq("This has underline format.")
675
+ expect(subject.excelx_value(2, 4, "Sheet1")).to eq("Superscript. x123")
676
+ expect(subject.excelx_value(2, 5, "Sheet1")).to eq("SubScript. Tj")
677
+
678
+ expect(subject.excelx_value(3, 1, "Sheet1")).to eq("Bold, italics together.")
679
+ expect(subject.excelx_value(3, 2, "Sheet1")).to eq("Bold, Underline together.")
680
+ expect(subject.excelx_value(3, 3, "Sheet1")).to eq("Bold, Superscript. xN")
681
+ expect(subject.excelx_value(3, 4, "Sheet1")).to eq("Bold, Subscript. Tabc")
682
+ expect(subject.excelx_value(3, 5, "Sheet1")).to eq("Italics, Underline together.")
683
+ expect(subject.excelx_value(3, 6, "Sheet1")).to eq("Italics, Superscript. Xabc")
684
+ expect(subject.excelx_value(3, 7, "Sheet1")).to eq("Italics, Subscript. Befg")
685
+ expect(subject.excelx_value(4, 1, "Sheet1")).to eq("Bold, italics underline, together.")
686
+ expect(subject.excelx_value(4, 2, "Sheet1")).to eq("Bold, italics, superscript. Xabc123")
687
+ expect(subject.excelx_value(4, 3, "Sheet1")).to eq("Bold, Italics, subscript. Mgha2")
688
+ expect(subject.excelx_value(4, 4, "Sheet1")).to eq("Bold, Underline, superscript. ABC123")
689
+ expect(subject.excelx_value(4, 5, "Sheet1")).to eq("Bold, Underline, subscript. GoodXYZ")
690
+ expect(subject.excelx_value(4, 6, "Sheet1")).to eq("Italics, Underline, superscript. Upswing")
691
+ expect(subject.excelx_value(4, 7, "Sheet1")).to eq("Italics, Underline, subscript. Tswing")
692
+ expect(subject.excelx_value(5, 1, "Sheet1")).to eq("Bold, italics, underline, superscript. GHJK1904")
693
+ expect(subject.excelx_value(5, 2, "Sheet1")).to eq("Bold, italics, underline, subscript. Mikedrop")
694
+ expect(subject.excelx_value(6, 1, "Sheet1")).to eq("See that regular html tags do not create html tags.\n<ol>\n <li> Denver Broncos </li>\n <li> Carolina Panthers </li>\n <li> New England Patriots</li>\n <li>Arizona Panthers</li>\n</ol>")
695
+ expect(subject.excelx_value(7, 1, "Sheet1")).to eq("Does create html tags when formatting is used..\n<ol>\n <li> Denver Broncos </li>\n <li> Carolina Panthers </li>\n <li> New England Patriots</li>\n <li>Arizona Panthers</li>\n</ol>")
696
+ end
697
+ end
698
+ end
467
699
  end
@@ -13,10 +13,10 @@ describe Roo::OpenOffice do
13
13
  context 'for float/integer values' do
14
14
  context 'integer without point' do
15
15
  it { expect(subject.cell(3,"A","Sheet4")).to eq(1234) }
16
- it { expect(subject.cell(3,"A","Sheet4")).to be_a(Fixnum) }
16
+ it { expect(subject.cell(3,"A","Sheet4")).to be_a(Integer) }
17
17
  end
18
18
 
19
- context 'float with point' do
19
+ context 'float with point' do
20
20
  it { expect(subject.cell(3,"B","Sheet4")).to eq(1234.00) }
21
21
  it { expect(subject.cell(3,"B","Sheet4")).to be_a(Float) }
22
22
  end
@@ -25,7 +25,7 @@ describe Roo::Spreadsheet do
25
25
  let(:filename) { tempfile.path }
26
26
 
27
27
  it 'loads the proper type' do
28
- expect(Roo::CSV).to receive(:new).with(filename, file_warning: :ignore).and_call_original
28
+ expect(Roo::CSV).to receive(:new).with(filename, {file_warning: :ignore}).and_call_original
29
29
  expect(Roo::Spreadsheet.open(tempfile, extension: :csv)).to be_a(Roo::CSV)
30
30
  end
31
31
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Roo::Excelx do
4
+ subject { Roo::Excelx.new('test/files/strict.xlsx') }
5
+
6
+ example '#sheets' do
7
+ expect(subject.sheets).to eq %w(Sheet1 Sheet2)
8
+ end
9
+
10
+ example '#sheet' do
11
+ expect(subject.sheet('Sheet1')).to be_a(Roo::Excelx)
12
+ end
13
+
14
+ example '#cell' do
15
+ expect(subject.cell(1, 1)).to eq 'Sheet 1'
16
+ expect(subject.cell(1, 1, 'Sheet2')).to eq 'Sheet 2'
17
+ end
18
+
19
+ example '#row' do
20
+ expect(subject.row(1)).to eq ['Sheet 1']
21
+ expect(subject.row(1, 'Sheet2')).to eq ['Sheet 2']
22
+ end
23
+
24
+ example '#first_row' do
25
+ expect(subject.first_row).to eq 1
26
+ expect(subject.first_row('Sheet2')).to eq 1
27
+ end
28
+
29
+ example '#last_row' do
30
+ expect(subject.last_row).to eq 1
31
+ expect(subject.last_row('Sheet2')).to eq 1
32
+ end
33
+
34
+ example '#first_column' do
35
+ expect(subject.first_column).to eq 1
36
+ expect(subject.first_column('Sheet2')).to eq 1
37
+ end
38
+
39
+ example '#last_column' do
40
+ expect(subject.last_column).to eq 1
41
+ expect(subject.last_column('Sheet2')).to eq 1
42
+ end
43
+ end
@@ -4,7 +4,7 @@ RSpec.describe ::Roo::Utils do
4
4
  subject { described_class }
5
5
 
6
6
  context '#number_to_letter' do
7
- ('A'..'Z').to_a.each_with_index do |letter, index|
7
+ described_class::LETTERS.each_with_index do |letter, index|
8
8
  it "should return '#{ letter }' when passed #{ index + 1 }" do
9
9
  expect(described_class.number_to_letter(index + 1)).to eq(letter)
10
10
  end
@@ -43,12 +43,12 @@ RSpec.describe ::Roo::Utils do
43
43
  end
44
44
  end
45
45
 
46
- context '.split_coordinate' do
46
+ context '.extract_coordinate' do
47
47
  it "returns the expected result" do
48
- expect(described_class.split_coordinate('A1')).to eq [1, 1]
49
- expect(described_class.split_coordinate('B2')).to eq [2, 2]
50
- expect(described_class.split_coordinate('R2')).to eq [2, 18]
51
- expect(described_class.split_coordinate('AR31')).to eq [31, 18 + 26]
48
+ expect(described_class.extract_coordinate('A1')).to eq [1, 1]
49
+ expect(described_class.extract_coordinate('B2')).to eq [2, 2]
50
+ expect(described_class.extract_coordinate('R2')).to eq [2, 18]
51
+ expect(described_class.extract_coordinate('AR31')).to eq [31, 18 + 26]
52
52
  end
53
53
  end
54
54
 
@@ -81,26 +81,39 @@ RSpec.describe ::Roo::Utils do
81
81
  end
82
82
  end
83
83
 
84
+ context '.coordinates_in_range' do
85
+ it "returns the expected result" do
86
+ expect(described_class.coordinates_in_range('').to_a).to eq []
87
+ expect(described_class.coordinates_in_range('B2').to_a).to eq [[2, 2]]
88
+ expect(described_class.coordinates_in_range('D2:G3').to_a).to eq [[2, 4], [2, 5], [2, 6], [2, 7], [3, 4], [3, 5], [3, 6], [3, 7]]
89
+ expect(described_class.coordinates_in_range('G3:D2').to_a).to eq []
90
+ end
91
+
92
+ it "raises an error when appropriate" do
93
+ expect { described_class.coordinates_in_range('D2:G3:I5').to_a }.to raise_error(ArgumentError)
94
+ end
95
+ end
96
+
84
97
  context '.load_xml' do
85
98
  it 'returns the expected result' do
86
99
  expect(described_class.load_xml('test/files/sheet1.xml')).to be_a(Nokogiri::XML::Document)
87
100
  expect(described_class.load_xml('test/files/sheet1.xml').
88
101
  remove_namespaces!.xpath("/worksheet/dimension").map do |dim|
89
- dim.attributes["ref"].value end.first).to eq "A1:B11"
102
+ dim["ref"] end.first).to eq "A1:B11"
90
103
  end
91
104
  end
92
105
 
93
106
  context '.each_element' do
94
107
  it 'returns the expected result' do
95
108
  described_class.each_element('test/files/sheet1.xml', 'dimension') do |dim|
96
- expect(dim.attributes["ref"].value).to eq "A1:B11"
109
+ expect(dim["ref"]).to eq "A1:B11"
97
110
  end
98
111
  rows = []
99
112
  described_class.each_element('test/files/sheet1.xml', 'row') do |row|
100
113
  rows << row
101
114
  end
102
115
  expect(rows.size).to eq 11
103
- expect(rows[2].attributes["r"].value).to eq "3"
116
+ expect(rows[2]["r"]).to eq "3"
104
117
  end
105
118
  end
106
119
  end