roo 2.1.0 → 2.1.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/CHANGELOG.md +4 -0
- data/README.md +4 -7
- data/lib/roo/base.rb +74 -77
- data/lib/roo/excelx/shared_strings.rb +10 -0
- data/lib/roo/spreadsheet.rb +2 -0
- data/lib/roo/version.rb +1 -1
- data/spec/helpers.rb +5 -0
- data/spec/lib/roo/base_spec.rb +212 -0
- data/spec/lib/roo/excelx_spec.rb +7 -0
- data/spec/spec_helper.rb +6 -1
- data/test/test_helper.rb +0 -4
- metadata +9 -8
- data/test/test_generic_spreadsheet.rb +0 -237
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 53d37d09a786f9536fd5bb00c7cacf9888c8b032
|
|
4
|
+
data.tar.gz: 284974b328b26668c58e3b952a12b8777439037f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4b0e6d58d52600710fc5feb49e7483fc81e4bca65fa9013a3fa1004f5526107392b02f982ae981676544e301056a0246b4b85e38d3959565174c247ce49695a9
|
|
7
|
+
data.tar.gz: 5c3beb6580bece8aa730d1f29b6316889ebb7ce5a7003d8f654edcb1c9800a9f939021fd0d88749489ffdee6ebf496739664e5fede43aeb0067a2a16ad46f2f5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## [2.1.1] - 2015-08-02
|
|
2
|
+
### Fixed invalid new lines with _x000D_ character[#231](https://github.com/roo-rb/roo/pull/231)
|
|
3
|
+
### Fixed missing URI issue. [#245](https://github.com/roo-rb/roo/pull/245)
|
|
4
|
+
|
|
1
5
|
## [2.1.0] - 2015-07-18
|
|
2
6
|
### Added
|
|
3
7
|
- Added support for Excel 2007 `xlsm` files. [#232](https://github.com/roo-rb/roo/pull/232)
|
data/README.md
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
[](https://travis-ci.org/roo-rb/roo) [](https://codeclimate.com/github/roo-rb/roo) [](https://coveralls.io/r/roo-rb/roo) [](https://rubygems.org/gems/roo)
|
|
4
4
|
|
|
5
5
|
Roo implements read access for all common spreadsheet types. It can handle:
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* OpenOffice / LibreOffice
|
|
6
|
+
* Excel 2007 - 2013 formats (xlsx, xlsm)
|
|
7
|
+
* LibreOffice / OpenOffice.org formats (ods)
|
|
9
8
|
* CSV
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
In addition, the [roo-xls](https://github.com/roo-rb/roo-xls) and [roo-google](https://github.com/roo-rb/roo-google) gems exist to extend Roo to support reading classic Excel formats (i.e. `.xls` and ``Excel2003XML``) and read/write access for Google spreadsheets.
|
|
9
|
+
* Excel 97, Excel 2002 XML, and Excel 2003 XML formats when using the [roo-xls](https://github.com/roo-rb/roo-xls) gem (xls, xml)
|
|
10
|
+
* Google spreadsheets with read/write access when using [roo-google](https://github.com/roo-rb/roo-google)
|
|
14
11
|
|
|
15
12
|
## Installation
|
|
16
13
|
|
data/lib/roo/base.rb
CHANGED
|
@@ -91,7 +91,7 @@ class Roo::Base
|
|
|
91
91
|
first_column = [first_column, key.last.to_i].min
|
|
92
92
|
last_column = [last_column, key.last.to_i].max
|
|
93
93
|
end if @cell[sheet]
|
|
94
|
-
{first_row: first_row, first_column: first_column, last_row: last_row, last_column: last_column}
|
|
94
|
+
{ first_row: first_row, first_column: first_column, last_row: last_row, last_column: last_column }
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
%w(first_row last_row first_column last_column).each do |key|
|
|
@@ -117,22 +117,23 @@ class Roo::Base
|
|
|
117
117
|
result = "--- \n"
|
|
118
118
|
from_row.upto(to_row) do |row|
|
|
119
119
|
from_column.upto(to_column) do |col|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
result << " value: #{value} \n"
|
|
120
|
+
next if empty?(row, col, sheet)
|
|
121
|
+
|
|
122
|
+
result << "cell_#{row}_#{col}: \n"
|
|
123
|
+
prefix.each do|k, v|
|
|
124
|
+
result << " #{k}: #{v} \n"
|
|
125
|
+
end
|
|
126
|
+
result << " row: #{row} \n"
|
|
127
|
+
result << " col: #{col} \n"
|
|
128
|
+
result << " celltype: #{celltype(row, col, sheet)} \n"
|
|
129
|
+
value = cell(row, col, sheet)
|
|
130
|
+
if celltype(row, col, sheet) == :time
|
|
131
|
+
value = integer_to_timestring(value)
|
|
133
132
|
end
|
|
133
|
+
result << " value: #{value} \n"
|
|
134
134
|
end
|
|
135
135
|
end
|
|
136
|
+
|
|
136
137
|
result
|
|
137
138
|
end
|
|
138
139
|
|
|
@@ -170,7 +171,7 @@ class Roo::Base
|
|
|
170
171
|
end
|
|
171
172
|
|
|
172
173
|
def inspect
|
|
173
|
-
"<##{
|
|
174
|
+
"<##{self.class}:#{object_id.to_s(8)} #{instance_variables.join(' ')}>"
|
|
174
175
|
end
|
|
175
176
|
|
|
176
177
|
# find a row either by row number or a condition
|
|
@@ -217,7 +218,7 @@ class Roo::Base
|
|
|
217
218
|
row, col = normalize(row, col)
|
|
218
219
|
cell_type = cell_type_by_value(value)
|
|
219
220
|
set_value(row, col, value, sheet)
|
|
220
|
-
set_type(row, col, cell_type
|
|
221
|
+
set_type(row, col, cell_type, sheet)
|
|
221
222
|
end
|
|
222
223
|
|
|
223
224
|
def cell_type_by_value(value)
|
|
@@ -225,7 +226,7 @@ class Roo::Base
|
|
|
225
226
|
when Fixnum then :float
|
|
226
227
|
when String, Float then :string
|
|
227
228
|
else
|
|
228
|
-
|
|
229
|
+
fail ArgumentError, "Type for #{value} not set"
|
|
229
230
|
end
|
|
230
231
|
end
|
|
231
232
|
|
|
@@ -256,13 +257,13 @@ class Roo::Base
|
|
|
256
257
|
sheets.each do|sheet|
|
|
257
258
|
self.default_sheet = sheet
|
|
258
259
|
result << 'Sheet ' + n.to_s + ":\n"
|
|
259
|
-
|
|
260
|
-
result << ' - empty -'
|
|
261
|
-
else
|
|
260
|
+
if first_row
|
|
262
261
|
result << " First row: #{first_row}\n"
|
|
263
262
|
result << " Last row: #{last_row}\n"
|
|
264
263
|
result << " First column: #{::Roo::Utils.number_to_letter(first_column)}\n"
|
|
265
264
|
result << " Last column: #{::Roo::Utils.number_to_letter(last_column)}"
|
|
265
|
+
else
|
|
266
|
+
result << ' - empty -'
|
|
266
267
|
end
|
|
267
268
|
result << "\n" if sheet != sheets.last
|
|
268
269
|
n += 1
|
|
@@ -282,12 +283,12 @@ class Roo::Base
|
|
|
282
283
|
# sonst gibt es Fehler bei leeren Blaettern
|
|
283
284
|
first_row.upto(last_row) do |row|
|
|
284
285
|
first_column.upto(last_column) do |col|
|
|
285
|
-
|
|
286
|
-
|
|
286
|
+
next if empty?(row, col)
|
|
287
|
+
|
|
288
|
+
x.cell(cell(row, col),
|
|
287
289
|
row: row,
|
|
288
290
|
column: col,
|
|
289
291
|
type: celltype(row, col))
|
|
290
|
-
end
|
|
291
292
|
end
|
|
292
293
|
end
|
|
293
294
|
end
|
|
@@ -318,7 +319,7 @@ class Roo::Base
|
|
|
318
319
|
# access different worksheets by calling spreadsheet.sheet(1)
|
|
319
320
|
# or spreadsheet.sheet('SHEETNAME')
|
|
320
321
|
def sheet(index, name = false)
|
|
321
|
-
self.default_sheet = String
|
|
322
|
+
self.default_sheet = index.is_a?(::String) ? index : sheets[index]
|
|
322
323
|
name ? [default_sheet, self] : self
|
|
323
324
|
end
|
|
324
325
|
|
|
@@ -352,25 +353,23 @@ class Roo::Base
|
|
|
352
353
|
# control characters and white spaces around columns
|
|
353
354
|
|
|
354
355
|
def each(options = {})
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
else
|
|
361
|
-
clean_sheet_if_need(options)
|
|
362
|
-
search_or_set_header(options)
|
|
363
|
-
headers = @headers ||
|
|
364
|
-
Hash[(first_column..last_column).map do |col|
|
|
365
|
-
[cell(@header_line, col), col]
|
|
366
|
-
end]
|
|
367
|
-
|
|
368
|
-
@header_line.upto(last_row) do |line|
|
|
369
|
-
yield(Hash[headers.map { |k, v| [k, cell(line, v)] }])
|
|
370
|
-
end
|
|
356
|
+
return to_enum(:each, options) unless block_given?
|
|
357
|
+
|
|
358
|
+
if options.empty?
|
|
359
|
+
1.upto(last_row) do |line|
|
|
360
|
+
yield row(line)
|
|
371
361
|
end
|
|
372
362
|
else
|
|
373
|
-
|
|
363
|
+
clean_sheet_if_need(options)
|
|
364
|
+
search_or_set_header(options)
|
|
365
|
+
headers = @headers ||
|
|
366
|
+
Hash[(first_column..last_column).map do |col|
|
|
367
|
+
[cell(@header_line, col), col]
|
|
368
|
+
end]
|
|
369
|
+
|
|
370
|
+
@header_line.upto(last_row) do |line|
|
|
371
|
+
yield(Hash[headers.map { |k, v| [k, cell(line, v)] }])
|
|
372
|
+
end
|
|
374
373
|
end
|
|
375
374
|
end
|
|
376
375
|
|
|
@@ -409,23 +408,24 @@ class Roo::Base
|
|
|
409
408
|
filename = File.basename(filename, File.extname(filename))
|
|
410
409
|
end
|
|
411
410
|
|
|
412
|
-
if uri?(filename) && qs_begin = filename.rindex('?')
|
|
411
|
+
if uri?(filename) && (qs_begin = filename.rindex('?'))
|
|
413
412
|
filename = filename[0..qs_begin - 1]
|
|
414
413
|
end
|
|
415
414
|
exts = Array(exts)
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
415
|
+
|
|
416
|
+
return if exts.include?(File.extname(filename).downcase)
|
|
417
|
+
|
|
418
|
+
case warning_level
|
|
419
|
+
when :error
|
|
420
|
+
warn file_type_warning_message(filename, exts)
|
|
421
|
+
fail TypeError, "#{filename} is not #{name} file"
|
|
422
|
+
when :warning
|
|
423
|
+
warn "are you sure, this is #{name} spreadsheet file?"
|
|
424
|
+
warn file_type_warning_message(filename, exts)
|
|
425
|
+
when :ignore
|
|
426
|
+
# ignore
|
|
427
|
+
else
|
|
428
|
+
fail "#{warning_level} illegal state of file_warning"
|
|
429
429
|
end
|
|
430
430
|
end
|
|
431
431
|
|
|
@@ -476,9 +476,9 @@ class Roo::Base
|
|
|
476
476
|
return if is_stream?(filename)
|
|
477
477
|
filename = download_uri(filename, tmpdir) if uri?(filename)
|
|
478
478
|
filename = unzip(filename, tmpdir) if packed == :zip
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
479
|
+
|
|
480
|
+
fail IOError, "file #{filename} does not exist" unless File.file?(filename)
|
|
481
|
+
|
|
482
482
|
filename
|
|
483
483
|
end
|
|
484
484
|
|
|
@@ -536,11 +536,8 @@ class Roo::Base
|
|
|
536
536
|
end
|
|
537
537
|
|
|
538
538
|
def make_tmpdir(prefix = nil, root = nil, &block)
|
|
539
|
-
prefix =
|
|
540
|
-
|
|
541
|
-
else
|
|
542
|
-
TEMP_PREFIX
|
|
543
|
-
end
|
|
539
|
+
prefix = "#{TEMP_PREFIX}#{prefix}"
|
|
540
|
+
|
|
544
541
|
::Dir.mktmpdir(prefix, root || ENV['ROO_TMP'], &block).tap do |result|
|
|
545
542
|
block_given? || track_tmpdir!(result)
|
|
546
543
|
end
|
|
@@ -588,9 +585,9 @@ class Roo::Base
|
|
|
588
585
|
fail ArgumentError
|
|
589
586
|
end
|
|
590
587
|
end
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
588
|
+
|
|
589
|
+
col = ::Roo::Utils.letter_to_number(col) if col.is_a?(::String)
|
|
590
|
+
|
|
594
591
|
[row, col]
|
|
595
592
|
end
|
|
596
593
|
|
|
@@ -641,7 +638,7 @@ class Roo::Base
|
|
|
641
638
|
fail RangeError, "sheet index #{sheet} not found"
|
|
642
639
|
end
|
|
643
640
|
when String
|
|
644
|
-
unless sheets.include?
|
|
641
|
+
unless sheets.include?(sheet)
|
|
645
642
|
fail RangeError, "sheet '#{sheet}' not found"
|
|
646
643
|
end
|
|
647
644
|
else
|
|
@@ -670,14 +667,14 @@ class Roo::Base
|
|
|
670
667
|
# parameter is nil the output goes to STDOUT
|
|
671
668
|
def write_csv_content(file = nil, sheet = nil, separator = ',')
|
|
672
669
|
file ||= STDOUT
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
670
|
+
return unless first_row(sheet) # The sheet is empty
|
|
671
|
+
|
|
672
|
+
1.upto(last_row(sheet)) do |row|
|
|
673
|
+
1.upto(last_column(sheet)) do |col|
|
|
674
|
+
file.print(separator) if col > 1
|
|
675
|
+
file.print cell_to_csv(row, col, sheet)
|
|
676
|
+
end
|
|
677
|
+
file.print("\n")
|
|
681
678
|
end
|
|
682
679
|
end
|
|
683
680
|
|
|
@@ -729,9 +726,9 @@ class Roo::Base
|
|
|
729
726
|
# converts an integer value to a time string like '02:05:06'
|
|
730
727
|
def integer_to_timestring(content)
|
|
731
728
|
h = (content / 3600.0).floor
|
|
732
|
-
content
|
|
729
|
+
content -= h * 3600
|
|
733
730
|
m = (content / 60.0).floor
|
|
734
|
-
content
|
|
731
|
+
content -= m * 60
|
|
735
732
|
s = content
|
|
736
733
|
sprintf('%02d:%02d:%02d', h, m, s)
|
|
737
734
|
end
|
|
@@ -13,9 +13,19 @@ module Roo
|
|
|
13
13
|
|
|
14
14
|
private
|
|
15
15
|
|
|
16
|
+
def fix_invalid_shared_strings(doc)
|
|
17
|
+
invalid = { '_x000D_' => "\n" }
|
|
18
|
+
xml = doc.to_s
|
|
19
|
+
|
|
20
|
+
if xml[/#{invalid.keys.join('|')}/]
|
|
21
|
+
@doc = ::Nokogiri::XML(xml.gsub(/#{invalid.keys.join('|')}/, invalid))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
16
25
|
def extract_shared_strings
|
|
17
26
|
return [] unless doc_exists?
|
|
18
27
|
|
|
28
|
+
fix_invalid_shared_strings(doc)
|
|
19
29
|
# read the shared strings xml document
|
|
20
30
|
doc.xpath('/sst/si').map do |si|
|
|
21
31
|
shared_string = ''
|
data/lib/roo/spreadsheet.rb
CHANGED
data/lib/roo/version.rb
CHANGED
data/spec/helpers.rb
ADDED
data/spec/lib/roo/base_spec.rb
CHANGED
|
@@ -1,4 +1,216 @@
|
|
|
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
|
+
[5, 1] => Date.civil(1961, 11, 21),
|
|
45
|
+
|
|
46
|
+
[8, 3] => 'thisisc8',
|
|
47
|
+
[8, 7] => 'thisisg8',
|
|
48
|
+
|
|
49
|
+
[12, 1] => 41.0,
|
|
50
|
+
[12, 2] => 42.0,
|
|
51
|
+
[12, 3] => 43.0,
|
|
52
|
+
[12, 4] => 44.0,
|
|
53
|
+
[12, 5] => 45.0,
|
|
54
|
+
|
|
55
|
+
[15, 3] => 43.0,
|
|
56
|
+
[15, 4] => 44.0,
|
|
57
|
+
[15, 5] => 45.0,
|
|
58
|
+
|
|
59
|
+
[16, 2] => '"Hello world!"',
|
|
60
|
+
[16, 3] => 'forty-three',
|
|
61
|
+
[16, 4] => 'forty-four',
|
|
62
|
+
[16, 5] => 'forty-five'
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
let(:spreadsheet) { klass.new('some_file', spreadsheet_data) }
|
|
67
|
+
|
|
68
|
+
describe '#uri?' do
|
|
69
|
+
it 'should return true when passed a filename starting with http(s)://' do
|
|
70
|
+
expect(spreadsheet.send(:uri?, 'http://example.com/')).to be_truthy
|
|
71
|
+
expect(spreadsheet.send(:uri?, 'https://example.com/')).to be_truthy
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'should return false when passed a filename which does not start with http(s)://' do
|
|
75
|
+
expect(spreadsheet.send(:uri?, 'example.com')).to be_falsy
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'should return false when passed non-String object such as Tempfile' do
|
|
79
|
+
expect(spreadsheet.send(:uri?, Tempfile.new('test'))).to be_falsy
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe '#set' do
|
|
84
|
+
it 'should not update cell when setting an invalid type' do
|
|
85
|
+
spreadsheet.set(1, 1, 1)
|
|
86
|
+
expect { spreadsheet.set(1, 1, :invalid_type) }.to raise_error(ArgumentError)
|
|
87
|
+
expect(spreadsheet.cell(1, 1)).to eq(1)
|
|
88
|
+
expect(spreadsheet.celltype(1, 1)).to eq(:float)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe '#first_row' do
|
|
93
|
+
it 'should return the first row' do
|
|
94
|
+
expect(spreadsheet.first_row).to eq(5)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#last_row' do
|
|
99
|
+
it 'should return the last row' do
|
|
100
|
+
expect(spreadsheet.last_row).to eq(16)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe '#first_column' do
|
|
105
|
+
it 'should return the first column' do
|
|
106
|
+
expect(spreadsheet.first_column).to eq(1)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe '#first_column_as_letter' do
|
|
111
|
+
it 'should return the first column as a letter' do
|
|
112
|
+
expect(spreadsheet.first_column_as_letter).to eq('A')
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe '#last_column' do
|
|
117
|
+
it 'should return the last column' do
|
|
118
|
+
expect(spreadsheet.last_column).to eq(7)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
describe '#last_column_as_letter' do
|
|
123
|
+
it 'should return the last column as a letter' do
|
|
124
|
+
expect(spreadsheet.last_column_as_letter).to eq('G')
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe '#row' do
|
|
129
|
+
it 'should return the specified row' do
|
|
130
|
+
expect(spreadsheet.row(12)).to eq([41.0, 42.0, 43.0, 44.0, 45.0, nil, nil])
|
|
131
|
+
expect(spreadsheet.row(16)).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil])
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe '#empty?' do
|
|
136
|
+
it 'should return true when empty' do
|
|
137
|
+
expect(spreadsheet.empty?(1, 1)).to be_truthy
|
|
138
|
+
expect(spreadsheet.empty?(8, 3)).to be_falsy
|
|
139
|
+
expect(spreadsheet.empty?('A', 11)).to be_truthy
|
|
140
|
+
expect(spreadsheet.empty?('A', 12)).to be_falsy
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe '#reload' do
|
|
145
|
+
it 'should return reinitialize the spreadsheet' do
|
|
146
|
+
spreadsheet.reload
|
|
147
|
+
expect(spreadsheet.instance_variable_get(:@cell).empty?).to be_truthy
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe '#each' do
|
|
152
|
+
it 'should return an enumerator with all the rows' do
|
|
153
|
+
each = spreadsheet.each
|
|
154
|
+
expect(each).to be_a(Enumerator)
|
|
155
|
+
expect(each.to_a.last).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil])
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
describe '#to_yaml' do
|
|
160
|
+
it 'should convert the spreadsheet to yaml' do
|
|
161
|
+
expect(spreadsheet.to_yaml({}, 5, 1, 5, 1)).to eq("--- \n" + yaml_entry(5, 1, 'date', '1961-11-21'))
|
|
162
|
+
expect(spreadsheet.to_yaml({}, 8, 3, 8, 3)).to eq("--- \n" + yaml_entry(8, 3, 'string', 'thisisc8'))
|
|
163
|
+
|
|
164
|
+
expect(spreadsheet.to_yaml({}, 12, 3, 12, 3)).to eq("--- \n" + yaml_entry(12, 3, 'float', 43.0))
|
|
165
|
+
|
|
166
|
+
expect(spreadsheet.to_yaml({}, 12, 3, 12)).to eq(
|
|
167
|
+
"--- \n" + yaml_entry(12, 3, 'float', 43.0) +
|
|
168
|
+
yaml_entry(12, 4, 'float', 44.0) +
|
|
169
|
+
yaml_entry(12, 5, 'float', 45.0))
|
|
170
|
+
|
|
171
|
+
expect(spreadsheet.to_yaml({}, 12, 3)).to eq(
|
|
172
|
+
"--- \n" + yaml_entry(12, 3, 'float', 43.0) +
|
|
173
|
+
yaml_entry(12, 4, 'float', 44.0) +
|
|
174
|
+
yaml_entry(12, 5, 'float', 45.0) +
|
|
175
|
+
yaml_entry(15, 3, 'float', 43.0) +
|
|
176
|
+
yaml_entry(15, 4, 'float', 44.0) +
|
|
177
|
+
yaml_entry(15, 5, 'float', 45.0) +
|
|
178
|
+
yaml_entry(16, 3, 'string', 'forty-three') +
|
|
179
|
+
yaml_entry(16, 4, 'string', 'forty-four') +
|
|
180
|
+
yaml_entry(16, 5, 'string', 'forty-five'))
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
let(:expected_csv) do
|
|
185
|
+
<<EOS
|
|
186
|
+
,,,,,,
|
|
187
|
+
,,,,,,
|
|
188
|
+
,,,,,,
|
|
189
|
+
,,,,,,
|
|
190
|
+
1961-11-21,,,,,,
|
|
191
|
+
,,,,,,
|
|
192
|
+
,,,,,,
|
|
193
|
+
,,"thisisc8",,,,"thisisg8"
|
|
194
|
+
,,,,,,
|
|
195
|
+
,,,,,,
|
|
196
|
+
,,,,,,
|
|
197
|
+
41,42,43,44,45,,
|
|
198
|
+
,,,,,,
|
|
199
|
+
,,,,,,
|
|
200
|
+
,,43,44,45,,
|
|
201
|
+
,"""Hello world!""","forty-three","forty-four","forty-five",,
|
|
202
|
+
EOS
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
let(:expected_csv_with_semicolons) { expected_csv.gsub(/\,/, ';') }
|
|
206
|
+
|
|
207
|
+
describe '#to_csv' do
|
|
208
|
+
it 'should convert the spreadsheet to csv' do
|
|
209
|
+
expect(spreadsheet.to_csv).to eq(expected_csv)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it 'should convert the spreadsheet to csv using the separator when is passed on the parameter' do
|
|
213
|
+
expect(spreadsheet.to_csv(nil, ';')).to eq(expected_csv_with_semicolons)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
4
216
|
end
|
data/spec/lib/roo/excelx_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/test/test_helper.rb
CHANGED
|
@@ -45,10 +45,6 @@ def file_diff(fn1,fn2)
|
|
|
45
45
|
result
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def yaml_entry(row,col,type,value)
|
|
49
|
-
"cell_#{row}_#{col}: \n row: #{row} \n col: #{col} \n celltype: #{type} \n value: #{value} \n"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
48
|
class File
|
|
53
49
|
def File.delete_if_exist(filename)
|
|
54
50
|
if File.exist?(filename)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: roo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.
|
|
4
|
+
version: 2.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Thomas Preymesser
|
|
@@ -11,17 +11,17 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date: 2015-
|
|
14
|
+
date: 2015-08-01 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: nokogiri
|
|
18
|
-
prerelease: false
|
|
19
18
|
requirement: !ruby/object:Gem::Requirement
|
|
20
19
|
requirements:
|
|
21
20
|
- - "~>"
|
|
22
21
|
- !ruby/object:Gem::Version
|
|
23
22
|
version: '1'
|
|
24
23
|
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
26
|
requirements:
|
|
27
27
|
- - "~>"
|
|
@@ -29,7 +29,6 @@ dependencies:
|
|
|
29
29
|
version: '1'
|
|
30
30
|
- !ruby/object:Gem::Dependency
|
|
31
31
|
name: rubyzip
|
|
32
|
-
prerelease: false
|
|
33
32
|
requirement: !ruby/object:Gem::Requirement
|
|
34
33
|
requirements:
|
|
35
34
|
- - "~>"
|
|
@@ -39,6 +38,7 @@ dependencies:
|
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
39
|
version: 2.0.0
|
|
41
40
|
type: :runtime
|
|
41
|
+
prerelease: false
|
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
@@ -49,13 +49,13 @@ dependencies:
|
|
|
49
49
|
version: 2.0.0
|
|
50
50
|
- !ruby/object:Gem::Dependency
|
|
51
51
|
name: rake
|
|
52
|
-
prerelease: false
|
|
53
52
|
requirement: !ruby/object:Gem::Requirement
|
|
54
53
|
requirements:
|
|
55
54
|
- - "~>"
|
|
56
55
|
- !ruby/object:Gem::Version
|
|
57
56
|
version: '10.1'
|
|
58
57
|
type: :development
|
|
58
|
+
prerelease: false
|
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
|
60
60
|
requirements:
|
|
61
61
|
- - "~>"
|
|
@@ -63,7 +63,6 @@ dependencies:
|
|
|
63
63
|
version: '10.1'
|
|
64
64
|
- !ruby/object:Gem::Dependency
|
|
65
65
|
name: minitest
|
|
66
|
-
prerelease: false
|
|
67
66
|
requirement: !ruby/object:Gem::Requirement
|
|
68
67
|
requirements:
|
|
69
68
|
- - "~>"
|
|
@@ -73,6 +72,7 @@ dependencies:
|
|
|
73
72
|
- !ruby/object:Gem::Version
|
|
74
73
|
version: 5.4.3
|
|
75
74
|
type: :development
|
|
75
|
+
prerelease: false
|
|
76
76
|
version_requirements: !ruby/object:Gem::Requirement
|
|
77
77
|
requirements:
|
|
78
78
|
- - "~>"
|
|
@@ -131,6 +131,7 @@ files:
|
|
|
131
131
|
- spec/fixtures/vcr_cassettes/google_drive.yml
|
|
132
132
|
- spec/fixtures/vcr_cassettes/google_drive_access_token.yml
|
|
133
133
|
- spec/fixtures/vcr_cassettes/google_drive_set.yml
|
|
134
|
+
- spec/helpers.rb
|
|
134
135
|
- spec/lib/roo/base_spec.rb
|
|
135
136
|
- spec/lib/roo/csv_spec.rb
|
|
136
137
|
- spec/lib/roo/excelx/format_spec.rb
|
|
@@ -141,7 +142,6 @@ files:
|
|
|
141
142
|
- spec/lib/roo/utils_spec.rb
|
|
142
143
|
- spec/spec_helper.rb
|
|
143
144
|
- test/all_ss.rb
|
|
144
|
-
- test/test_generic_spreadsheet.rb
|
|
145
145
|
- test/test_helper.rb
|
|
146
146
|
- test/test_roo.rb
|
|
147
147
|
homepage: http://github.com/roo-rb/roo
|
|
@@ -164,8 +164,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
164
164
|
version: '0'
|
|
165
165
|
requirements: []
|
|
166
166
|
rubyforge_project:
|
|
167
|
-
rubygems_version: 2.4.
|
|
167
|
+
rubygems_version: 2.4.5
|
|
168
168
|
signing_key:
|
|
169
169
|
specification_version: 4
|
|
170
170
|
summary: Roo can access the contents of various spreadsheet files.
|
|
171
171
|
test_files: []
|
|
172
|
+
has_rdoc:
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
require File.dirname(__FILE__) + '/test_helper'
|
|
3
|
-
|
|
4
|
-
class TestBase < Minitest::Test
|
|
5
|
-
def setup
|
|
6
|
-
@klass = Class.new(Roo::Base) do
|
|
7
|
-
def initialize(filename = 'some_file')
|
|
8
|
-
super
|
|
9
|
-
@filename = filename
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def read_cells(sheet = nil)
|
|
13
|
-
@cells_read[sheet] = true
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def cell(row, col, sheet = nil)
|
|
17
|
-
sheet ||= default_sheet
|
|
18
|
-
@cell[sheet][[row, col]]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def celltype(row, col, sheet = nil)
|
|
22
|
-
sheet ||= default_sheet
|
|
23
|
-
@cell_type[sheet][[row, col]]
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def sheets
|
|
27
|
-
['my_sheet', 'blank sheet']
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
@oo = @klass.new
|
|
31
|
-
setup_test_sheet(@oo)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
context 'private method Roo::Base.uri?(filename)' do
|
|
35
|
-
should 'return true when passed a filename starts with http(s)://' do
|
|
36
|
-
assert_equal true, @oo.send(:uri?, 'http://example.com/')
|
|
37
|
-
assert_equal true, @oo.send(:uri?, 'https://example.com/')
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
should 'return false when passed a filename which does not start with http(s)://' do
|
|
41
|
-
assert_equal false, @oo.send(:uri?, 'example.com')
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
should 'return false when passed non-String object such as Tempfile' do
|
|
45
|
-
assert_equal false, @oo.send(:uri?, Tempfile.new('test'))
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def test_setting_invalid_type_does_not_update_cell
|
|
50
|
-
@oo.set(1, 1, 1)
|
|
51
|
-
assert_raises(ArgumentError) { @oo.set(1, 1, :invalid_type) }
|
|
52
|
-
assert_equal 1, @oo.cell(1, 1)
|
|
53
|
-
assert_equal :float, @oo.celltype(1, 1)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def test_first_row
|
|
57
|
-
assert_equal 5, @oo.first_row
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def test_last_row
|
|
61
|
-
assert_equal 16, @oo.last_row
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def test_first_column
|
|
65
|
-
assert_equal 1, @oo.first_column
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def test_first_column_as_letter
|
|
69
|
-
assert_equal 'A', @oo.first_column_as_letter
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def test_last_column
|
|
73
|
-
assert_equal 7, @oo.last_column
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def test_last_column_as_letter
|
|
77
|
-
assert_equal 'G', @oo.last_column_as_letter
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def test_rows
|
|
81
|
-
assert_equal [41.0, 42.0, 43.0, 44.0, 45.0, nil, nil], @oo.row(12)
|
|
82
|
-
assert_equal [nil, '"Hello world!"', 'dreiundvierzig', 'vierundvierzig', 'fuenfundvierzig', nil, nil], @oo.row(16)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def test_empty_eh
|
|
86
|
-
assert @oo.empty?(1, 1)
|
|
87
|
-
assert !@oo.empty?(8, 3)
|
|
88
|
-
assert @oo.empty?('A', 11)
|
|
89
|
-
assert !@oo.empty?('A', 12)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def test_reload
|
|
93
|
-
@oo.reload
|
|
94
|
-
assert @oo.instance_variable_get(:@cell).empty?
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def test_each
|
|
98
|
-
oo_each = @oo.each
|
|
99
|
-
assert_instance_of Enumerator, oo_each
|
|
100
|
-
assert_equal [nil, '"Hello world!"', 'dreiundvierzig', 'vierundvierzig', 'fuenfundvierzig', nil, nil], oo_each.to_a.last
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def test_to_yaml
|
|
104
|
-
assert_equal "--- \n" + yaml_entry(5, 1, 'date', '1961-11-21'), @oo.to_yaml({}, 5, 1, 5, 1)
|
|
105
|
-
assert_equal "--- \n" + yaml_entry(8, 3, 'string', 'thisisc8'), @oo.to_yaml({}, 8, 3, 8, 3)
|
|
106
|
-
assert_equal "--- \n" + yaml_entry(12, 3, 'float', 43.0), @oo.to_yaml({}, 12, 3, 12, 3)
|
|
107
|
-
assert_equal \
|
|
108
|
-
"--- \n" + yaml_entry(12, 3, 'float', 43.0) +
|
|
109
|
-
yaml_entry(12, 4, 'float', 44.0) +
|
|
110
|
-
yaml_entry(12, 5, 'float', 45.0), @oo.to_yaml({}, 12, 3, 12)
|
|
111
|
-
assert_equal \
|
|
112
|
-
"--- \n" + yaml_entry(12, 3, 'float', 43.0) +
|
|
113
|
-
yaml_entry(12, 4, 'float', 44.0) +
|
|
114
|
-
yaml_entry(12, 5, 'float', 45.0) +
|
|
115
|
-
yaml_entry(15, 3, 'float', 43.0) +
|
|
116
|
-
yaml_entry(15, 4, 'float', 44.0) +
|
|
117
|
-
yaml_entry(15, 5, 'float', 45.0) +
|
|
118
|
-
yaml_entry(16, 3, 'string', 'dreiundvierzig') +
|
|
119
|
-
yaml_entry(16, 4, 'string', 'vierundvierzig') +
|
|
120
|
-
yaml_entry(16, 5, 'string', 'fuenfundvierzig'), @oo.to_yaml({}, 12, 3)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def test_to_csv
|
|
124
|
-
assert_equal expected_csv, @oo.to_csv
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def test_to_csv_with_separator
|
|
128
|
-
assert_equal expected_csv_with_semicolons, @oo.to_csv(nil, ';')
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
protected
|
|
132
|
-
|
|
133
|
-
def setup_test_sheet(workbook = nil)
|
|
134
|
-
workbook ||= @oo
|
|
135
|
-
set_sheet_values(workbook)
|
|
136
|
-
set_sheet_types(workbook)
|
|
137
|
-
set_cells_read(workbook)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def set_sheet_values(workbook)
|
|
141
|
-
workbook.instance_variable_get(:@cell)[workbook.default_sheet] = {
|
|
142
|
-
[5, 1] => Date.civil(1961, 11, 21).to_s,
|
|
143
|
-
|
|
144
|
-
[8, 3] => 'thisisc8',
|
|
145
|
-
[8, 7] => 'thisisg8',
|
|
146
|
-
|
|
147
|
-
[12, 1] => 41.0,
|
|
148
|
-
[12, 2] => 42.0,
|
|
149
|
-
[12, 3] => 43.0,
|
|
150
|
-
[12, 4] => 44.0,
|
|
151
|
-
[12, 5] => 45.0,
|
|
152
|
-
|
|
153
|
-
[15, 3] => 43.0,
|
|
154
|
-
[15, 4] => 44.0,
|
|
155
|
-
[15, 5] => 45.0,
|
|
156
|
-
|
|
157
|
-
[16, 2] => '"Hello world!"',
|
|
158
|
-
[16, 3] => 'dreiundvierzig',
|
|
159
|
-
[16, 4] => 'vierundvierzig',
|
|
160
|
-
[16, 5] => 'fuenfundvierzig'
|
|
161
|
-
}
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def set_sheet_types(workbook)
|
|
165
|
-
workbook.instance_variable_get(:@cell_type)[workbook.default_sheet] = {
|
|
166
|
-
[5, 1] => :date,
|
|
167
|
-
|
|
168
|
-
[8, 3] => :string,
|
|
169
|
-
[8, 7] => :string,
|
|
170
|
-
|
|
171
|
-
[12, 1] => :float,
|
|
172
|
-
[12, 2] => :float,
|
|
173
|
-
[12, 3] => :float,
|
|
174
|
-
[12, 4] => :float,
|
|
175
|
-
[12, 5] => :float,
|
|
176
|
-
|
|
177
|
-
[15, 3] => :float,
|
|
178
|
-
[15, 4] => :float,
|
|
179
|
-
[15, 5] => :float,
|
|
180
|
-
|
|
181
|
-
[16, 2] => :string,
|
|
182
|
-
[16, 3] => :string,
|
|
183
|
-
[16, 4] => :string,
|
|
184
|
-
[16, 5] => :string
|
|
185
|
-
}
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def set_first_row(workbook)
|
|
189
|
-
row_hash = workbook.instance_variable_get(:@first_row)
|
|
190
|
-
row_hash[workbook.default_sheet] = workbook.instance_variable_get(:@cell)[workbook.default_sheet].map { |k, _v| k[0] }.min
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
def set_last_row(workbook)
|
|
194
|
-
row_hash = workbook.instance_variable_get(:@last_row)
|
|
195
|
-
row_hash[workbook.default_sheet] = workbook.instance_variable_get(:@cell)[workbook.default_sheet].map { |k, _v| k[0] }.max
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def set_first_col(workbook)
|
|
199
|
-
col_hash = workbook.instance_variable_get(:@first_column)
|
|
200
|
-
col_hash[workbook.default_sheet] = workbook.instance_variable_get(:@cell)[workbook.default_sheet].map { |k, _v| k[1] }.min
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def set_last_col(workbook)
|
|
204
|
-
col_hash = workbook.instance_variable_get(:@last_column)
|
|
205
|
-
col_hash[workbook.default_sheet] = workbook.instance_variable_get(:@cell)[workbook.default_sheet].map { |k, _v| k[1] }.max
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def set_cells_read(workbook)
|
|
209
|
-
read_hash = workbook.instance_variable_get(:@cells_read)
|
|
210
|
-
read_hash[workbook.default_sheet] = true
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def expected_csv
|
|
214
|
-
<<EOS
|
|
215
|
-
,,,,,,
|
|
216
|
-
,,,,,,
|
|
217
|
-
,,,,,,
|
|
218
|
-
,,,,,,
|
|
219
|
-
1961-11-21,,,,,,
|
|
220
|
-
,,,,,,
|
|
221
|
-
,,,,,,
|
|
222
|
-
,,"thisisc8",,,,"thisisg8"
|
|
223
|
-
,,,,,,
|
|
224
|
-
,,,,,,
|
|
225
|
-
,,,,,,
|
|
226
|
-
41,42,43,44,45,,
|
|
227
|
-
,,,,,,
|
|
228
|
-
,,,,,,
|
|
229
|
-
,,43,44,45,,
|
|
230
|
-
,"""Hello world!""","dreiundvierzig","vierundvierzig","fuenfundvierzig",,
|
|
231
|
-
EOS
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
def expected_csv_with_semicolons
|
|
235
|
-
expected_csv.gsub(/\,/, ';')
|
|
236
|
-
end
|
|
237
|
-
end
|