roo 2.0.1 → 2.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +17 -0
- data/.github/ISSUE_TEMPLATE +10 -0
- data/.gitignore +4 -0
- data/.travis.yml +10 -6
- data/CHANGELOG.md +116 -1
- data/Gemfile +3 -4
- data/Gemfile_ruby2 +30 -0
- data/Guardfile +1 -2
- data/README.md +56 -22
- data/Rakefile +1 -1
- data/lib/roo/base.rb +108 -245
- data/lib/roo/constants.rb +5 -0
- data/lib/roo/csv.rb +94 -87
- data/lib/roo/errors.rb +11 -0
- data/lib/roo/excelx/cell/base.rb +94 -0
- data/lib/roo/excelx/cell/boolean.rb +27 -0
- data/lib/roo/excelx/cell/date.rb +28 -0
- data/lib/roo/excelx/cell/datetime.rb +111 -0
- data/lib/roo/excelx/cell/empty.rb +19 -0
- data/lib/roo/excelx/cell/number.rb +87 -0
- data/lib/roo/excelx/cell/string.rb +19 -0
- data/lib/roo/excelx/cell/time.rb +43 -0
- data/lib/roo/excelx/cell.rb +33 -4
- data/lib/roo/excelx/comments.rb +33 -0
- data/lib/roo/excelx/coordinate.rb +12 -0
- data/lib/roo/excelx/extractor.rb +3 -4
- data/lib/roo/excelx/format.rb +64 -0
- data/lib/roo/excelx/shared.rb +32 -0
- data/lib/roo/excelx/shared_strings.rb +124 -4
- data/lib/roo/excelx/sheet.rb +12 -7
- data/lib/roo/excelx/sheet_doc.rb +108 -97
- data/lib/roo/excelx/styles.rb +1 -1
- data/lib/roo/excelx.rb +61 -103
- data/lib/roo/formatters/base.rb +15 -0
- data/lib/roo/formatters/csv.rb +84 -0
- data/lib/roo/formatters/matrix.rb +23 -0
- data/lib/roo/formatters/xml.rb +31 -0
- data/lib/roo/formatters/yaml.rb +40 -0
- data/lib/roo/libre_office.rb +1 -2
- data/lib/roo/link.rb +21 -2
- data/lib/roo/open_office.rb +468 -523
- data/lib/roo/spreadsheet.rb +3 -1
- data/lib/roo/tempdir.rb +21 -0
- data/lib/roo/utils.rb +7 -7
- data/lib/roo/version.rb +1 -1
- data/lib/roo.rb +8 -3
- data/roo.gemspec +2 -1
- data/spec/helpers.rb +5 -0
- data/spec/lib/roo/base_spec.rb +229 -0
- data/spec/lib/roo/csv_spec.rb +19 -0
- data/spec/lib/roo/excelx_spec.rb +97 -11
- data/spec/lib/roo/openoffice_spec.rb +18 -1
- data/spec/lib/roo/spreadsheet_spec.rb +20 -0
- data/spec/lib/roo/utils_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -5
- data/test/all_ss.rb +12 -11
- data/test/excelx/cell/test_base.rb +63 -0
- data/test/excelx/cell/test_boolean.rb +36 -0
- data/test/excelx/cell/test_date.rb +38 -0
- data/test/excelx/cell/test_datetime.rb +45 -0
- data/test/excelx/cell/test_empty.rb +7 -0
- data/test/excelx/cell/test_number.rb +74 -0
- data/test/excelx/cell/test_string.rb +28 -0
- data/test/excelx/cell/test_time.rb +30 -0
- data/test/formatters/test_csv.rb +119 -0
- data/test/formatters/test_matrix.rb +76 -0
- data/test/formatters/test_xml.rb +78 -0
- data/test/formatters/test_yaml.rb +20 -0
- data/test/helpers/test_accessing_files.rb +60 -0
- data/test/helpers/test_comments.rb +43 -0
- data/test/helpers/test_formulas.rb +9 -0
- data/test/helpers/test_labels.rb +103 -0
- data/test/helpers/test_sheets.rb +55 -0
- data/test/helpers/test_styles.rb +62 -0
- data/test/roo/test_base.rb +182 -0
- data/test/roo/test_csv.rb +60 -0
- data/test/roo/test_excelx.rb +325 -0
- data/test/roo/test_libre_office.rb +9 -0
- data/test/roo/test_open_office.rb +289 -0
- data/test/test_helper.rb +116 -18
- data/test/test_roo.rb +362 -2088
- metadata +70 -4
- data/test/test_generic_spreadsheet.rb +0 -237
data/lib/roo/spreadsheet.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
1
3
|
module Roo
|
2
4
|
class Spreadsheet
|
3
5
|
class << self
|
@@ -22,7 +24,7 @@ module Roo
|
|
22
24
|
options[:file_warning] = :ignore
|
23
25
|
extension.tr('.', '').downcase.to_sym
|
24
26
|
else
|
25
|
-
res = ::File.extname((path =~ ::URI.regexp) ? ::URI.parse(::URI.encode(path)).path : path)
|
27
|
+
res = ::File.extname((path =~ /\A#{::URI.regexp}\z/) ? ::URI.parse(::URI.encode(path)).path : path)
|
26
28
|
res.tr('.', '').downcase.to_sym
|
27
29
|
end
|
28
30
|
end
|
data/lib/roo/tempdir.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Roo
|
2
|
+
module Tempdir
|
3
|
+
def finalize_tempdirs(object_id)
|
4
|
+
if @tempdirs && (dirs_to_remove = @tempdirs[object_id])
|
5
|
+
@tempdirs.delete(object_id)
|
6
|
+
dirs_to_remove.each do |dir|
|
7
|
+
::FileUtils.remove_entry(dir)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def make_tempdir(object, prefix, root)
|
13
|
+
root ||= ENV["ROO_TMP"]
|
14
|
+
# NOTE: This folder is cleaned up by finalize_tempdirs.
|
15
|
+
::Dir.mktmpdir("#{Roo::TEMP_PREFIX}#{prefix}", root).tap do |tmpdir|
|
16
|
+
@tempdirs ||= Hash.new { |h, k| h[k] = [] }
|
17
|
+
@tempdirs[object.object_id] << tmpdir
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/roo/utils.rb
CHANGED
@@ -2,6 +2,8 @@ module Roo
|
|
2
2
|
module Utils
|
3
3
|
extend self
|
4
4
|
|
5
|
+
LETTERS = ('A'..'Z').to_a
|
6
|
+
|
5
7
|
def split_coordinate(str)
|
6
8
|
@split_coordinate ||= {}
|
7
9
|
|
@@ -27,16 +29,14 @@ module Roo
|
|
27
29
|
|
28
30
|
# convert a number to something like 'AB' (1 => 'A', 2 => 'B', ...)
|
29
31
|
def number_to_letter(num)
|
30
|
-
|
31
|
-
num = num.to_i
|
32
|
+
result = ""
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
num = ((num - mod) / 26)
|
34
|
+
until num.zero?
|
35
|
+
num, index = (num - 1).divmod(26)
|
36
|
+
result.prepend(LETTERS[index])
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
result
|
40
40
|
end
|
41
41
|
|
42
42
|
def letter_to_number(letters)
|
data/lib/roo/version.rb
CHANGED
data/lib/roo.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'roo/constants'
|
2
|
+
require 'roo/errors'
|
1
3
|
require 'roo/spreadsheet'
|
2
4
|
require 'roo/base'
|
3
5
|
|
@@ -7,20 +9,23 @@ module Roo
|
|
7
9
|
autoload :Excelx, 'roo/excelx'
|
8
10
|
autoload :CSV, 'roo/csv'
|
9
11
|
|
12
|
+
TEMP_PREFIX = 'roo_'.freeze
|
13
|
+
|
10
14
|
CLASS_FOR_EXTENSION = {
|
11
15
|
ods: Roo::OpenOffice,
|
12
16
|
xlsx: Roo::Excelx,
|
17
|
+
xlsm: Roo::Excelx,
|
13
18
|
csv: Roo::CSV
|
14
19
|
}
|
15
20
|
|
16
21
|
def self.const_missing(const_name)
|
17
22
|
case const_name
|
18
23
|
when :Excel
|
19
|
-
raise
|
24
|
+
raise ROO_EXCEL_NOTICE
|
20
25
|
when :Excel2003XML
|
21
|
-
raise
|
26
|
+
raise ROO_EXCELML_NOTICE
|
22
27
|
when :Google
|
23
|
-
raise
|
28
|
+
raise ROO_GOOGLE_NOTICE
|
24
29
|
else
|
25
30
|
super
|
26
31
|
end
|
data/roo.gemspec
CHANGED
@@ -6,7 +6,7 @@ require 'roo/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'roo'
|
8
8
|
spec.version = Roo::VERSION
|
9
|
-
spec.authors = ['Thomas Preymesser', 'Hugh McGowan', 'Ben Woosley', 'Oleksandr Simonov']
|
9
|
+
spec.authors = ['Thomas Preymesser', 'Hugh McGowan', 'Ben Woosley', 'Oleksandr Simonov', 'Steven Daniels']
|
10
10
|
spec.email = ['ruby.ruby.ruby.roo@gmail.com', 'oleksandr@simonov.me']
|
11
11
|
spec.summary = 'Roo can access the contents of various spreadsheet files.'
|
12
12
|
spec.description = "Roo can access the contents of various spreadsheet files. It can handle\n* OpenOffice\n* Excelx\n* LibreOffice\n* CSV"
|
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.add_development_dependency 'rake', '~> 10.1'
|
24
24
|
spec.add_development_dependency 'minitest', '~> 5.4', '>= 5.4.3'
|
25
|
+
spec.add_development_dependency 'rack', '~> 1.6', '< 2.0.0'
|
25
26
|
end
|
data/spec/helpers.rb
ADDED
data/spec/lib/roo/base_spec.rb
CHANGED
@@ -1,4 +1,233 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Roo::Base do
|
4
|
+
let(:klass) do
|
5
|
+
Class.new(Roo::Base) do
|
6
|
+
def initialize(filename, data = {})
|
7
|
+
super(filename)
|
8
|
+
@data ||= data
|
9
|
+
end
|
10
|
+
|
11
|
+
def read_cells(sheet = default_sheet)
|
12
|
+
return if @cells_read[sheet]
|
13
|
+
type_map = { String => :string, Date => :date, Numeric => :float }
|
14
|
+
|
15
|
+
@cell[sheet] = @data
|
16
|
+
@cell_type[sheet] = Hash[@data.map { |k, v| [k, type_map.find {|type,_| v.is_a?(type) }.last ] }]
|
17
|
+
@first_row[sheet] = @data.map { |k, _| k[0] }.min
|
18
|
+
@last_row[sheet] = @data.map { |k, _| k[0] }.max
|
19
|
+
@first_column[sheet] = @data.map { |k, _| k[1] }.min
|
20
|
+
@last_column[sheet] = @data.map { |k, _| k[1] }.max
|
21
|
+
@cells_read[sheet] = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def cell(row, col, sheet = nil)
|
25
|
+
sheet ||= default_sheet
|
26
|
+
read_cells(sheet)
|
27
|
+
@cell[sheet][[row, col]]
|
28
|
+
end
|
29
|
+
|
30
|
+
def celltype(row, col, sheet = nil)
|
31
|
+
sheet ||= default_sheet
|
32
|
+
read_cells(sheet)
|
33
|
+
@cell_type[sheet][[row, col]]
|
34
|
+
end
|
35
|
+
|
36
|
+
def sheets
|
37
|
+
['my_sheet', 'blank sheet']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:spreadsheet_data) do
|
43
|
+
{
|
44
|
+
[3, 1] => 'Header',
|
45
|
+
|
46
|
+
[5, 1] => Date.civil(1961, 11, 21),
|
47
|
+
|
48
|
+
[8, 3] => 'thisisc8',
|
49
|
+
[8, 7] => 'thisisg8',
|
50
|
+
|
51
|
+
[12, 1] => 41.0,
|
52
|
+
[12, 2] => 42.0,
|
53
|
+
[12, 3] => 43.0,
|
54
|
+
[12, 4] => 44.0,
|
55
|
+
[12, 5] => 45.0,
|
56
|
+
|
57
|
+
[15, 3] => 43.0,
|
58
|
+
[15, 4] => 44.0,
|
59
|
+
[15, 5] => 45.0,
|
60
|
+
|
61
|
+
[16, 2] => '"Hello world!"',
|
62
|
+
[16, 3] => 'forty-three',
|
63
|
+
[16, 4] => 'forty-four',
|
64
|
+
[16, 5] => 'forty-five'
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
let(:spreadsheet) { klass.new('some_file', spreadsheet_data) }
|
69
|
+
|
70
|
+
describe '#uri?' do
|
71
|
+
it 'should return true when passed a filename starting with http(s)://' do
|
72
|
+
expect(spreadsheet.send(:uri?, 'http://example.com/')).to be_truthy
|
73
|
+
expect(spreadsheet.send(:uri?, 'https://example.com/')).to be_truthy
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should return false when passed a filename which does not start with http(s)://' do
|
77
|
+
expect(spreadsheet.send(:uri?, 'example.com')).to be_falsy
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should return false when passed non-String object such as Tempfile' do
|
81
|
+
expect(spreadsheet.send(:uri?, Tempfile.new('test'))).to be_falsy
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#set' do
|
86
|
+
it 'should not update cell when setting an invalid type' do
|
87
|
+
spreadsheet.set(1, 1, 1)
|
88
|
+
expect { spreadsheet.set(1, 1, :invalid_type) }.to raise_error(ArgumentError)
|
89
|
+
expect(spreadsheet.cell(1, 1)).to eq(1)
|
90
|
+
expect(spreadsheet.celltype(1, 1)).to eq(:float)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#first_row' do
|
95
|
+
it 'should return the first row' do
|
96
|
+
expect(spreadsheet.first_row).to eq(3)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#last_row' do
|
101
|
+
it 'should return the last row' do
|
102
|
+
expect(spreadsheet.last_row).to eq(16)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#first_column' do
|
107
|
+
it 'should return the first column' do
|
108
|
+
expect(spreadsheet.first_column).to eq(1)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#first_column_as_letter' do
|
113
|
+
it 'should return the first column as a letter' do
|
114
|
+
expect(spreadsheet.first_column_as_letter).to eq('A')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#last_column' do
|
119
|
+
it 'should return the last column' do
|
120
|
+
expect(spreadsheet.last_column).to eq(7)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#last_column_as_letter' do
|
125
|
+
it 'should return the last column as a letter' do
|
126
|
+
expect(spreadsheet.last_column_as_letter).to eq('G')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#row' do
|
131
|
+
it 'should return the specified row' do
|
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])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#row_with' do
|
138
|
+
context 'with a matching header row' do
|
139
|
+
it 'returns the row number' do
|
140
|
+
expect(spreadsheet.row_with([/Header/])). to eq 3
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'without a matching header row' do
|
145
|
+
it 'raises an error' do
|
146
|
+
expect { spreadsheet.row_with([/Missing Header/]) }.to \
|
147
|
+
raise_error(Roo::HeaderRowNotFoundError)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe '#empty?' do
|
153
|
+
it 'should return true when empty' do
|
154
|
+
expect(spreadsheet.empty?(1, 1)).to be_truthy
|
155
|
+
expect(spreadsheet.empty?(8, 3)).to be_falsy
|
156
|
+
expect(spreadsheet.empty?('A', 11)).to be_truthy
|
157
|
+
expect(spreadsheet.empty?('A', 12)).to be_falsy
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#reload' do
|
162
|
+
it 'should return reinitialize the spreadsheet' do
|
163
|
+
spreadsheet.reload
|
164
|
+
expect(spreadsheet.instance_variable_get(:@cell).empty?).to be_truthy
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#each' do
|
169
|
+
it 'should return an enumerator with all the rows' do
|
170
|
+
each = spreadsheet.each
|
171
|
+
expect(each).to be_a(Enumerator)
|
172
|
+
expect(each.to_a.last).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil])
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe '#to_yaml' do
|
177
|
+
it 'should convert the spreadsheet to yaml' do
|
178
|
+
expect(spreadsheet.to_yaml({}, 5, 1, 5, 1)).to eq("--- \n" + yaml_entry(5, 1, 'date', '1961-11-21'))
|
179
|
+
expect(spreadsheet.to_yaml({}, 8, 3, 8, 3)).to eq("--- \n" + yaml_entry(8, 3, 'string', 'thisisc8'))
|
180
|
+
|
181
|
+
expect(spreadsheet.to_yaml({}, 12, 3, 12, 3)).to eq("--- \n" + yaml_entry(12, 3, 'float', 43.0))
|
182
|
+
|
183
|
+
expect(spreadsheet.to_yaml({}, 12, 3, 12)).to eq(
|
184
|
+
"--- \n" + yaml_entry(12, 3, 'float', 43.0) +
|
185
|
+
yaml_entry(12, 4, 'float', 44.0) +
|
186
|
+
yaml_entry(12, 5, 'float', 45.0))
|
187
|
+
|
188
|
+
expect(spreadsheet.to_yaml({}, 12, 3)).to eq(
|
189
|
+
"--- \n" + yaml_entry(12, 3, 'float', 43.0) +
|
190
|
+
yaml_entry(12, 4, 'float', 44.0) +
|
191
|
+
yaml_entry(12, 5, 'float', 45.0) +
|
192
|
+
yaml_entry(15, 3, 'float', 43.0) +
|
193
|
+
yaml_entry(15, 4, 'float', 44.0) +
|
194
|
+
yaml_entry(15, 5, 'float', 45.0) +
|
195
|
+
yaml_entry(16, 3, 'string', 'forty-three') +
|
196
|
+
yaml_entry(16, 4, 'string', 'forty-four') +
|
197
|
+
yaml_entry(16, 5, 'string', 'forty-five'))
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
let(:expected_csv) do
|
202
|
+
<<EOS
|
203
|
+
,,,,,,
|
204
|
+
,,,,,,
|
205
|
+
"Header",,,,,,
|
206
|
+
,,,,,,
|
207
|
+
1961-11-21,,,,,,
|
208
|
+
,,,,,,
|
209
|
+
,,,,,,
|
210
|
+
,,"thisisc8",,,,"thisisg8"
|
211
|
+
,,,,,,
|
212
|
+
,,,,,,
|
213
|
+
,,,,,,
|
214
|
+
41,42,43,44,45,,
|
215
|
+
,,,,,,
|
216
|
+
,,,,,,
|
217
|
+
,,43,44,45,,
|
218
|
+
,"""Hello world!""","forty-three","forty-four","forty-five",,
|
219
|
+
EOS
|
220
|
+
end
|
221
|
+
|
222
|
+
let(:expected_csv_with_semicolons) { expected_csv.gsub(/\,/, ';') }
|
223
|
+
|
224
|
+
describe '#to_csv' do
|
225
|
+
it 'should convert the spreadsheet to csv' do
|
226
|
+
expect(spreadsheet.to_csv).to eq(expected_csv)
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should convert the spreadsheet to csv using the separator when is passed on the parameter' do
|
230
|
+
expect(spreadsheet.to_csv(nil, ';')).to eq(expected_csv_with_semicolons)
|
231
|
+
end
|
232
|
+
end
|
4
233
|
end
|
data/spec/lib/roo/csv_spec.rb
CHANGED
@@ -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
|
data/spec/lib/roo/excelx_spec.rb
CHANGED
@@ -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
|
@@ -58,7 +69,11 @@ describe Roo::Excelx do
|
|
58
69
|
|
59
70
|
it 'returns a link with the number as a string value' do
|
60
71
|
expect(subject).to be_a(Roo::Link)
|
61
|
-
|
72
|
+
# FIXME: Because Link inherits from String, it is a String,
|
73
|
+
# But in theory, it shouldn't have to be a String.
|
74
|
+
# NOTE: This test is broken becase Cell::Numeric formats numbers
|
75
|
+
# more intelligently.
|
76
|
+
# expect(subject).to eq('8675309.0')
|
62
77
|
end
|
63
78
|
end
|
64
79
|
end
|
@@ -82,7 +97,7 @@ describe Roo::Excelx do
|
|
82
97
|
this: 'This',
|
83
98
|
that: 'That'
|
84
99
|
)
|
85
|
-
end.to raise_error(
|
100
|
+
end.to raise_error(Roo::HeaderRowNotFoundError)
|
86
101
|
end
|
87
102
|
end
|
88
103
|
end
|
@@ -107,16 +122,12 @@ describe Roo::Excelx do
|
|
107
122
|
let(:options) { {clean: true, name: 'Name'} }
|
108
123
|
|
109
124
|
context 'with clean: true' do
|
110
|
-
|
111
125
|
it 'returns a non empty string' do
|
112
126
|
expect(xlsx.parse(options).last[:name]).to eql('凯')
|
113
127
|
end
|
114
128
|
end
|
115
129
|
end
|
116
130
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
131
|
describe '#sheets' do
|
121
132
|
let(:path) { 'test/files/numbers1.xlsx' }
|
122
133
|
|
@@ -191,7 +202,6 @@ describe Roo::Excelx do
|
|
191
202
|
end
|
192
203
|
|
193
204
|
describe '#set' do
|
194
|
-
|
195
205
|
before do
|
196
206
|
subject.set(1, 2, "Foo", "Sheet5")
|
197
207
|
end
|
@@ -268,15 +278,29 @@ describe Roo::Excelx do
|
|
268
278
|
end
|
269
279
|
end
|
270
280
|
|
281
|
+
# FIXME: IMO, these tests don't provide much value. Under what circumstances
|
282
|
+
# will a user require the "index" value for the shared strings table?
|
283
|
+
# Excel value should be the raw unformatted value for the cell.
|
271
284
|
describe '#excelx_value' do
|
272
285
|
let(:path) { 'test/files/numbers1.xlsx' }
|
273
286
|
|
274
287
|
it 'returns the expected result' do
|
275
288
|
# These values are the index in the shared strings table, might be a better
|
276
289
|
# way to get these rather than hardcoding.
|
277
|
-
|
278
|
-
expect(subject.excelx_value(
|
279
|
-
expect(subject.excelx_value(
|
290
|
+
|
291
|
+
# expect(subject.excelx_value(1, 1, "Sheet5")).to eq "1" # passes by accident
|
292
|
+
# expect(subject.excelx_value(6, 2, "Sheet5")).to eq "16"
|
293
|
+
# expect(subject.excelx_value(6000, 2000, "Sheet5")).to eq nil
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
describe '#formatted_value' do
|
298
|
+
context 'contains zero-padded numbers' do
|
299
|
+
let(:path) { 'test/files/zero-padded-number.xlsx' }
|
300
|
+
|
301
|
+
it 'returns a zero-padded number' do
|
302
|
+
expect(subject.formatted_value(4, 1)).to eq '05010'
|
303
|
+
end
|
280
304
|
end
|
281
305
|
end
|
282
306
|
|
@@ -447,5 +471,67 @@ describe Roo::Excelx do
|
|
447
471
|
expect(index).to eq 4
|
448
472
|
end
|
449
473
|
end
|
474
|
+
|
475
|
+
context 'without block passed' do
|
476
|
+
it 'returns an enumerator' do
|
477
|
+
expect(subject.each_row_streaming).to be_a(Enumerator)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
describe '#html_strings' do
|
483
|
+
let(:path) { 'test/files/html_strings_formatting.xlsx' }
|
484
|
+
|
485
|
+
it 'returns the expected result' do
|
486
|
+
expect(subject.excelx_value(1, 1, "Sheet1")).to eq "This has no formatting."
|
487
|
+
expect(subject.excelx_value(2, 1, "Sheet1")).to eq "<html>This has<b> bold </b>formatting.</html>"
|
488
|
+
expect(subject.excelx_value(2, 2, "Sheet1")).to eq "<html>This has <i>italics</i> formatting.</html>"
|
489
|
+
expect(subject.excelx_value(2, 3, "Sheet1")).to eq "<html>This has <u>underline</u> format.</html>"
|
490
|
+
expect(subject.excelx_value(2, 4, "Sheet1")).to eq "<html>Superscript. x<sup>123</sup></html>"
|
491
|
+
expect(subject.excelx_value(2, 5, "Sheet1")).to eq "<html>SubScript. T<sub>j</sub></html>"
|
492
|
+
|
493
|
+
expect(subject.excelx_value(3, 1, "Sheet1")).to eq "<html>Bold, italics <b><i>together</i></b>.</html>"
|
494
|
+
expect(subject.excelx_value(3, 2, "Sheet1")).to eq "<html>Bold, Underline <b><u>together</u></b>.</html>"
|
495
|
+
expect(subject.excelx_value(3, 3, "Sheet1")).to eq "<html>Bold, Superscript. <b>x</b><sup><b>N</b></sup></html>"
|
496
|
+
expect(subject.excelx_value(3, 4, "Sheet1")).to eq "<html>Bold, Subscript. <b>T</b><sub><b>abc</b></sub></html>"
|
497
|
+
expect(subject.excelx_value(3, 5, "Sheet1")).to eq "<html>Italics, Underline <i><u>together</u></i>.</html>"
|
498
|
+
expect(subject.excelx_value(3, 6, "Sheet1")).to eq "<html>Italics, Superscript. <i>X</i><sup><i>abc</i></sup></html>"
|
499
|
+
expect(subject.excelx_value(3, 7, "Sheet1")).to eq "<html>Italics, Subscript. <i>B</i><sub><i>efg</i></sub></html>"
|
500
|
+
expect(subject.excelx_value(4, 1, "Sheet1")).to eq "<html>Bold, italics underline,<b><i><u> together</u></i></b>.</html>"
|
501
|
+
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>"
|
502
|
+
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>"
|
503
|
+
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>"
|
504
|
+
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>"
|
505
|
+
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>"
|
506
|
+
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>"
|
507
|
+
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>"
|
508
|
+
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>"
|
509
|
+
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>"
|
510
|
+
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>"
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
describe '_x000D_' do
|
515
|
+
let(:path) { 'test/files/x000D.xlsx' }
|
516
|
+
it 'does not contain _x000D_' do
|
517
|
+
expect(subject.cell(2, 9)).not_to include('_x000D_')
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
describe 'opening a file with a chart sheet' do
|
522
|
+
let(:path) { 'test/files/chart_sheet.xlsx' }
|
523
|
+
it 'should not raise' do
|
524
|
+
expect{ subject }.to_not raise_error
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
describe 'opening a file with white space in the styles.xml' do
|
529
|
+
let(:path) { 'test/files/style_nodes_with_white_spaces.xlsx' }
|
530
|
+
subject(:xlsx) do
|
531
|
+
Roo::Spreadsheet.open(path, expand_merged_ranges: true, extension: :xlsx)
|
532
|
+
end
|
533
|
+
it 'should properly recognize formats' do
|
534
|
+
expect(subject.sheet(0).excelx_format(2,1)).to eq 'm/d/yyyy" "h:mm:ss" "AM/PM'
|
535
|
+
end
|
450
536
|
end
|
451
537
|
end
|
@@ -10,6 +10,23 @@ describe Roo::OpenOffice do
|
|
10
10
|
expect(subject).to be_a(Roo::OpenOffice)
|
11
11
|
end
|
12
12
|
|
13
|
+
context 'for float/integer values' do
|
14
|
+
context 'integer without point' do
|
15
|
+
it { expect(subject.cell(3,"A","Sheet4")).to eq(1234) }
|
16
|
+
it { expect(subject.cell(3,"A","Sheet4")).to be_a(Integer) }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'float with point' do
|
20
|
+
it { expect(subject.cell(3,"B","Sheet4")).to eq(1234.00) }
|
21
|
+
it { expect(subject.cell(3,"B","Sheet4")).to be_a(Float) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'float with point' do
|
25
|
+
it { expect(subject.cell(3,"C","Sheet4")).to eq(1234.12) }
|
26
|
+
it { expect(subject.cell(3,"C","Sheet4")).to be_a(Float) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
13
30
|
context 'file path is a Pathname' do
|
14
31
|
subject do
|
15
32
|
Roo::OpenOffice.new(Pathname.new('test/files/numbers1.ods'))
|
@@ -19,7 +36,7 @@ describe Roo::OpenOffice do
|
|
19
36
|
expect(subject).to be_a(Roo::OpenOffice)
|
20
37
|
end
|
21
38
|
end
|
22
|
-
|
39
|
+
|
23
40
|
end
|
24
41
|
|
25
42
|
# OpenOffice is an alias of LibreOffice. See libreoffice_spec.
|
@@ -41,6 +41,26 @@ describe Roo::Spreadsheet do
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
context 'for a windows path' do
|
45
|
+
context 'that is xlsx' do
|
46
|
+
let(:filename) { 'c:\Users\Joe\Desktop\myfile.xlsx' }
|
47
|
+
|
48
|
+
it 'loads the proper type' do
|
49
|
+
expect(Roo::Excelx).to receive(:new).with(filename, {})
|
50
|
+
Roo::Spreadsheet.open(filename)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'for a xlsm file' do
|
56
|
+
let(:filename) { 'macros spreadsheet.xlsm' }
|
57
|
+
|
58
|
+
it 'loads the proper type' do
|
59
|
+
expect(Roo::Excelx).to receive(:new).with(filename, {})
|
60
|
+
Roo::Spreadsheet.open(filename)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
44
64
|
context 'for a csv file' do
|
45
65
|
let(:filename) { 'file.csv' }
|
46
66
|
let(:options) { { csv_options: { col_sep: '"' } } }
|
data/spec/lib/roo/utils_spec.rb
CHANGED
@@ -4,7 +4,7 @@ RSpec.describe ::Roo::Utils do
|
|
4
4
|
subject { described_class }
|
5
5
|
|
6
6
|
context '#number_to_letter' do
|
7
|
-
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'simplecov'
|
2
2
|
require 'roo'
|
3
|
+
require 'helpers'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
c.
|
8
|
-
c.hook_into :webmock # or :fakeweb
|
5
|
+
RSpec.configure do |c|
|
6
|
+
c.include Helpers
|
7
|
+
c.color = true
|
8
|
+
c.formatter = :documentation if ENV["USE_REPORTERS"]
|
9
9
|
end
|
data/test/all_ss.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
require 'roo'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
1
|
+
require 'roo'
|
2
|
+
|
3
|
+
Dir.glob('test/files/*.ods').each do |fn|
|
4
|
+
begin
|
5
|
+
oo = Roo::OpenOffice.new fn
|
6
|
+
print "#{File.basename(fn)} "
|
7
|
+
puts oo.officeversion
|
8
|
+
rescue Zip::ZipError, Errno::ENOENT => e
|
9
|
+
# file is not a real .ods spreadsheet file
|
10
|
+
puts e.message
|
11
|
+
end
|
12
|
+
end
|