roo 2.6.0 → 2.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.codeclimate.yml +17 -0
- data/.github/issue_template.md +16 -0
- data/.github/pull_request_template.md +14 -0
- data/.rubocop.yml +186 -0
- data/.travis.yml +14 -11
- data/CHANGELOG.md +64 -2
- data/Gemfile +2 -4
- data/LICENSE +2 -0
- data/README.md +36 -10
- data/lib/roo/base.rb +82 -225
- data/lib/roo/constants.rb +5 -3
- data/lib/roo/csv.rb +100 -97
- data/lib/roo/excelx/cell/base.rb +26 -12
- data/lib/roo/excelx/cell/boolean.rb +9 -6
- data/lib/roo/excelx/cell/date.rb +7 -7
- data/lib/roo/excelx/cell/datetime.rb +50 -44
- data/lib/roo/excelx/cell/empty.rb +3 -2
- data/lib/roo/excelx/cell/number.rb +44 -47
- data/lib/roo/excelx/cell/string.rb +3 -3
- data/lib/roo/excelx/cell/time.rb +17 -16
- data/lib/roo/excelx/cell.rb +10 -6
- data/lib/roo/excelx/comments.rb +3 -3
- data/lib/roo/excelx/coordinate.rb +11 -4
- data/lib/roo/excelx/extractor.rb +21 -3
- data/lib/roo/excelx/format.rb +38 -31
- data/lib/roo/excelx/images.rb +26 -0
- data/lib/roo/excelx/relationships.rb +12 -4
- data/lib/roo/excelx/shared.rb +10 -3
- data/lib/roo/excelx/shared_strings.rb +9 -15
- data/lib/roo/excelx/sheet.rb +49 -10
- data/lib/roo/excelx/sheet_doc.rb +89 -48
- data/lib/roo/excelx/styles.rb +3 -3
- data/lib/roo/excelx/workbook.rb +7 -3
- data/lib/roo/excelx.rb +50 -19
- 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/helpers/default_attr_reader.rb +20 -0
- data/lib/roo/helpers/weak_instance_cache.rb +41 -0
- data/lib/roo/open_office.rb +17 -9
- data/lib/roo/spreadsheet.rb +1 -1
- data/lib/roo/tempdir.rb +5 -10
- data/lib/roo/utils.rb +70 -20
- data/lib/roo/version.rb +1 -1
- data/lib/roo.rb +4 -1
- data/roo.gemspec +14 -11
- data/spec/lib/roo/base_spec.rb +45 -3
- data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
- data/spec/lib/roo/excelx/sheet_doc_spec.rb +11 -0
- data/spec/lib/roo/excelx_spec.rb +150 -31
- data/spec/lib/roo/strict_spec.rb +43 -0
- data/spec/lib/roo/utils_spec.rb +25 -3
- data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
- data/spec/lib/roo_spec.rb +0 -0
- data/spec/spec_helper.rb +2 -6
- data/test/excelx/cell/test_attr_reader_default.rb +72 -0
- data/test/excelx/cell/test_base.rb +5 -0
- data/test/excelx/cell/test_datetime.rb +6 -6
- data/test/excelx/cell/test_empty.rb +11 -0
- data/test/excelx/cell/test_number.rb +9 -0
- data/test/excelx/cell/test_string.rb +20 -0
- data/test/excelx/cell/test_time.rb +5 -5
- data/test/excelx/test_coordinate.rb +51 -0
- data/test/formatters/test_csv.rb +136 -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 +88 -0
- data/test/roo/test_excelx.rb +330 -0
- data/test/roo/test_libre_office.rb +9 -0
- data/test/roo/test_open_office.rb +289 -0
- data/test/test_helper.rb +129 -14
- data/test/test_roo.rb +32 -1787
- metadata +81 -29
- data/.github/ISSUE_TEMPLATE +0 -10
- data/Gemfile_ruby2 +0 -29
data/lib/roo/base.rb
CHANGED
@@ -1,16 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
require "tmpdir"
|
2
|
+
require "stringio"
|
3
|
+
require "nokogiri"
|
4
|
+
require "roo/utils"
|
5
|
+
require "roo/formatters/base"
|
6
|
+
require "roo/formatters/csv"
|
7
|
+
require "roo/formatters/matrix"
|
8
|
+
require "roo/formatters/xml"
|
9
|
+
require "roo/formatters/yaml"
|
7
10
|
|
8
11
|
# Base class for all other types of spreadsheets
|
9
12
|
class Roo::Base
|
10
13
|
include Enumerable
|
14
|
+
include Roo::Formatters::Base
|
15
|
+
include Roo::Formatters::CSV
|
16
|
+
include Roo::Formatters::Matrix
|
17
|
+
include Roo::Formatters::XML
|
18
|
+
include Roo::Formatters::YAML
|
11
19
|
|
12
|
-
MAX_ROW_COL = 999_999
|
13
|
-
MIN_ROW_COL = 0
|
20
|
+
MAX_ROW_COL = 999_999
|
21
|
+
MIN_ROW_COL = 0
|
14
22
|
|
15
23
|
attr_reader :headers
|
16
24
|
|
@@ -18,10 +26,14 @@ class Roo::Base
|
|
18
26
|
attr_accessor :header_line
|
19
27
|
|
20
28
|
def self.TEMP_PREFIX
|
21
|
-
warn
|
29
|
+
warn "[DEPRECATION] please access TEMP_PREFIX via Roo::TEMP_PREFIX"
|
22
30
|
Roo::TEMP_PREFIX
|
23
31
|
end
|
24
32
|
|
33
|
+
def self.finalize(object_id)
|
34
|
+
proc { finalize_tempdirs(object_id) }
|
35
|
+
end
|
36
|
+
|
25
37
|
def initialize(filename, options = {}, _file_warning = :error, _tmpdir = nil)
|
26
38
|
@filename = filename
|
27
39
|
@options = options
|
@@ -42,6 +54,11 @@ class Roo::Base
|
|
42
54
|
if self.class.respond_to?(:finalize_tempdirs)
|
43
55
|
self.class.finalize_tempdirs(object_id)
|
44
56
|
end
|
57
|
+
|
58
|
+
instance_variables.each do |instance_variable|
|
59
|
+
instance_variable_set(instance_variable, nil)
|
60
|
+
end
|
61
|
+
|
45
62
|
nil
|
46
63
|
end
|
47
64
|
|
@@ -50,10 +67,10 @@ class Roo::Base
|
|
50
67
|
end
|
51
68
|
|
52
69
|
# sets the working sheet in the document
|
53
|
-
# 'sheet' can be a number (
|
70
|
+
# 'sheet' can be a number (0 = first sheet) or the name of a sheet.
|
54
71
|
def default_sheet=(sheet)
|
55
72
|
validate_sheet!(sheet)
|
56
|
-
@default_sheet = sheet
|
73
|
+
@default_sheet = sheet.is_a?(String) ? sheet : sheets[sheet]
|
57
74
|
@first_row[sheet] = @last_row[sheet] = @first_column[sheet] = @last_column[sheet] = nil
|
58
75
|
@cells_read[sheet] = false
|
59
76
|
end
|
@@ -86,7 +103,7 @@ class Roo::Base
|
|
86
103
|
def collect_last_row_col_for_sheet(sheet)
|
87
104
|
first_row = first_column = MAX_ROW_COL
|
88
105
|
last_row = last_column = MIN_ROW_COL
|
89
|
-
@cell[sheet].each_pair do|key, value|
|
106
|
+
@cell[sheet].each_pair do |key, value|
|
90
107
|
next unless value
|
91
108
|
first_row = [first_row, key.first.to_i].min
|
92
109
|
last_row = [last_row, key.first.to_i].max
|
@@ -96,82 +113,14 @@ class Roo::Base
|
|
96
113
|
{ first_row: first_row, first_column: first_column, last_row: last_row, last_column: last_column }
|
97
114
|
end
|
98
115
|
|
99
|
-
%
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end # end
|
105
|
-
EOS
|
106
|
-
end
|
107
|
-
|
108
|
-
# returns a rectangular area (default: all cells) as yaml-output
|
109
|
-
# you can add additional attributes with the prefix parameter like:
|
110
|
-
# oo.to_yaml({"file"=>"flightdata_2007-06-26", "sheet" => "1"})
|
111
|
-
def to_yaml(prefix = {}, from_row = nil, from_column = nil, to_row = nil, to_column = nil, sheet = default_sheet)
|
112
|
-
return '' unless first_row # empty result if there is no first_row in a sheet
|
113
|
-
|
114
|
-
from_row ||= first_row(sheet)
|
115
|
-
to_row ||= last_row(sheet)
|
116
|
-
from_column ||= first_column(sheet)
|
117
|
-
to_column ||= last_column(sheet)
|
118
|
-
|
119
|
-
result = "--- \n"
|
120
|
-
from_row.upto(to_row) do |row|
|
121
|
-
from_column.upto(to_column) do |col|
|
122
|
-
next if empty?(row, col, sheet)
|
123
|
-
|
124
|
-
result << "cell_#{row}_#{col}: \n"
|
125
|
-
prefix.each do|k, v|
|
126
|
-
result << " #{k}: #{v} \n"
|
127
|
-
end
|
128
|
-
result << " row: #{row} \n"
|
129
|
-
result << " col: #{col} \n"
|
130
|
-
result << " celltype: #{celltype(row, col, sheet)} \n"
|
131
|
-
value = cell(row, col, sheet)
|
132
|
-
if celltype(row, col, sheet) == :time
|
133
|
-
value = integer_to_timestring(value)
|
134
|
-
end
|
135
|
-
result << " value: #{value} \n"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
result
|
140
|
-
end
|
141
|
-
|
142
|
-
# write the current spreadsheet to stdout or into a file
|
143
|
-
def to_csv(filename = nil, separator = ',', sheet = default_sheet)
|
144
|
-
if filename
|
145
|
-
File.open(filename, 'w') do |file|
|
146
|
-
write_csv_content(file, sheet, separator)
|
147
|
-
end
|
148
|
-
true
|
149
|
-
else
|
150
|
-
sio = ::StringIO.new
|
151
|
-
write_csv_content(sio, sheet, separator)
|
152
|
-
sio.rewind
|
153
|
-
sio.read
|
116
|
+
%i(first_row last_row first_column last_column).each do |key|
|
117
|
+
ivar = "@#{key}".to_sym
|
118
|
+
define_method(key) do |sheet = default_sheet|
|
119
|
+
read_cells(sheet)
|
120
|
+
instance_variable_get(ivar)[sheet] ||= first_last_row_col_for_sheet(sheet)[key]
|
154
121
|
end
|
155
122
|
end
|
156
123
|
|
157
|
-
# returns a matrix object from the whole sheet or a rectangular area of a sheet
|
158
|
-
def to_matrix(from_row = nil, from_column = nil, to_row = nil, to_column = nil, sheet = default_sheet)
|
159
|
-
require 'matrix'
|
160
|
-
|
161
|
-
return Matrix.empty unless first_row
|
162
|
-
|
163
|
-
from_row ||= first_row(sheet)
|
164
|
-
to_row ||= last_row(sheet)
|
165
|
-
from_column ||= first_column(sheet)
|
166
|
-
to_column ||= last_column(sheet)
|
167
|
-
|
168
|
-
Matrix.rows(from_row.upto(to_row).map do |row|
|
169
|
-
from_column.upto(to_column).map do |col|
|
170
|
-
cell(row, col, sheet)
|
171
|
-
end
|
172
|
-
end)
|
173
|
-
end
|
174
|
-
|
175
124
|
def inspect
|
176
125
|
"<##{self.class}:#{object_id.to_s(8)} #{instance_variables.join(' ')}>"
|
177
126
|
end
|
@@ -256,16 +205,16 @@ class Roo::Base
|
|
256
205
|
"Number of sheets: #{sheets.size}\n"\
|
257
206
|
"Sheets: #{sheets.join(', ')}\n"
|
258
207
|
n = 1
|
259
|
-
sheets.each do|sheet|
|
208
|
+
sheets.each do |sheet|
|
260
209
|
self.default_sheet = sheet
|
261
|
-
result <<
|
210
|
+
result << "Sheet " + n.to_s + ":\n"
|
262
211
|
if first_row
|
263
212
|
result << " First row: #{first_row}\n"
|
264
213
|
result << " Last row: #{last_row}\n"
|
265
214
|
result << " First column: #{::Roo::Utils.number_to_letter(first_column)}\n"
|
266
215
|
result << " Last column: #{::Roo::Utils.number_to_letter(last_column)}"
|
267
216
|
else
|
268
|
-
result <<
|
217
|
+
result << " - empty -"
|
269
218
|
end
|
270
219
|
result << "\n" if sheet != sheets.last
|
271
220
|
n += 1
|
@@ -274,32 +223,6 @@ class Roo::Base
|
|
274
223
|
end
|
275
224
|
end
|
276
225
|
|
277
|
-
# returns an XML representation of all sheets of a spreadsheet file
|
278
|
-
def to_xml
|
279
|
-
Nokogiri::XML::Builder.new do |xml|
|
280
|
-
xml.spreadsheet do
|
281
|
-
sheets.each do |sheet|
|
282
|
-
self.default_sheet = sheet
|
283
|
-
xml.sheet(name: sheet) do |x|
|
284
|
-
if first_row && last_row && first_column && last_column
|
285
|
-
# sonst gibt es Fehler bei leeren Blaettern
|
286
|
-
first_row.upto(last_row) do |row|
|
287
|
-
first_column.upto(last_column) do |col|
|
288
|
-
next if empty?(row, col)
|
289
|
-
|
290
|
-
x.cell(cell(row, col),
|
291
|
-
row: row,
|
292
|
-
column: col,
|
293
|
-
type: celltype(row, col))
|
294
|
-
end
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
299
|
-
end
|
300
|
-
end.to_xml
|
301
|
-
end
|
302
|
-
|
303
226
|
# when a method like spreadsheet.a42 is called
|
304
227
|
# convert it to a call of spreadsheet.cell('a',42)
|
305
228
|
def method_missing(m, *args)
|
@@ -365,39 +288,42 @@ class Roo::Base
|
|
365
288
|
clean_sheet_if_need(options)
|
366
289
|
search_or_set_header(options)
|
367
290
|
headers = @headers ||
|
368
|
-
|
369
|
-
[cell(@header_line, col)
|
370
|
-
end
|
291
|
+
(first_column..last_column).each_with_object({}) do |col, hash|
|
292
|
+
hash[cell(@header_line, col)] = col
|
293
|
+
end
|
371
294
|
|
372
295
|
@header_line.upto(last_row) do |line|
|
373
|
-
yield(
|
296
|
+
yield(headers.each_with_object({}) { |(k, v), hash| hash[k] = cell(line, v) })
|
374
297
|
end
|
375
298
|
end
|
376
299
|
end
|
377
300
|
|
378
301
|
def parse(options = {})
|
379
|
-
|
380
|
-
|
381
|
-
yield(row) if block_given?
|
382
|
-
ary << row
|
302
|
+
results = each(options).map do |row|
|
303
|
+
block_given? ? yield(row) : row
|
383
304
|
end
|
384
|
-
|
305
|
+
|
306
|
+
options[:headers] == true ? results : results.drop(1)
|
385
307
|
end
|
386
308
|
|
387
309
|
def row_with(query, return_headers = false)
|
388
310
|
line_no = 0
|
311
|
+
closest_mismatched_headers = []
|
389
312
|
each do |row|
|
390
313
|
line_no += 1
|
391
314
|
headers = query.map { |q| row.grep(q)[0] }.compact
|
392
|
-
|
393
315
|
if headers.length == query.length
|
394
316
|
@header_line = line_no
|
395
317
|
return return_headers ? headers : line_no
|
396
|
-
|
397
|
-
|
318
|
+
else
|
319
|
+
closest_mismatched_headers = headers if headers.length > closest_mismatched_headers.length
|
320
|
+
if line_no > 100
|
321
|
+
break
|
322
|
+
end
|
398
323
|
end
|
399
324
|
end
|
400
|
-
|
325
|
+
missing_headers = query.select { |q| closest_mismatched_headers.grep(q).empty? }
|
326
|
+
raise Roo::HeaderRowNotFoundError, missing_headers
|
401
327
|
end
|
402
328
|
|
403
329
|
protected
|
@@ -410,7 +336,7 @@ class Roo::Base
|
|
410
336
|
filename = File.basename(filename, File.extname(filename))
|
411
337
|
end
|
412
338
|
|
413
|
-
if uri?(filename) && (qs_begin = filename.rindex(
|
339
|
+
if uri?(filename) && (qs_begin = filename.rindex("?"))
|
414
340
|
filename = filename[0..qs_begin - 1]
|
415
341
|
end
|
416
342
|
exts = Array(exts)
|
@@ -436,7 +362,7 @@ class Roo::Base
|
|
436
362
|
# Diese Methode ist eine temp. Loesung, um zu erforschen, ob der
|
437
363
|
# Zugriff mit numerischen Keys schneller ist.
|
438
364
|
def key_to_num(str)
|
439
|
-
r, c = str.split(
|
365
|
+
r, c = str.split(",")
|
440
366
|
[r.to_i, c.to_i]
|
441
367
|
end
|
442
368
|
|
@@ -498,9 +424,9 @@ class Roo::Base
|
|
498
424
|
|
499
425
|
def find_by_conditions(options)
|
500
426
|
rows = first_row.upto(last_row)
|
501
|
-
header_for =
|
502
|
-
[col
|
503
|
-
end
|
427
|
+
header_for = 1.upto(last_column).each_with_object({}) do |col, hash|
|
428
|
+
hash[col] = cell(@header_line, col)
|
429
|
+
end
|
504
430
|
|
505
431
|
# are all conditions met?
|
506
432
|
conditions = options[:conditions]
|
@@ -515,9 +441,9 @@ class Roo::Base
|
|
515
441
|
rows.map { |i| row(i) }
|
516
442
|
else
|
517
443
|
rows.map do |i|
|
518
|
-
|
519
|
-
[header_for.fetch(j)
|
520
|
-
end
|
444
|
+
1.upto(row(i).size).each_with_object({}) do |j, hash|
|
445
|
+
hash[header_for.fetch(j)] = cell(i, j)
|
446
|
+
end
|
521
447
|
end
|
522
448
|
end
|
523
449
|
end
|
@@ -535,7 +461,7 @@ class Roo::Base
|
|
535
461
|
|
536
462
|
def find_basename(filename)
|
537
463
|
if uri?(filename)
|
538
|
-
require
|
464
|
+
require "uri"
|
539
465
|
uri = URI.parse filename
|
540
466
|
File.basename(uri.path)
|
541
467
|
elsif !is_stream?(filename)
|
@@ -544,9 +470,9 @@ class Roo::Base
|
|
544
470
|
end
|
545
471
|
|
546
472
|
def make_tmpdir(prefix = nil, root = nil, &block)
|
547
|
-
warn
|
473
|
+
warn "[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead"
|
548
474
|
prefix = "#{Roo::TEMP_PREFIX}#{prefix}"
|
549
|
-
root ||= ENV[
|
475
|
+
root ||= ENV["ROO_TMP"]
|
550
476
|
|
551
477
|
if block_given?
|
552
478
|
# folder is deleted at end of block
|
@@ -565,14 +491,17 @@ class Roo::Base
|
|
565
491
|
end
|
566
492
|
|
567
493
|
def sanitize_value(v)
|
568
|
-
v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/,
|
494
|
+
v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/, "")
|
569
495
|
end
|
570
496
|
|
571
497
|
def set_headers(hash = {})
|
572
498
|
# try to find header row with all values or give an error
|
573
499
|
# then create new hash by indexing strings and keeping integers for header array
|
574
|
-
|
575
|
-
@headers =
|
500
|
+
header_row = row_with(hash.values, true)
|
501
|
+
@headers = {}
|
502
|
+
hash.each_with_index do |(key, _), index|
|
503
|
+
@headers[key] = header_index(header_row[index])
|
504
|
+
end
|
576
505
|
end
|
577
506
|
|
578
507
|
def header_index(query)
|
@@ -605,17 +534,17 @@ class Roo::Base
|
|
605
534
|
end
|
606
535
|
|
607
536
|
def uri?(filename)
|
608
|
-
filename.start_with?(
|
537
|
+
filename.start_with?("http://", "https://", "ftp://")
|
609
538
|
rescue
|
610
539
|
false
|
611
540
|
end
|
612
541
|
|
613
542
|
def download_uri(uri, tmpdir)
|
614
|
-
require
|
543
|
+
require "open-uri"
|
615
544
|
tempfilename = File.join(tmpdir, find_basename(uri))
|
616
545
|
begin
|
617
|
-
File.open(tempfilename,
|
618
|
-
open(uri,
|
546
|
+
File.open(tempfilename, "wb") do |file|
|
547
|
+
open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
|
619
548
|
file.write(net.read)
|
620
549
|
end
|
621
550
|
end
|
@@ -626,15 +555,15 @@ class Roo::Base
|
|
626
555
|
end
|
627
556
|
|
628
557
|
def open_from_stream(stream, tmpdir)
|
629
|
-
tempfilename = File.join(tmpdir,
|
630
|
-
File.open(tempfilename,
|
558
|
+
tempfilename = File.join(tmpdir, "spreadsheet")
|
559
|
+
File.open(tempfilename, "wb") do |file|
|
631
560
|
file.write(stream[7..-1])
|
632
561
|
end
|
633
|
-
File.join(tmpdir,
|
562
|
+
File.join(tmpdir, "spreadsheet")
|
634
563
|
end
|
635
564
|
|
636
565
|
def unzip(filename, tmpdir)
|
637
|
-
require
|
566
|
+
require "zip/filesystem"
|
638
567
|
|
639
568
|
Zip::File.open(filename) do |zip|
|
640
569
|
process_zipfile_packed(zip, tmpdir)
|
@@ -647,7 +576,7 @@ class Roo::Base
|
|
647
576
|
when nil
|
648
577
|
fail ArgumentError, "Error: sheet 'nil' not valid"
|
649
578
|
when Integer
|
650
|
-
sheets.fetch(sheet
|
579
|
+
sheets.fetch(sheet) do
|
651
580
|
fail RangeError, "sheet index #{sheet} not found"
|
652
581
|
end
|
653
582
|
when String
|
@@ -659,92 +588,20 @@ class Roo::Base
|
|
659
588
|
end
|
660
589
|
end
|
661
590
|
|
662
|
-
def process_zipfile_packed(zip, tmpdir, path =
|
591
|
+
def process_zipfile_packed(zip, tmpdir, path = "")
|
663
592
|
if zip.file.file? path
|
664
593
|
# extract and return filename
|
665
|
-
File.open(File.join(tmpdir, path),
|
594
|
+
File.open(File.join(tmpdir, path), "wb") do |file|
|
666
595
|
file.write(zip.read(path))
|
667
596
|
end
|
668
597
|
File.join(tmpdir, path)
|
669
598
|
else
|
670
599
|
ret = nil
|
671
|
-
path +=
|
600
|
+
path += "/" unless path.empty?
|
672
601
|
zip.dir.foreach(path) do |filename|
|
673
602
|
ret = process_zipfile_packed(zip, tmpdir, path + filename)
|
674
603
|
end
|
675
604
|
ret
|
676
605
|
end
|
677
606
|
end
|
678
|
-
|
679
|
-
# Write all cells to the csv file. File can be a filename or nil. If the this
|
680
|
-
# parameter is nil the output goes to STDOUT
|
681
|
-
def write_csv_content(file = nil, sheet = nil, separator = ',')
|
682
|
-
file ||= STDOUT
|
683
|
-
return unless first_row(sheet) # The sheet is empty
|
684
|
-
|
685
|
-
1.upto(last_row(sheet)) do |row|
|
686
|
-
1.upto(last_column(sheet)) do |col|
|
687
|
-
file.print(separator) if col > 1
|
688
|
-
file.print cell_to_csv(row, col, sheet)
|
689
|
-
end
|
690
|
-
file.print("\n")
|
691
|
-
end
|
692
|
-
end
|
693
|
-
|
694
|
-
# The content of a cell in the csv output
|
695
|
-
def cell_to_csv(row, col, sheet)
|
696
|
-
return '' if empty?(row, col, sheet)
|
697
|
-
|
698
|
-
onecell = cell(row, col, sheet)
|
699
|
-
|
700
|
-
case celltype(row, col, sheet)
|
701
|
-
when :string
|
702
|
-
%("#{onecell.gsub('"', '""')}") unless onecell.empty?
|
703
|
-
when :boolean
|
704
|
-
# TODO: this only works for excelx
|
705
|
-
onecell = self.sheet_for(sheet).cells[[row, col]].formatted_value
|
706
|
-
%("#{onecell.gsub('"', '""').downcase}")
|
707
|
-
when :float, :percentage
|
708
|
-
if onecell == onecell.to_i
|
709
|
-
onecell.to_i.to_s
|
710
|
-
else
|
711
|
-
onecell.to_s
|
712
|
-
end
|
713
|
-
when :formula
|
714
|
-
case onecell
|
715
|
-
when String
|
716
|
-
%("#{onecell.gsub('"', '""')}") unless onecell.empty?
|
717
|
-
when Integer
|
718
|
-
onecell.to_s
|
719
|
-
when Float
|
720
|
-
if onecell == onecell.to_i
|
721
|
-
onecell.to_i.to_s
|
722
|
-
else
|
723
|
-
onecell.to_s
|
724
|
-
end
|
725
|
-
when DateTime
|
726
|
-
onecell.to_s
|
727
|
-
else
|
728
|
-
fail "unhandled onecell-class #{onecell.class}"
|
729
|
-
end
|
730
|
-
when :date, :datetime
|
731
|
-
onecell.to_s
|
732
|
-
when :time
|
733
|
-
integer_to_timestring(onecell)
|
734
|
-
when :link
|
735
|
-
%("#{onecell.url.gsub('"', '""')}")
|
736
|
-
else
|
737
|
-
fail "unhandled celltype #{celltype(row, col, sheet)}"
|
738
|
-
end || ''
|
739
|
-
end
|
740
|
-
|
741
|
-
# converts an integer value to a time string like '02:05:06'
|
742
|
-
def integer_to_timestring(content)
|
743
|
-
h = (content / 3600.0).floor
|
744
|
-
content -= h * 3600
|
745
|
-
m = (content / 60.0).floor
|
746
|
-
content -= m * 60
|
747
|
-
s = content
|
748
|
-
sprintf('%02d:%02d:%02d', h, m, s)
|
749
|
-
end
|
750
607
|
end
|
data/lib/roo/constants.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roo
|
2
|
-
ROO_EXCEL_NOTICE = "Excel support has been extracted to roo-xls due to its dependency on the GPL'd spreadsheet gem. Install roo-xls to use Roo::Excel."
|
3
|
-
ROO_EXCELML_NOTICE = "Excel SpreadsheetML support has been extracted to roo-xls. Install roo-xls to use Roo::Excel2003XML."
|
4
|
-
ROO_GOOGLE_NOTICE = "Google support has been extracted to roo-google. Install roo-google to use Roo::Google."
|
4
|
+
ROO_EXCEL_NOTICE = "Excel support has been extracted to roo-xls due to its dependency on the GPL'd spreadsheet gem. Install roo-xls to use Roo::Excel."
|
5
|
+
ROO_EXCELML_NOTICE = "Excel SpreadsheetML support has been extracted to roo-xls. Install roo-xls to use Roo::Excel2003XML."
|
6
|
+
ROO_GOOGLE_NOTICE = "Google support has been extracted to roo-google. Install roo-google to use Roo::Google."
|
5
7
|
end
|