roo 2.0.1 → 2.7.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.
- 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
|