roo 1.13.2 → 2.0.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.
- checksums.yaml +4 -4
- data/.gitignore +7 -0
- data/.simplecov +4 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +500 -0
- data/Gemfile +16 -10
- data/Guardfile +24 -0
- data/LICENSE +3 -1
- data/README.md +254 -0
- data/Rakefile +23 -23
- data/examples/roo_soap_client.rb +28 -31
- data/examples/roo_soap_server.rb +4 -6
- data/examples/write_me.rb +9 -10
- data/lib/roo/base.rb +303 -388
- data/lib/roo/csv.rb +120 -113
- data/lib/roo/excelx/comments.rb +24 -0
- data/lib/roo/excelx/extractor.rb +20 -0
- data/lib/roo/excelx/relationships.rb +26 -0
- data/lib/roo/excelx/shared_strings.rb +40 -0
- data/lib/roo/excelx/sheet_doc.rb +202 -0
- data/lib/roo/excelx/styles.rb +62 -0
- data/lib/roo/excelx/workbook.rb +59 -0
- data/lib/roo/excelx.rb +452 -484
- data/lib/roo/font.rb +17 -0
- data/lib/roo/libre_office.rb +5 -0
- data/lib/roo/link.rb +15 -0
- data/lib/roo/{openoffice.rb → open_office.rb} +678 -496
- data/lib/roo/spreadsheet.rb +20 -23
- data/lib/roo/utils.rb +78 -0
- data/lib/roo/version.rb +3 -0
- data/lib/roo.rb +18 -24
- data/roo.gemspec +20 -204
- data/spec/lib/roo/base_spec.rb +1 -4
- data/spec/lib/roo/csv_spec.rb +21 -13
- data/spec/lib/roo/excelx/format_spec.rb +7 -6
- data/spec/lib/roo/excelx_spec.rb +388 -11
- data/spec/lib/roo/libreoffice_spec.rb +16 -6
- data/spec/lib/roo/openoffice_spec.rb +2 -8
- data/spec/lib/roo/spreadsheet_spec.rb +40 -12
- data/spec/lib/roo/utils_spec.rb +106 -0
- data/spec/spec_helper.rb +2 -1
- data/test/test_generic_spreadsheet.rb +19 -67
- data/test/test_helper.rb +9 -56
- data/test/test_roo.rb +252 -477
- metadata +63 -302
- data/CHANGELOG +0 -417
- data/Gemfile.lock +0 -78
- data/README.markdown +0 -126
- data/VERSION +0 -1
- data/lib/roo/excel.rb +0 -355
- data/lib/roo/excel2003xml.rb +0 -300
- data/lib/roo/google.rb +0 -292
- data/lib/roo/roo_rails_helper.rb +0 -83
- data/lib/roo/worksheet.rb +0 -18
- data/spec/lib/roo/excel2003xml_spec.rb +0 -15
- data/spec/lib/roo/excel_spec.rb +0 -17
- data/spec/lib/roo/google_spec.rb +0 -64
- data/test/files/1900_base.xls +0 -0
- data/test/files/1900_base.xlsx +0 -0
- data/test/files/1904_base.xls +0 -0
- data/test/files/1904_base.xlsx +0 -0
- data/test/files/Bibelbund.csv +0 -3741
- data/test/files/Bibelbund.ods +0 -0
- data/test/files/Bibelbund.xls +0 -0
- data/test/files/Bibelbund.xlsx +0 -0
- data/test/files/Bibelbund.xml +0 -62518
- data/test/files/Bibelbund1.ods +0 -0
- data/test/files/Pfand_from_windows_phone.xlsx +0 -0
- data/test/files/bad_excel_date.xls +0 -0
- data/test/files/bbu.ods +0 -0
- data/test/files/bbu.xls +0 -0
- data/test/files/bbu.xlsx +0 -0
- data/test/files/bbu.xml +0 -152
- data/test/files/bode-v1.ods.zip +0 -0
- data/test/files/bode-v1.xls.zip +0 -0
- data/test/files/boolean.csv +0 -2
- data/test/files/boolean.ods +0 -0
- data/test/files/boolean.xls +0 -0
- data/test/files/boolean.xlsx +0 -0
- data/test/files/boolean.xml +0 -112
- data/test/files/borders.ods +0 -0
- data/test/files/borders.xls +0 -0
- data/test/files/borders.xlsx +0 -0
- data/test/files/borders.xml +0 -144
- data/test/files/bug-numbered-sheet-names.xlsx +0 -0
- data/test/files/bug-row-column-fixnum-float.xls +0 -0
- data/test/files/bug-row-column-fixnum-float.xml +0 -127
- data/test/files/comments.ods +0 -0
- data/test/files/comments.xls +0 -0
- data/test/files/comments.xlsx +0 -0
- data/test/files/csvtypes.csv +0 -1
- data/test/files/datetime.ods +0 -0
- data/test/files/datetime.xls +0 -0
- data/test/files/datetime.xlsx +0 -0
- data/test/files/datetime.xml +0 -142
- data/test/files/datetime_floatconv.xls +0 -0
- data/test/files/datetime_floatconv.xml +0 -148
- data/test/files/dreimalvier.ods +0 -0
- data/test/files/emptysheets.ods +0 -0
- data/test/files/emptysheets.xls +0 -0
- data/test/files/emptysheets.xlsx +0 -0
- data/test/files/emptysheets.xml +0 -105
- data/test/files/excel2003.xml +0 -21140
- data/test/files/false_encoding.xls +0 -0
- data/test/files/false_encoding.xml +0 -132
- data/test/files/file_item_error.xlsx +0 -0
- data/test/files/formula.ods +0 -0
- data/test/files/formula.xls +0 -0
- data/test/files/formula.xlsx +0 -0
- data/test/files/formula.xml +0 -134
- data/test/files/formula_parse_error.xls +0 -0
- data/test/files/formula_parse_error.xml +0 -1833
- data/test/files/formula_string_error.xlsx +0 -0
- data/test/files/html-escape.ods +0 -0
- data/test/files/link.xls +0 -0
- data/test/files/link.xlsx +0 -0
- data/test/files/matrix.ods +0 -0
- data/test/files/matrix.xls +0 -0
- data/test/files/named_cells.ods +0 -0
- data/test/files/named_cells.xls +0 -0
- data/test/files/named_cells.xlsx +0 -0
- data/test/files/no_spreadsheet_file.txt +0 -1
- data/test/files/numbers1.csv +0 -18
- data/test/files/numbers1.ods +0 -0
- data/test/files/numbers1.xls +0 -0
- data/test/files/numbers1.xlsx +0 -0
- data/test/files/numbers1.xml +0 -312
- data/test/files/numeric-link.xlsx +0 -0
- data/test/files/only_one_sheet.ods +0 -0
- data/test/files/only_one_sheet.xls +0 -0
- data/test/files/only_one_sheet.xlsx +0 -0
- data/test/files/only_one_sheet.xml +0 -67
- data/test/files/paragraph.ods +0 -0
- data/test/files/paragraph.xls +0 -0
- data/test/files/paragraph.xlsx +0 -0
- data/test/files/paragraph.xml +0 -127
- data/test/files/prova.xls +0 -0
- data/test/files/ric.ods +0 -0
- data/test/files/simple_spreadsheet.ods +0 -0
- data/test/files/simple_spreadsheet.xls +0 -0
- data/test/files/simple_spreadsheet.xlsx +0 -0
- data/test/files/simple_spreadsheet.xml +0 -225
- data/test/files/simple_spreadsheet_from_italo.ods +0 -0
- data/test/files/simple_spreadsheet_from_italo.xls +0 -0
- data/test/files/simple_spreadsheet_from_italo.xml +0 -242
- data/test/files/so_datetime.csv +0 -7
- data/test/files/style.ods +0 -0
- data/test/files/style.xls +0 -0
- data/test/files/style.xlsx +0 -0
- data/test/files/style.xml +0 -154
- data/test/files/time-test.csv +0 -2
- data/test/files/time-test.ods +0 -0
- data/test/files/time-test.xls +0 -0
- data/test/files/time-test.xlsx +0 -0
- data/test/files/time-test.xml +0 -131
- data/test/files/type_excel.ods +0 -0
- data/test/files/type_excel.xlsx +0 -0
- data/test/files/type_excelx.ods +0 -0
- data/test/files/type_excelx.xls +0 -0
- data/test/files/type_openoffice.xls +0 -0
- data/test/files/type_openoffice.xlsx +0 -0
- data/test/files/whitespace.ods +0 -0
- data/test/files/whitespace.xls +0 -0
- data/test/files/whitespace.xlsx +0 -0
- data/test/files/whitespace.xml +0 -184
- data/test/rm_sub_test.rb +0 -12
- data/test/rm_test.rb +0 -7
- data/website/index.html +0 -385
- data/website/index.txt +0 -423
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -130
- data/website/template.rhtml +0 -48
data/spec/lib/roo/excelx_spec.rb
CHANGED
|
@@ -1,37 +1,414 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
require 'spec_helper'
|
|
2
3
|
|
|
3
4
|
describe Roo::Excelx do
|
|
5
|
+
subject(:xlsx) do
|
|
6
|
+
Roo::Excelx.new(path)
|
|
7
|
+
end
|
|
8
|
+
|
|
4
9
|
describe '.new' do
|
|
5
|
-
|
|
6
|
-
Roo::Excelx.new('test/files/numbers1.xlsx')
|
|
7
|
-
}
|
|
10
|
+
let(:path) { 'test/files/numeric-link.xlsx' }
|
|
8
11
|
|
|
9
12
|
it 'creates an instance' do
|
|
10
13
|
expect(subject).to be_a(Roo::Excelx)
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
context 'given a file with missing rels' do
|
|
14
|
-
|
|
15
|
-
Roo::Excelx.new('test/files/file_item_error.xlsx')
|
|
16
|
-
}
|
|
17
|
+
let(:path) { 'test/files/file_item_error.xlsx' }
|
|
17
18
|
|
|
18
19
|
it 'creates an instance' do
|
|
19
20
|
expect(subject).to be_a(Roo::Excelx)
|
|
20
21
|
end
|
|
21
22
|
end
|
|
23
|
+
|
|
24
|
+
context 'with more cells than specified max' do
|
|
25
|
+
let(:path) { 'test/files/only_one_sheet.xlsx' }
|
|
26
|
+
|
|
27
|
+
it 'raises an appropriate error' do
|
|
28
|
+
expect { Roo::Excelx.new(path, cell_max: 1) }.to raise_error(Roo::Excelx::ExceedsMaxError)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context 'with fewer cells than specified max' do
|
|
33
|
+
let(:path) { 'test/files/only_one_sheet.xlsx' }
|
|
34
|
+
|
|
35
|
+
it 'creates an instance' do
|
|
36
|
+
expect(Roo::Excelx.new(path, cell_max: 100)).to be_a(Roo::Excelx)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
22
39
|
end
|
|
23
40
|
|
|
24
41
|
describe '#cell' do
|
|
25
42
|
context 'for a link cell' do
|
|
26
43
|
context 'with numeric contents' do
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
44
|
+
let(:path) { 'test/files/numeric-link.xlsx' }
|
|
45
|
+
|
|
46
|
+
subject do
|
|
47
|
+
xlsx.cell('A', 1)
|
|
48
|
+
end
|
|
30
49
|
|
|
31
50
|
it 'returns a link with the number as a string value' do
|
|
32
|
-
expect(subject).to be_a(
|
|
33
|
-
expect(subject).to eq(
|
|
51
|
+
expect(subject).to be_a(Roo::Link)
|
|
52
|
+
expect(subject).to eq('8675309.0')
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'for a non-existent cell' do
|
|
58
|
+
let(:path) { 'test/files/numeric-link.xlsx' }
|
|
59
|
+
it 'return nil' do
|
|
60
|
+
expect(xlsx.cell('AAA', 999)).to eq nil
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#parse' do
|
|
66
|
+
let(:path) { 'test/files/numeric-link.xlsx' }
|
|
67
|
+
|
|
68
|
+
context 'with a columns hash' do
|
|
69
|
+
context 'when not present in the sheet' do
|
|
70
|
+
it 'does not raise' do
|
|
71
|
+
expect do
|
|
72
|
+
xlsx.sheet(0).parse(
|
|
73
|
+
this: 'This',
|
|
74
|
+
that: 'That'
|
|
75
|
+
)
|
|
76
|
+
end.to raise_error("Couldn't find header row.")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#parse_with_clean_option' do
|
|
83
|
+
let(:path) { 'test/files/parse_with_clean_option.xlsx' }
|
|
84
|
+
let(:options) { {clean: true} }
|
|
85
|
+
|
|
86
|
+
context 'with clean: true' do
|
|
87
|
+
|
|
88
|
+
it 'does not raise' do
|
|
89
|
+
expect do
|
|
90
|
+
xlsx.parse(options)
|
|
91
|
+
end.not_to raise_error
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe '#parse_unicode_with_clean_option' do
|
|
97
|
+
let(:path) { 'test/files/parse_clean_with_unicode.xlsx' }
|
|
98
|
+
let(:options) { {clean: true, name: 'Name'} }
|
|
99
|
+
|
|
100
|
+
context 'with clean: true' do
|
|
101
|
+
|
|
102
|
+
it 'returns a non empty string' do
|
|
103
|
+
expect(xlsx.parse(options).last[:name]).to eql('凯')
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
describe '#sheets' do
|
|
112
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
113
|
+
|
|
114
|
+
it 'returns the expected result' do
|
|
115
|
+
expect(subject.sheets).to eq ["Tabelle1", "Name of Sheet 2", "Sheet3", "Sheet4", "Sheet5"]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe 'only showing visible sheets' do
|
|
119
|
+
let(:path) { 'test/files/hidden_sheets.xlsx' }
|
|
120
|
+
|
|
121
|
+
it 'returns the expected result' do
|
|
122
|
+
expect(Roo::Excelx.new(path, only_visible_sheets: true).sheets).to eq ["VisibleSheet1"]
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe '#sheet_for' do
|
|
128
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
129
|
+
|
|
130
|
+
# This is kinda gross
|
|
131
|
+
it 'returns the expected result' do
|
|
132
|
+
expect(subject.sheet_for("Tabelle1").instance_variable_get("@name")).to eq "Tabelle1"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
describe '#row' do
|
|
137
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
138
|
+
|
|
139
|
+
it 'returns the expected result' do
|
|
140
|
+
expect(subject.row(1, "Sheet5")).to eq [1.0, 5.0, 5.0, nil, nil]
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe '#column' do
|
|
145
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
146
|
+
|
|
147
|
+
it 'returns the expected result' do
|
|
148
|
+
expect(subject.column(1, "Sheet5")).to eq [1.0, 2.0, 3.0, Date.new(2007,11,21), 42.0, "ABC"]
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
describe '#first_row' do
|
|
153
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
154
|
+
|
|
155
|
+
it 'returns the expected result' do
|
|
156
|
+
expect(subject.first_row("Sheet5")).to eq 1
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
describe '#last_row' do
|
|
161
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
162
|
+
|
|
163
|
+
it 'returns the expected result' do
|
|
164
|
+
expect(subject.last_row("Sheet5")).to eq 6
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe '#first_column' do
|
|
169
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
170
|
+
|
|
171
|
+
it 'returns the expected result' do
|
|
172
|
+
expect(subject.first_column("Sheet5")).to eq 1
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
describe '#last_column' do
|
|
177
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
178
|
+
|
|
179
|
+
it 'returns the expected result' do
|
|
180
|
+
expect(subject.last_column("Sheet5")).to eq 5
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
describe '#set' do
|
|
185
|
+
|
|
186
|
+
before do
|
|
187
|
+
subject.set(1, 2, "Foo", "Sheet5")
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
191
|
+
let(:cell) { subject.cell(1, 2, "Sheet5") }
|
|
192
|
+
|
|
193
|
+
it 'returns the expected result' do
|
|
194
|
+
expect(cell).to eq "Foo"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
describe '#formula' do
|
|
199
|
+
let(:path) { 'test/files/formula.xlsx' }
|
|
200
|
+
|
|
201
|
+
it 'returns the expected result' do
|
|
202
|
+
expect(subject.formula(1, 1, "Sheet1")).to eq nil
|
|
203
|
+
expect(subject.formula(7, 2, "Sheet1")).to eq "SUM($A$1:B6)"
|
|
204
|
+
expect(subject.formula(1000, 2000, "Sheet1")).to eq nil
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe '#formula?' do
|
|
209
|
+
let(:path) { 'test/files/formula.xlsx' }
|
|
210
|
+
|
|
211
|
+
it 'returns the expected result' do
|
|
212
|
+
expect(subject.formula?(1, 1, "Sheet1")).to eq false
|
|
213
|
+
expect(subject.formula?(7, 2, "Sheet1")).to eq true
|
|
214
|
+
expect(subject.formula?(1000, 2000, "Sheet1")).to eq false
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
describe '#formulas' do
|
|
219
|
+
let(:path) { 'test/files/formula.xlsx' }
|
|
220
|
+
|
|
221
|
+
it 'returns the expected result' do
|
|
222
|
+
expect(subject.formulas("Sheet1")).to eq [[7, 1, "SUM(A1:A6)"], [7, 2, "SUM($A$1:B6)"]]
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
describe '#font' do
|
|
227
|
+
let(:path) { 'test/files/style.xlsx' }
|
|
228
|
+
|
|
229
|
+
it 'returns the expected result' do
|
|
230
|
+
expect(subject.font(1, 1).bold?).to eq true
|
|
231
|
+
expect(subject.font(1, 1).italic?).to eq false
|
|
232
|
+
expect(subject.font(1, 1).underline?).to eq false
|
|
233
|
+
|
|
234
|
+
expect(subject.font(7, 1).bold?).to eq false
|
|
235
|
+
expect(subject.font(7, 1).italic?).to eq true
|
|
236
|
+
expect(subject.font(7, 1).underline?).to eq true
|
|
237
|
+
expect(subject.font(1000, 2000)).to eq nil
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
describe '#celltype' do
|
|
242
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
243
|
+
|
|
244
|
+
it 'returns the expected result' do
|
|
245
|
+
expect(subject.celltype(1, 1, "Sheet4")).to eq :date
|
|
246
|
+
expect(subject.celltype(1, 2, "Sheet4")).to eq :float
|
|
247
|
+
expect(subject.celltype(6, 2, "Sheet5")).to eq :string
|
|
248
|
+
expect(subject.celltype(1000, 2000, "Sheet5")).to eq nil
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
describe '#excelx_type' do
|
|
253
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
254
|
+
|
|
255
|
+
it 'returns the expected result' do
|
|
256
|
+
expect(subject.excelx_type(1, 1, "Sheet5")).to eq [:numeric_or_formula, "General"]
|
|
257
|
+
expect(subject.excelx_type(6, 2, "Sheet5")).to eq :string
|
|
258
|
+
expect(subject.excelx_type(1000, 2000, "Sheet5")).to eq nil
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
describe '#excelx_value' do
|
|
263
|
+
let(:path) { 'test/files/numbers1.xlsx' }
|
|
264
|
+
|
|
265
|
+
it 'returns the expected result' do
|
|
266
|
+
# These values are the index in the shared strings table, might be a better
|
|
267
|
+
# way to get these rather than hardcoding.
|
|
268
|
+
expect(subject.excelx_value(1, 1, "Sheet5")).to eq "1"
|
|
269
|
+
expect(subject.excelx_value(6, 2, "Sheet5")).to eq "16"
|
|
270
|
+
expect(subject.excelx_value(6000, 2000, "Sheet5")).to eq nil
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
describe '#excelx_format' do
|
|
275
|
+
let(:path) { 'test/files/style.xlsx' }
|
|
276
|
+
|
|
277
|
+
it 'returns the expected result' do
|
|
278
|
+
# These are the index of the style for a given document
|
|
279
|
+
# might be more reliable way to get this info.
|
|
280
|
+
expect(subject.excelx_format(1, 1)).to eq "General"
|
|
281
|
+
expect(subject.excelx_format(2, 2)).to eq "0.00"
|
|
282
|
+
expect(subject.excelx_format(5000, 1000)).to eq nil
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
describe '#empty?' do
|
|
287
|
+
let(:path) { 'test/files/style.xlsx' }
|
|
288
|
+
|
|
289
|
+
it 'returns the expected result' do
|
|
290
|
+
# These are the index of the style for a given document
|
|
291
|
+
# might be more reliable way to get this info.
|
|
292
|
+
expect(subject.empty?(1, 1)).to eq false
|
|
293
|
+
expect(subject.empty?(13, 1)).to eq true
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
describe '#label' do
|
|
298
|
+
let(:path) { 'test/files/named_cells.xlsx' }
|
|
299
|
+
|
|
300
|
+
it 'returns the expected result' do
|
|
301
|
+
expect(subject.label("berta")).to eq [4, 2, "Sheet1"]
|
|
302
|
+
expect(subject.label("dave")).to eq [nil, nil, nil]
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
describe '#labels' do
|
|
307
|
+
let(:path) { 'test/files/named_cells.xlsx' }
|
|
308
|
+
|
|
309
|
+
it 'returns the expected result' do
|
|
310
|
+
expect(subject.labels).to eq [["anton", [5, 3, "Sheet1"]], ["berta", [4, 2, "Sheet1"]], ["caesar", [7, 2, "Sheet1"]]]
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
describe '#hyperlink?' do
|
|
315
|
+
let(:path) { 'test/files/link.xlsx' }
|
|
316
|
+
|
|
317
|
+
it 'returns the expected result' do
|
|
318
|
+
expect(subject.hyperlink?(1, 1)).to eq true
|
|
319
|
+
expect(subject.hyperlink?(1, 2)).to eq false
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
describe '#hyperlink' do
|
|
324
|
+
let(:path) { 'test/files/link.xlsx' }
|
|
325
|
+
|
|
326
|
+
it 'returns the expected result' do
|
|
327
|
+
expect(subject.hyperlink(1, 1)).to eq "http://www.google.com"
|
|
328
|
+
expect(subject.hyperlink(1, 2)).to eq nil
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
describe '#comment' do
|
|
333
|
+
let(:path) { 'test/files/comments.xlsx' }
|
|
334
|
+
|
|
335
|
+
it 'returns the expected result' do
|
|
336
|
+
expect(subject.comment(4, 2)).to eq "Kommentar fuer B4"
|
|
337
|
+
expect(subject.comment(1, 2)).to eq nil
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
describe '#comment?' do
|
|
342
|
+
let(:path) { 'test/files/comments.xlsx' }
|
|
343
|
+
|
|
344
|
+
it 'returns the expected result' do
|
|
345
|
+
expect(subject.comment?(4, 2)).to eq true
|
|
346
|
+
expect(subject.comment?(1, 2)).to eq false
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
describe '#comments' do
|
|
351
|
+
let(:path) { 'test/files/comments.xlsx' }
|
|
352
|
+
|
|
353
|
+
it 'returns the expected result' do
|
|
354
|
+
expect(subject.comments).to eq [[4, 2, "Kommentar fuer B4"], [5, 2, "Kommentar fuer B5"]]
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# nil, nil, nil, nil, nil
|
|
359
|
+
# nil, nil, nil, nil, nil
|
|
360
|
+
# Date Start time End time Pause Sum Comment
|
|
361
|
+
# 2007-05-07 9.25 10.25 0 1 Task 1
|
|
362
|
+
# 2007-05-07 10.75 12.50 0 1.75 Task 1
|
|
363
|
+
# 2007-05-07 18.00 19.00 0 1 Task 2
|
|
364
|
+
# 2007-05-08 9.25 10.25 0 1 Task 2
|
|
365
|
+
# 2007-05-08 14.50 15.50 0 1 Task 3
|
|
366
|
+
# 2007-05-08 8.75 9.25 0 0.5 Task 3
|
|
367
|
+
# 2007-05-14 21.75 22.25 0 0.5 Task 3
|
|
368
|
+
# 2007-05-14 22.50 23.00 0 0.5 Task 3
|
|
369
|
+
# 2007-05-15 11.75 12.75 0 1 Task 3
|
|
370
|
+
# 2007-05-07 10.75 10.75 0 0 Task 1
|
|
371
|
+
# nil
|
|
372
|
+
describe '#each_row_streaming' do
|
|
373
|
+
let(:path) { 'test/files/simple_spreadsheet.xlsx' }
|
|
374
|
+
|
|
375
|
+
let(:expected_rows) do
|
|
376
|
+
[
|
|
377
|
+
[nil, nil, nil, nil, nil],
|
|
378
|
+
[nil, nil, nil, nil, nil],
|
|
379
|
+
["Date", "Start time", "End time", "Pause", "Sum", "Comment", nil, nil],
|
|
380
|
+
[Date.new(2007, 5, 7), 9.25, 10.25, 0.0, 1.0, "Task 1"],
|
|
381
|
+
[Date.new(2007, 5, 7), 10.75, 12.50, 0.0, 1.75, "Task 1"],
|
|
382
|
+
[Date.new(2007, 5, 7), 18.0, 19.0, 0.0, 1.0, "Task 2"],
|
|
383
|
+
[Date.new(2007, 5, 8), 9.25, 10.25, 0.0, 1.0, "Task 2"],
|
|
384
|
+
[Date.new(2007, 5, 8), 14.5, 15.5, 0.0, 1.0, "Task 3"],
|
|
385
|
+
[Date.new(2007, 5, 8), 8.75, 9.25, 0.0, 0.5, "Task 3"],
|
|
386
|
+
[Date.new(2007, 5, 14), 21.75, 22.25, 0.0, 0.5, "Task 3"],
|
|
387
|
+
[Date.new(2007, 5, 14), 22.5, 23.0, 0.0, 0.5, "Task 3"],
|
|
388
|
+
[Date.new(2007, 5, 15), 11.75, 12.75, 0.0, 1.0, "Task 3"],
|
|
389
|
+
[Date.new(2007, 5, 7), 10.75, 10.75, 0.0, 0.0, "Task 1"],
|
|
390
|
+
[nil]
|
|
391
|
+
]
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
it 'returns the expected result' do
|
|
395
|
+
index = 0
|
|
396
|
+
subject.each_row_streaming do |row|
|
|
397
|
+
expect(row.map(&:value)).to eq expected_rows[index]
|
|
398
|
+
index += 1
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
context 'with max_rows options' do
|
|
403
|
+
it 'returns the expected result' do
|
|
404
|
+
index = 0
|
|
405
|
+
subject.each_row_streaming(max_rows: 3) do |row|
|
|
406
|
+
expect(row.map(&:value)).to eq expected_rows[index]
|
|
407
|
+
index += 1
|
|
34
408
|
end
|
|
409
|
+
# Expect this to get incremented one time more than max (because of the increment at the end of the block)
|
|
410
|
+
# but it should not be near expected_rows.size
|
|
411
|
+
expect(index).to eq 4
|
|
35
412
|
end
|
|
36
413
|
end
|
|
37
414
|
end
|
|
@@ -2,18 +2,28 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Roo::LibreOffice do
|
|
4
4
|
describe '.new' do
|
|
5
|
-
subject
|
|
5
|
+
subject do
|
|
6
6
|
Roo::LibreOffice.new('test/files/numbers1.ods')
|
|
7
|
-
|
|
7
|
+
end
|
|
8
8
|
|
|
9
9
|
it 'creates an instance' do
|
|
10
10
|
expect(subject).to be_a(Roo::LibreOffice)
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
|
-
end
|
|
14
13
|
|
|
15
|
-
describe
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
describe '#sheets' do
|
|
15
|
+
let(:path) { 'test/files/hidden_sheets.ods' }
|
|
16
|
+
|
|
17
|
+
describe 'showing all sheets' do
|
|
18
|
+
it 'returns the expected result' do
|
|
19
|
+
expect(Roo::LibreOffice.new(path).sheets).to eq ["HiddenSheet1", "VisibleSheet1", "HiddenSheet2"]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe 'only showing visible sheets' do
|
|
24
|
+
it 'returns the expected result' do
|
|
25
|
+
expect(Roo::LibreOffice.new(path, only_visible_sheets: true).sheets).to eq ["VisibleSheet1"]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
18
28
|
end
|
|
19
29
|
end
|
|
@@ -2,9 +2,9 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Roo::OpenOffice do
|
|
4
4
|
describe '.new' do
|
|
5
|
-
subject
|
|
5
|
+
subject do
|
|
6
6
|
Roo::OpenOffice.new('test/files/numbers1.ods')
|
|
7
|
-
|
|
7
|
+
end
|
|
8
8
|
|
|
9
9
|
it 'creates an instance' do
|
|
10
10
|
expect(subject).to be_a(Roo::OpenOffice)
|
|
@@ -13,9 +13,3 @@ describe Roo::OpenOffice do
|
|
|
13
13
|
|
|
14
14
|
# OpenOffice is an alias of LibreOffice. See libreoffice_spec.
|
|
15
15
|
end
|
|
16
|
-
|
|
17
|
-
describe Roo::Openoffice do
|
|
18
|
-
it 'is an alias of LibreOffice' do
|
|
19
|
-
expect(Roo::Openoffice).to eq(Roo::OpenOffice)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -2,15 +2,34 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Roo::Spreadsheet do
|
|
4
4
|
describe '.open' do
|
|
5
|
+
context 'when the file name includes a space' do
|
|
6
|
+
let(:filename) { 'great scott.xlsx' }
|
|
7
|
+
|
|
8
|
+
it 'loads the proper type' do
|
|
9
|
+
expect(Roo::Excelx).to receive(:new).with(filename, {})
|
|
10
|
+
Roo::Spreadsheet.open(filename)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
5
14
|
context 'when the file extension is uppercase' do
|
|
6
|
-
let(:filename) { 'file.
|
|
15
|
+
let(:filename) { 'file.XLSX' }
|
|
7
16
|
|
|
8
17
|
it 'loads the proper type' do
|
|
9
|
-
expect(Roo::
|
|
18
|
+
expect(Roo::Excelx).to receive(:new).with(filename, {})
|
|
10
19
|
Roo::Spreadsheet.open(filename)
|
|
11
20
|
end
|
|
12
21
|
end
|
|
13
22
|
|
|
23
|
+
context 'for a tempfile' do
|
|
24
|
+
let(:tempfile) { Tempfile.new('foo.csv') }
|
|
25
|
+
let(:filename) { tempfile.path }
|
|
26
|
+
|
|
27
|
+
it 'loads the proper type' do
|
|
28
|
+
expect(Roo::CSV).to receive(:new).with(filename, file_warning: :ignore).and_call_original
|
|
29
|
+
expect(Roo::Spreadsheet.open(tempfile, extension: :csv)).to be_a(Roo::CSV)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
14
33
|
context 'for a url' do
|
|
15
34
|
context 'that is csv' do
|
|
16
35
|
let(:filename) { 'http://example.com/file.csv?with=params#and=anchor' }
|
|
@@ -24,33 +43,42 @@ describe Roo::Spreadsheet do
|
|
|
24
43
|
|
|
25
44
|
context 'for a csv file' do
|
|
26
45
|
let(:filename) { 'file.csv' }
|
|
27
|
-
let(:options) { {csv_options: {col_sep: '"'}} }
|
|
46
|
+
let(:options) { { csv_options: { col_sep: '"' } } }
|
|
28
47
|
|
|
29
|
-
context 'with
|
|
30
|
-
it 'passes the
|
|
48
|
+
context 'with csv_options' do
|
|
49
|
+
it 'passes the csv_options through' do
|
|
31
50
|
expect(Roo::CSV).to receive(:new).with(filename, options)
|
|
32
51
|
Roo::Spreadsheet.open(filename, options)
|
|
33
52
|
end
|
|
34
53
|
end
|
|
35
54
|
end
|
|
36
55
|
|
|
37
|
-
context '
|
|
56
|
+
context 'with a file extension option' do
|
|
38
57
|
let(:filename) { 'file.xls' }
|
|
39
58
|
|
|
40
|
-
context
|
|
41
|
-
let(:options) { { extension:
|
|
59
|
+
context ':xlsx' do
|
|
60
|
+
let(:options) { { extension: :xlsx } }
|
|
61
|
+
|
|
62
|
+
it 'loads with xls extension options' do
|
|
63
|
+
expect(Roo::Excelx).to receive(:new).with(filename, options)
|
|
64
|
+
Roo::Spreadsheet.open(filename, options)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context 'xlsx' do
|
|
69
|
+
let(:options) { { extension: 'xlsx' } }
|
|
42
70
|
|
|
43
71
|
it 'loads with xls extension options' do
|
|
44
|
-
expect(Roo::
|
|
72
|
+
expect(Roo::Excelx).to receive(:new).with(filename, options)
|
|
45
73
|
Roo::Spreadsheet.open(filename, options)
|
|
46
74
|
end
|
|
47
75
|
end
|
|
48
76
|
|
|
49
|
-
context
|
|
50
|
-
let(:options) { { extension:
|
|
77
|
+
context '.xlsx' do
|
|
78
|
+
let(:options) { { extension: '.xlsx' } }
|
|
51
79
|
|
|
52
80
|
it 'loads with .xls extension options' do
|
|
53
|
-
expect(Roo::
|
|
81
|
+
expect(Roo::Excelx).to receive(:new).with(filename, options)
|
|
54
82
|
Roo::Spreadsheet.open(filename, options)
|
|
55
83
|
end
|
|
56
84
|
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe ::Roo::Utils do
|
|
4
|
+
subject { described_class }
|
|
5
|
+
|
|
6
|
+
context '#number_to_letter' do
|
|
7
|
+
('A'..'Z').to_a.each_with_index do |letter, index|
|
|
8
|
+
it "should return '#{ letter }' when passed #{ index + 1 }" do
|
|
9
|
+
expect(described_class.number_to_letter(index + 1)).to eq(letter)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
27 => 'AA', 26*2 => 'AZ', 26*3 => 'BZ', 26**2 + 26 => 'ZZ', 26**2 + 27 => 'AAA',
|
|
15
|
+
26**3 + 26**2 + 26 => 'ZZZ', 1.0 => 'A', 676 => 'YZ', 677 => 'ZA'
|
|
16
|
+
}.each do |key, value|
|
|
17
|
+
it "should return '#{value}' when passed #{key}" do
|
|
18
|
+
expect(described_class.number_to_letter(key)).to eq(value)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context '#letter_to_number' do
|
|
24
|
+
it "should give 1 for 'A' and 'a'" do
|
|
25
|
+
expect(described_class.letter_to_number('A')).to eq(1)
|
|
26
|
+
expect(described_class.letter_to_number('a')).to eq(1)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should give the correct value for 'Z'" do
|
|
30
|
+
expect(described_class.letter_to_number('Z')).to eq(26)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should give the correct value for 'AA' regardless of case mixing" do
|
|
34
|
+
%w(AA aA Aa aa).each do |key|
|
|
35
|
+
expect(described_class.letter_to_number(key)).to eq(27)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
{ 'AB' => 28, 'AZ' => 26*2, 'BZ' => 26*3, 'ZZ' => 26**2 + 26 }.each do |key, value|
|
|
40
|
+
it "should give the correct value for '#{key}'" do
|
|
41
|
+
expect(described_class.letter_to_number(key)).to eq(value)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context '.split_coordinate' do
|
|
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]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context '.split_coord' do
|
|
56
|
+
it "returns the expected result" do
|
|
57
|
+
expect(described_class.split_coord('A1')).to eq ["A", 1]
|
|
58
|
+
expect(described_class.split_coord('B2')).to eq ["B", 2]
|
|
59
|
+
expect(described_class.split_coord('R2')).to eq ["R", 2]
|
|
60
|
+
expect(described_class.split_coord('AR31')).to eq ["AR", 31]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "raises an error when appropriate" do
|
|
64
|
+
expect { described_class.split_coord('A') }.to raise_error(ArgumentError)
|
|
65
|
+
expect { described_class.split_coord('2') }.to raise_error(ArgumentError)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
context '.num_cells_in_range' do
|
|
71
|
+
it "returns the expected result" do
|
|
72
|
+
expect(described_class.num_cells_in_range('A1:B2')).to eq 4
|
|
73
|
+
expect(described_class.num_cells_in_range('B2:E3')).to eq 8
|
|
74
|
+
expect(described_class.num_cells_in_range('R2:Z10')).to eq 81
|
|
75
|
+
expect(described_class.num_cells_in_range('AR31:AR32')).to eq 2
|
|
76
|
+
expect(described_class.num_cells_in_range('A1')).to eq 1
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "raises an error when appropriate" do
|
|
80
|
+
expect { described_class.num_cells_in_range('A1:B1:B2') }.to raise_error(ArgumentError)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context '.load_xml' do
|
|
85
|
+
it 'returns the expected result' do
|
|
86
|
+
expect(described_class.load_xml('test/files/sheet1.xml')).to be_a(Nokogiri::XML::Document)
|
|
87
|
+
expect(described_class.load_xml('test/files/sheet1.xml').
|
|
88
|
+
remove_namespaces!.xpath("/worksheet/dimension").map do |dim|
|
|
89
|
+
dim.attributes["ref"].value end.first).to eq "A1:B11"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context '.each_element' do
|
|
94
|
+
it 'returns the expected result' do
|
|
95
|
+
described_class.each_element('test/files/sheet1.xml', 'dimension') do |dim|
|
|
96
|
+
expect(dim.attributes["ref"].value).to eq "A1:B11"
|
|
97
|
+
end
|
|
98
|
+
rows = []
|
|
99
|
+
described_class.each_element('test/files/sheet1.xml', 'row') do |row|
|
|
100
|
+
rows << row
|
|
101
|
+
end
|
|
102
|
+
expect(rows.size).to eq 11
|
|
103
|
+
expect(rows[2].attributes["r"].value).to eq "3"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
data/spec/spec_helper.rb
CHANGED