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/base.rb
CHANGED
@@ -4,12 +4,21 @@ require 'tmpdir'
|
|
4
4
|
require 'stringio'
|
5
5
|
require 'nokogiri'
|
6
6
|
require 'roo/utils'
|
7
|
+
require "roo/formatters/base"
|
8
|
+
require "roo/formatters/csv"
|
9
|
+
require "roo/formatters/matrix"
|
10
|
+
require "roo/formatters/xml"
|
11
|
+
require "roo/formatters/yaml"
|
7
12
|
|
8
13
|
# Base class for all other types of spreadsheets
|
9
14
|
class Roo::Base
|
10
15
|
include Enumerable
|
16
|
+
include Roo::Formatters::Base
|
17
|
+
include Roo::Formatters::CSV
|
18
|
+
include Roo::Formatters::Matrix
|
19
|
+
include Roo::Formatters::XML
|
20
|
+
include Roo::Formatters::YAML
|
11
21
|
|
12
|
-
TEMP_PREFIX = 'roo_'.freeze
|
13
22
|
MAX_ROW_COL = 999_999.freeze
|
14
23
|
MIN_ROW_COL = 0.freeze
|
15
24
|
|
@@ -18,6 +27,15 @@ class Roo::Base
|
|
18
27
|
# sets the line with attribute names (default: 1)
|
19
28
|
attr_accessor :header_line
|
20
29
|
|
30
|
+
def self.TEMP_PREFIX
|
31
|
+
warn '[DEPRECATION] please access TEMP_PREFIX via Roo::TEMP_PREFIX'
|
32
|
+
Roo::TEMP_PREFIX
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.finalize(object_id)
|
36
|
+
proc { finalize_tempdirs(object_id) }
|
37
|
+
end
|
38
|
+
|
21
39
|
def initialize(filename, options = {}, _file_warning = :error, _tmpdir = nil)
|
22
40
|
@filename = filename
|
23
41
|
@options = options
|
@@ -32,14 +50,12 @@ class Roo::Base
|
|
32
50
|
@last_column = {}
|
33
51
|
|
34
52
|
@header_line = 1
|
35
|
-
rescue => e # clean up any temp files, but only if an error was raised
|
36
|
-
close
|
37
|
-
raise e
|
38
53
|
end
|
39
54
|
|
40
55
|
def close
|
41
|
-
|
42
|
-
|
56
|
+
if self.class.respond_to?(:finalize_tempdirs)
|
57
|
+
self.class.finalize_tempdirs(object_id)
|
58
|
+
end
|
43
59
|
nil
|
44
60
|
end
|
45
61
|
|
@@ -91,7 +107,7 @@ class Roo::Base
|
|
91
107
|
first_column = [first_column, key.last.to_i].min
|
92
108
|
last_column = [last_column, key.last.to_i].max
|
93
109
|
end if @cell[sheet]
|
94
|
-
{first_row: first_row, first_column: first_column, last_row: last_row, last_column: last_column}
|
110
|
+
{ first_row: first_row, first_column: first_column, last_row: last_row, last_column: last_column }
|
95
111
|
end
|
96
112
|
|
97
113
|
%w(first_row last_row first_column last_column).each do |key|
|
@@ -103,74 +119,8 @@ class Roo::Base
|
|
103
119
|
EOS
|
104
120
|
end
|
105
121
|
|
106
|
-
# returns a rectangular area (default: all cells) as yaml-output
|
107
|
-
# you can add additional attributes with the prefix parameter like:
|
108
|
-
# oo.to_yaml({"file"=>"flightdata_2007-06-26", "sheet" => "1"})
|
109
|
-
def to_yaml(prefix = {}, from_row = nil, from_column = nil, to_row = nil, to_column = nil, sheet = default_sheet)
|
110
|
-
return '' unless first_row # empty result if there is no first_row in a sheet
|
111
|
-
|
112
|
-
from_row ||= first_row(sheet)
|
113
|
-
to_row ||= last_row(sheet)
|
114
|
-
from_column ||= first_column(sheet)
|
115
|
-
to_column ||= last_column(sheet)
|
116
|
-
|
117
|
-
result = "--- \n"
|
118
|
-
from_row.upto(to_row) do |row|
|
119
|
-
from_column.upto(to_column) do |col|
|
120
|
-
unless empty?(row, col, sheet)
|
121
|
-
result << "cell_#{row}_#{col}: \n"
|
122
|
-
prefix.each do|k, v|
|
123
|
-
result << " #{k}: #{v} \n"
|
124
|
-
end
|
125
|
-
result << " row: #{row} \n"
|
126
|
-
result << " col: #{col} \n"
|
127
|
-
result << " celltype: #{celltype(row, col, sheet)} \n"
|
128
|
-
value = cell(row, col, sheet)
|
129
|
-
if celltype(row, col, sheet) == :time
|
130
|
-
value = integer_to_timestring(value)
|
131
|
-
end
|
132
|
-
result << " value: #{value} \n"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
result
|
137
|
-
end
|
138
|
-
|
139
|
-
# write the current spreadsheet to stdout or into a file
|
140
|
-
def to_csv(filename = nil, separator = ',', sheet = default_sheet)
|
141
|
-
if filename
|
142
|
-
File.open(filename, 'w') do |file|
|
143
|
-
write_csv_content(file, sheet, separator)
|
144
|
-
end
|
145
|
-
true
|
146
|
-
else
|
147
|
-
sio = ::StringIO.new
|
148
|
-
write_csv_content(sio, sheet, separator)
|
149
|
-
sio.rewind
|
150
|
-
sio.read
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# returns a matrix object from the whole sheet or a rectangular area of a sheet
|
155
|
-
def to_matrix(from_row = nil, from_column = nil, to_row = nil, to_column = nil, sheet = default_sheet)
|
156
|
-
require 'matrix'
|
157
|
-
|
158
|
-
return Matrix.empty unless first_row
|
159
|
-
|
160
|
-
from_row ||= first_row(sheet)
|
161
|
-
to_row ||= last_row(sheet)
|
162
|
-
from_column ||= first_column(sheet)
|
163
|
-
to_column ||= last_column(sheet)
|
164
|
-
|
165
|
-
Matrix.rows(from_row.upto(to_row).map do |row|
|
166
|
-
from_column.upto(to_column).map do |col|
|
167
|
-
cell(row, col, sheet)
|
168
|
-
end
|
169
|
-
end)
|
170
|
-
end
|
171
|
-
|
172
122
|
def inspect
|
173
|
-
"<##{
|
123
|
+
"<##{self.class}:#{object_id.to_s(8)} #{instance_variables.join(' ')}>"
|
174
124
|
end
|
175
125
|
|
176
126
|
# find a row either by row number or a condition
|
@@ -180,7 +130,7 @@ class Roo::Base
|
|
180
130
|
options = (args.last.is_a?(Hash) ? args.pop : {})
|
181
131
|
|
182
132
|
case args[0]
|
183
|
-
when
|
133
|
+
when Integer
|
184
134
|
find_by_row(args[0])
|
185
135
|
when :all
|
186
136
|
find_by_conditions(options)
|
@@ -217,15 +167,15 @@ class Roo::Base
|
|
217
167
|
row, col = normalize(row, col)
|
218
168
|
cell_type = cell_type_by_value(value)
|
219
169
|
set_value(row, col, value, sheet)
|
220
|
-
set_type(row, col, cell_type
|
170
|
+
set_type(row, col, cell_type, sheet)
|
221
171
|
end
|
222
172
|
|
223
173
|
def cell_type_by_value(value)
|
224
174
|
case value
|
225
|
-
when
|
175
|
+
when Integer then :float
|
226
176
|
when String, Float then :string
|
227
177
|
else
|
228
|
-
|
178
|
+
fail ArgumentError, "Type for #{value} not set"
|
229
179
|
end
|
230
180
|
end
|
231
181
|
|
@@ -256,13 +206,13 @@ class Roo::Base
|
|
256
206
|
sheets.each do|sheet|
|
257
207
|
self.default_sheet = sheet
|
258
208
|
result << 'Sheet ' + n.to_s + ":\n"
|
259
|
-
|
260
|
-
result << ' - empty -'
|
261
|
-
else
|
209
|
+
if first_row
|
262
210
|
result << " First row: #{first_row}\n"
|
263
211
|
result << " Last row: #{last_row}\n"
|
264
212
|
result << " First column: #{::Roo::Utils.number_to_letter(first_column)}\n"
|
265
213
|
result << " Last column: #{::Roo::Utils.number_to_letter(last_column)}"
|
214
|
+
else
|
215
|
+
result << ' - empty -'
|
266
216
|
end
|
267
217
|
result << "\n" if sheet != sheets.last
|
268
218
|
n += 1
|
@@ -271,38 +221,12 @@ class Roo::Base
|
|
271
221
|
end
|
272
222
|
end
|
273
223
|
|
274
|
-
# returns an XML representation of all sheets of a spreadsheet file
|
275
|
-
def to_xml
|
276
|
-
Nokogiri::XML::Builder.new do |xml|
|
277
|
-
xml.spreadsheet do
|
278
|
-
sheets.each do |sheet|
|
279
|
-
self.default_sheet = sheet
|
280
|
-
xml.sheet(name: sheet) do |x|
|
281
|
-
if first_row && last_row && first_column && last_column
|
282
|
-
# sonst gibt es Fehler bei leeren Blaettern
|
283
|
-
first_row.upto(last_row) do |row|
|
284
|
-
first_column.upto(last_column) do |col|
|
285
|
-
unless empty?(row, col)
|
286
|
-
x.cell(cell(row, col),
|
287
|
-
row: row,
|
288
|
-
column: col,
|
289
|
-
type: celltype(row, col))
|
290
|
-
end
|
291
|
-
end
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end.to_xml
|
298
|
-
end
|
299
|
-
|
300
224
|
# when a method like spreadsheet.a42 is called
|
301
225
|
# convert it to a call of spreadsheet.cell('a',42)
|
302
226
|
def method_missing(m, *args)
|
303
227
|
# #aa42 => #cell('aa',42)
|
304
228
|
# #aa42('Sheet1') => #cell('aa',42,'Sheet1')
|
305
|
-
if m =~ /^([a-z]+)(\d)$/
|
229
|
+
if m =~ /^([a-z]+)(\d+)$/
|
306
230
|
col = ::Roo::Utils.letter_to_number(Regexp.last_match[1])
|
307
231
|
row = Regexp.last_match[2].to_i
|
308
232
|
if args.empty?
|
@@ -318,7 +242,7 @@ class Roo::Base
|
|
318
242
|
# access different worksheets by calling spreadsheet.sheet(1)
|
319
243
|
# or spreadsheet.sheet('SHEETNAME')
|
320
244
|
def sheet(index, name = false)
|
321
|
-
self.default_sheet = String
|
245
|
+
self.default_sheet = index.is_a?(::String) ? index : sheets[index]
|
322
246
|
name ? [default_sheet, self] : self
|
323
247
|
end
|
324
248
|
|
@@ -352,35 +276,32 @@ class Roo::Base
|
|
352
276
|
# control characters and white spaces around columns
|
353
277
|
|
354
278
|
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
|
279
|
+
return to_enum(:each, options) unless block_given?
|
280
|
+
|
281
|
+
if options.empty?
|
282
|
+
1.upto(last_row) do |line|
|
283
|
+
yield row(line)
|
371
284
|
end
|
372
285
|
else
|
373
|
-
|
286
|
+
clean_sheet_if_need(options)
|
287
|
+
search_or_set_header(options)
|
288
|
+
headers = @headers ||
|
289
|
+
Hash[(first_column..last_column).map do |col|
|
290
|
+
[cell(@header_line, col), col]
|
291
|
+
end]
|
292
|
+
|
293
|
+
@header_line.upto(last_row) do |line|
|
294
|
+
yield(Hash[headers.map { |k, v| [k, cell(line, v)] }])
|
295
|
+
end
|
374
296
|
end
|
375
297
|
end
|
376
298
|
|
377
299
|
def parse(options = {})
|
378
|
-
|
379
|
-
|
380
|
-
yield(row) if block_given?
|
381
|
-
ary << row
|
300
|
+
results = each(options).map do |row|
|
301
|
+
block_given? ? yield(row) : row
|
382
302
|
end
|
383
|
-
|
303
|
+
|
304
|
+
options[:headers] == true ? results : results.drop(1)
|
384
305
|
end
|
385
306
|
|
386
307
|
def row_with(query, return_headers = false)
|
@@ -393,38 +314,40 @@ class Roo::Base
|
|
393
314
|
@header_line = line_no
|
394
315
|
return return_headers ? headers : line_no
|
395
316
|
elsif line_no > 100
|
396
|
-
|
317
|
+
raise Roo::HeaderRowNotFoundError
|
397
318
|
end
|
398
319
|
end
|
399
|
-
|
320
|
+
raise Roo::HeaderRowNotFoundError
|
400
321
|
end
|
401
322
|
|
402
323
|
protected
|
403
324
|
|
404
|
-
def file_type_check(filename,
|
325
|
+
def file_type_check(filename, exts, name, warning_level, packed = nil)
|
405
326
|
if packed == :zip
|
406
|
-
#
|
407
|
-
#
|
408
|
-
#
|
327
|
+
# spreadsheet.ods.zip => spreadsheet.ods
|
328
|
+
# Decompression is not performed here, only the 'zip' extension
|
329
|
+
# is removed from the file.
|
409
330
|
filename = File.basename(filename, File.extname(filename))
|
410
331
|
end
|
411
332
|
|
412
|
-
if uri?(filename) && qs_begin = filename.rindex('?')
|
333
|
+
if uri?(filename) && (qs_begin = filename.rindex('?'))
|
413
334
|
filename = filename[0..qs_begin - 1]
|
414
335
|
end
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
336
|
+
exts = Array(exts)
|
337
|
+
|
338
|
+
return if exts.include?(File.extname(filename).downcase)
|
339
|
+
|
340
|
+
case warning_level
|
341
|
+
when :error
|
342
|
+
warn file_type_warning_message(filename, exts)
|
343
|
+
fail TypeError, "#{filename} is not #{name} file"
|
344
|
+
when :warning
|
345
|
+
warn "are you sure, this is #{name} spreadsheet file?"
|
346
|
+
warn file_type_warning_message(filename, exts)
|
347
|
+
when :ignore
|
348
|
+
# ignore
|
349
|
+
else
|
350
|
+
fail "#{warning_level} illegal state of file_warning"
|
428
351
|
end
|
429
352
|
end
|
430
353
|
|
@@ -448,10 +371,6 @@ class Roo::Base
|
|
448
371
|
|
449
372
|
private
|
450
373
|
|
451
|
-
def track_tmpdir!(tmpdir)
|
452
|
-
(@tmpdirs ||= []) << tmpdir
|
453
|
-
end
|
454
|
-
|
455
374
|
def clean_sheet_if_need(options)
|
456
375
|
return unless options[:clean]
|
457
376
|
options.delete(:clean)
|
@@ -475,16 +394,18 @@ class Roo::Base
|
|
475
394
|
return if is_stream?(filename)
|
476
395
|
filename = download_uri(filename, tmpdir) if uri?(filename)
|
477
396
|
filename = unzip(filename, tmpdir) if packed == :zip
|
478
|
-
|
479
|
-
|
480
|
-
|
397
|
+
|
398
|
+
fail IOError, "file #{filename} does not exist" unless File.file?(filename)
|
399
|
+
|
481
400
|
filename
|
482
401
|
end
|
483
402
|
|
484
|
-
def file_type_warning_message(filename,
|
485
|
-
|
403
|
+
def file_type_warning_message(filename, exts)
|
404
|
+
*rest, last_ext = exts
|
405
|
+
ext_list = rest.any? ? "#{rest.join(', ')} or #{last_ext}" : last_ext
|
406
|
+
"use #{Roo::CLASS_FOR_EXTENSION.fetch(last_ext.sub('.', '').to_sym)}.new to handle #{ext_list} spreadsheet files. This has #{File.extname(filename).downcase}"
|
486
407
|
rescue KeyError
|
487
|
-
raise "unknown file
|
408
|
+
raise "unknown file types: #{ext_list}"
|
488
409
|
end
|
489
410
|
|
490
411
|
def find_by_row(row_index)
|
@@ -532,14 +453,26 @@ class Roo::Base
|
|
532
453
|
initialize(@filename)
|
533
454
|
end
|
534
455
|
|
456
|
+
def find_basename(filename)
|
457
|
+
if uri?(filename)
|
458
|
+
require 'uri'
|
459
|
+
uri = URI.parse filename
|
460
|
+
File.basename(uri.path)
|
461
|
+
elsif !is_stream?(filename)
|
462
|
+
File.basename(filename)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
535
466
|
def make_tmpdir(prefix = nil, root = nil, &block)
|
536
|
-
|
537
|
-
|
467
|
+
warn '[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead'
|
468
|
+
prefix = "#{Roo::TEMP_PREFIX}#{prefix}"
|
469
|
+
root ||= ENV['ROO_TMP']
|
470
|
+
|
471
|
+
if block_given?
|
472
|
+
# folder is deleted at end of block
|
473
|
+
::Dir.mktmpdir(prefix, root, &block)
|
538
474
|
else
|
539
|
-
|
540
|
-
end
|
541
|
-
::Dir.mktmpdir(prefix, root || ENV['ROO_TMP'], &block).tap do |result|
|
542
|
-
block_given? || track_tmpdir!(result)
|
475
|
+
self.class.make_tempdir(self, prefix, root)
|
543
476
|
end
|
544
477
|
end
|
545
478
|
|
@@ -577,7 +510,7 @@ class Roo::Base
|
|
577
510
|
# converts cell coordinate to numeric values of row,col
|
578
511
|
def normalize(row, col)
|
579
512
|
if row.is_a?(::String)
|
580
|
-
if col.is_a?(::
|
513
|
+
if col.is_a?(::Integer)
|
581
514
|
# ('A',1):
|
582
515
|
# ('B', 5) -> (5, 2)
|
583
516
|
row, col = col, row
|
@@ -585,21 +518,21 @@ class Roo::Base
|
|
585
518
|
fail ArgumentError
|
586
519
|
end
|
587
520
|
end
|
588
|
-
|
589
|
-
|
590
|
-
|
521
|
+
|
522
|
+
col = ::Roo::Utils.letter_to_number(col) if col.is_a?(::String)
|
523
|
+
|
591
524
|
[row, col]
|
592
525
|
end
|
593
526
|
|
594
527
|
def uri?(filename)
|
595
|
-
filename.start_with?('http://', 'https://')
|
528
|
+
filename.start_with?('http://', 'https://', 'ftp://')
|
596
529
|
rescue
|
597
530
|
false
|
598
531
|
end
|
599
532
|
|
600
533
|
def download_uri(uri, tmpdir)
|
601
534
|
require 'open-uri'
|
602
|
-
tempfilename = File.join(tmpdir,
|
535
|
+
tempfilename = File.join(tmpdir, find_basename(uri))
|
603
536
|
begin
|
604
537
|
File.open(tempfilename, 'wb') do |file|
|
605
538
|
open(uri, 'User-Agent' => "Ruby/#{RUBY_VERSION}") do |net|
|
@@ -633,12 +566,12 @@ class Roo::Base
|
|
633
566
|
case sheet
|
634
567
|
when nil
|
635
568
|
fail ArgumentError, "Error: sheet 'nil' not valid"
|
636
|
-
when
|
569
|
+
when Integer
|
637
570
|
sheets.fetch(sheet - 1) do
|
638
571
|
fail RangeError, "sheet index #{sheet} not found"
|
639
572
|
end
|
640
573
|
when String
|
641
|
-
unless sheets.include?
|
574
|
+
unless sheets.include?(sheet)
|
642
575
|
fail RangeError, "sheet '#{sheet}' not found"
|
643
576
|
end
|
644
577
|
else
|
@@ -662,74 +595,4 @@ class Roo::Base
|
|
662
595
|
ret
|
663
596
|
end
|
664
597
|
end
|
665
|
-
|
666
|
-
# Write all cells to the csv file. File can be a filename or nil. If the this
|
667
|
-
# parameter is nil the output goes to STDOUT
|
668
|
-
def write_csv_content(file = nil, sheet = nil, separator = ',')
|
669
|
-
file ||= STDOUT
|
670
|
-
if first_row(sheet) # sheet is not empty
|
671
|
-
1.upto(last_row(sheet)) do |row|
|
672
|
-
1.upto(last_column(sheet)) do |col|
|
673
|
-
file.print(separator) if col > 1
|
674
|
-
file.print cell_to_csv(row, col, sheet)
|
675
|
-
end
|
676
|
-
file.print("\n")
|
677
|
-
end # sheet not empty
|
678
|
-
end
|
679
|
-
end
|
680
|
-
|
681
|
-
# The content of a cell in the csv output
|
682
|
-
def cell_to_csv(row, col, sheet)
|
683
|
-
if empty?(row, col, sheet)
|
684
|
-
''
|
685
|
-
else
|
686
|
-
onecell = cell(row, col, sheet)
|
687
|
-
|
688
|
-
case celltype(row, col, sheet)
|
689
|
-
when :string
|
690
|
-
%("#{onecell.gsub('"', '""')}") unless onecell.empty?
|
691
|
-
when :boolean
|
692
|
-
%("#{onecell.gsub('"', '""').downcase}")
|
693
|
-
when :float, :percentage
|
694
|
-
if onecell == onecell.to_i
|
695
|
-
onecell.to_i.to_s
|
696
|
-
else
|
697
|
-
onecell.to_s
|
698
|
-
end
|
699
|
-
when :formula
|
700
|
-
case onecell
|
701
|
-
when String
|
702
|
-
%("#{onecell.gsub('"', '""')}") unless onecell.empty?
|
703
|
-
when Float
|
704
|
-
if onecell == onecell.to_i
|
705
|
-
onecell.to_i.to_s
|
706
|
-
else
|
707
|
-
onecell.to_s
|
708
|
-
end
|
709
|
-
when DateTime
|
710
|
-
onecell.to_s
|
711
|
-
else
|
712
|
-
fail "unhandled onecell-class #{onecell.class}"
|
713
|
-
end
|
714
|
-
when :date, :datetime
|
715
|
-
onecell.to_s
|
716
|
-
when :time
|
717
|
-
integer_to_timestring(onecell)
|
718
|
-
when :link
|
719
|
-
%("#{onecell.url.gsub('"', '""')}")
|
720
|
-
else
|
721
|
-
fail "unhandled celltype #{celltype(row, col, sheet)}"
|
722
|
-
end || ''
|
723
|
-
end
|
724
|
-
end
|
725
|
-
|
726
|
-
# converts an integer value to a time string like '02:05:06'
|
727
|
-
def integer_to_timestring(content)
|
728
|
-
h = (content / 3600.0).floor
|
729
|
-
content = content - h * 3600
|
730
|
-
m = (content / 60.0).floor
|
731
|
-
content = content - m * 60
|
732
|
-
s = content
|
733
|
-
sprintf('%02d:%02d:%02d', h, m, s)
|
734
|
-
end
|
735
598
|
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
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.".freeze
|
3
|
+
ROO_EXCELML_NOTICE = "Excel SpreadsheetML support has been extracted to roo-xls. Install roo-xls to use Roo::Excel2003XML.".freeze
|
4
|
+
ROO_GOOGLE_NOTICE = "Google support has been extracted to roo-google. Install roo-google to use Roo::Google.".freeze
|
5
|
+
end
|