roo 2.3.0 → 2.10.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.
Files changed (95) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +17 -0
  3. data/.github/issue_template.md +16 -0
  4. data/.github/pull_request_template.md +14 -0
  5. data/.github/workflows/pull-request.yml +15 -0
  6. data/.github/workflows/ruby.yml +34 -0
  7. data/.gitignore +4 -0
  8. data/.rubocop.yml +186 -0
  9. data/CHANGELOG.md +148 -0
  10. data/Gemfile +4 -4
  11. data/LICENSE +2 -0
  12. data/README.md +84 -27
  13. data/Rakefile +1 -1
  14. data/lib/roo/base.rb +111 -237
  15. data/lib/roo/constants.rb +5 -3
  16. data/lib/roo/csv.rb +106 -85
  17. data/lib/roo/errors.rb +2 -0
  18. data/lib/roo/excelx/cell/base.rb +26 -12
  19. data/lib/roo/excelx/cell/boolean.rb +9 -6
  20. data/lib/roo/excelx/cell/date.rb +7 -7
  21. data/lib/roo/excelx/cell/datetime.rb +50 -44
  22. data/lib/roo/excelx/cell/empty.rb +3 -2
  23. data/lib/roo/excelx/cell/number.rb +60 -47
  24. data/lib/roo/excelx/cell/string.rb +3 -3
  25. data/lib/roo/excelx/cell/time.rb +17 -16
  26. data/lib/roo/excelx/cell.rb +11 -7
  27. data/lib/roo/excelx/comments.rb +3 -3
  28. data/lib/roo/excelx/coordinate.rb +11 -4
  29. data/lib/roo/excelx/extractor.rb +20 -3
  30. data/lib/roo/excelx/format.rb +38 -31
  31. data/lib/roo/excelx/images.rb +26 -0
  32. data/lib/roo/excelx/relationships.rb +12 -4
  33. data/lib/roo/excelx/shared.rb +10 -3
  34. data/lib/roo/excelx/shared_strings.rb +113 -9
  35. data/lib/roo/excelx/sheet.rb +49 -10
  36. data/lib/roo/excelx/sheet_doc.rb +101 -48
  37. data/lib/roo/excelx/styles.rb +4 -4
  38. data/lib/roo/excelx/workbook.rb +8 -3
  39. data/lib/roo/excelx.rb +85 -42
  40. data/lib/roo/formatters/base.rb +15 -0
  41. data/lib/roo/formatters/csv.rb +84 -0
  42. data/lib/roo/formatters/matrix.rb +23 -0
  43. data/lib/roo/formatters/xml.rb +31 -0
  44. data/lib/roo/formatters/yaml.rb +40 -0
  45. data/lib/roo/helpers/default_attr_reader.rb +20 -0
  46. data/lib/roo/helpers/weak_instance_cache.rb +41 -0
  47. data/lib/roo/open_office.rb +41 -27
  48. data/lib/roo/spreadsheet.rb +8 -2
  49. data/lib/roo/tempdir.rb +24 -0
  50. data/lib/roo/utils.rb +76 -26
  51. data/lib/roo/version.rb +1 -1
  52. data/lib/roo.rb +5 -0
  53. data/roo.gemspec +22 -12
  54. data/spec/lib/roo/base_spec.rb +65 -3
  55. data/spec/lib/roo/csv_spec.rb +19 -0
  56. data/spec/lib/roo/excelx/cell/time_spec.rb +15 -0
  57. data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
  58. data/spec/lib/roo/excelx/sheet_doc_spec.rb +11 -0
  59. data/spec/lib/roo/excelx_spec.rb +237 -5
  60. data/spec/lib/roo/openoffice_spec.rb +2 -2
  61. data/spec/lib/roo/spreadsheet_spec.rb +1 -1
  62. data/spec/lib/roo/strict_spec.rb +43 -0
  63. data/spec/lib/roo/utils_spec.rb +22 -9
  64. data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
  65. data/spec/lib/roo_spec.rb +0 -0
  66. data/spec/spec_helper.rb +2 -7
  67. data/test/excelx/cell/test_attr_reader_default.rb +72 -0
  68. data/test/excelx/cell/test_base.rb +6 -2
  69. data/test/excelx/cell/test_boolean.rb +1 -3
  70. data/test/excelx/cell/test_date.rb +1 -6
  71. data/test/excelx/cell/test_datetime.rb +7 -10
  72. data/test/excelx/cell/test_empty.rb +12 -2
  73. data/test/excelx/cell/test_number.rb +28 -4
  74. data/test/excelx/cell/test_string.rb +21 -3
  75. data/test/excelx/cell/test_time.rb +7 -10
  76. data/test/excelx/test_coordinate.rb +51 -0
  77. data/test/formatters/test_csv.rb +136 -0
  78. data/test/formatters/test_matrix.rb +76 -0
  79. data/test/formatters/test_xml.rb +78 -0
  80. data/test/formatters/test_yaml.rb +20 -0
  81. data/test/helpers/test_accessing_files.rb +81 -0
  82. data/test/helpers/test_comments.rb +43 -0
  83. data/test/helpers/test_formulas.rb +9 -0
  84. data/test/helpers/test_labels.rb +103 -0
  85. data/test/helpers/test_sheets.rb +55 -0
  86. data/test/helpers/test_styles.rb +62 -0
  87. data/test/roo/test_base.rb +182 -0
  88. data/test/roo/test_csv.rb +88 -0
  89. data/test/roo/test_excelx.rb +360 -0
  90. data/test/roo/test_libre_office.rb +9 -0
  91. data/test/roo/test_open_office.rb +289 -0
  92. data/test/test_helper.rb +129 -14
  93. data/test/test_roo.rb +60 -1765
  94. metadata +91 -21
  95. data/.travis.yml +0 -14
data/lib/roo/base.rb CHANGED
@@ -1,23 +1,39 @@
1
- # encoding: utf-8
2
-
3
- require 'tmpdir'
4
- require 'stringio'
5
- require 'nokogiri'
6
- require 'roo/utils'
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
- TEMP_PREFIX = 'roo_'.freeze
13
- MAX_ROW_COL = 999_999.freeze
14
- MIN_ROW_COL = 0.freeze
20
+ MAX_ROW_COL = 999_999
21
+ MIN_ROW_COL = 0
15
22
 
16
23
  attr_reader :headers
17
24
 
18
25
  # sets the line with attribute names (default: 1)
19
26
  attr_accessor :header_line
20
27
 
28
+ def self.TEMP_PREFIX
29
+ warn "[DEPRECATION] please access TEMP_PREFIX via Roo::TEMP_PREFIX"
30
+ Roo::TEMP_PREFIX
31
+ end
32
+
33
+ def self.finalize(object_id)
34
+ proc { finalize_tempdirs(object_id) }
35
+ end
36
+
21
37
  def initialize(filename, options = {}, _file_warning = :error, _tmpdir = nil)
22
38
  @filename = filename
23
39
  @options = options
@@ -32,14 +48,17 @@ class Roo::Base
32
48
  @last_column = {}
33
49
 
34
50
  @header_line = 1
35
- rescue => e # clean up any temp files, but only if an error was raised
36
- close
37
- raise e
38
51
  end
39
52
 
40
53
  def close
41
- return nil unless @tmpdirs
42
- @tmpdirs.each { |dir| ::FileUtils.remove_entry(dir) }
54
+ if self.class.respond_to?(:finalize_tempdirs)
55
+ self.class.finalize_tempdirs(object_id)
56
+ end
57
+
58
+ instance_variables.each do |instance_variable|
59
+ instance_variable_set(instance_variable, nil)
60
+ end
61
+
43
62
  nil
44
63
  end
45
64
 
@@ -48,10 +67,10 @@ class Roo::Base
48
67
  end
49
68
 
50
69
  # sets the working sheet in the document
51
- # 'sheet' can be a number (1 = first sheet) or the name of a sheet.
70
+ # 'sheet' can be a number (0 = first sheet) or the name of a sheet.
52
71
  def default_sheet=(sheet)
53
72
  validate_sheet!(sheet)
54
- @default_sheet = sheet
73
+ @default_sheet = sheet.is_a?(String) ? sheet : sheets[sheet]
55
74
  @first_row[sheet] = @last_row[sheet] = @first_column[sheet] = @last_column[sheet] = nil
56
75
  @cells_read[sheet] = false
57
76
  end
@@ -84,7 +103,7 @@ class Roo::Base
84
103
  def collect_last_row_col_for_sheet(sheet)
85
104
  first_row = first_column = MAX_ROW_COL
86
105
  last_row = last_column = MIN_ROW_COL
87
- @cell[sheet].each_pair do|key, value|
106
+ @cell[sheet].each_pair do |key, value|
88
107
  next unless value
89
108
  first_row = [first_row, key.first.to_i].min
90
109
  last_row = [last_row, key.first.to_i].max
@@ -94,80 +113,12 @@ class Roo::Base
94
113
  { first_row: first_row, first_column: first_column, last_row: last_row, last_column: last_column }
95
114
  end
96
115
 
97
- %w(first_row last_row first_column last_column).each do |key|
98
- class_eval <<-EOS, __FILE__, __LINE__ + 1
99
- def #{key}(sheet = default_sheet) # def first_row(sheet = default_sheet)
100
- read_cells(sheet) # read_cells(sheet)
101
- @#{key}[sheet] ||= first_last_row_col_for_sheet(sheet)[:#{key}] # @first_row[sheet] ||= first_last_row_col_for_sheet(sheet)[:first_row]
102
- end # end
103
- EOS
104
- end
105
-
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
- 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)
132
- end
133
- result << " value: #{value} \n"
134
- end
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]
135
121
  end
136
-
137
- result
138
- end
139
-
140
- # write the current spreadsheet to stdout or into a file
141
- def to_csv(filename = nil, separator = ',', sheet = default_sheet)
142
- if filename
143
- File.open(filename, 'w') do |file|
144
- write_csv_content(file, sheet, separator)
145
- end
146
- true
147
- else
148
- sio = ::StringIO.new
149
- write_csv_content(sio, sheet, separator)
150
- sio.rewind
151
- sio.read
152
- end
153
- end
154
-
155
- # returns a matrix object from the whole sheet or a rectangular area of a sheet
156
- def to_matrix(from_row = nil, from_column = nil, to_row = nil, to_column = nil, sheet = default_sheet)
157
- require 'matrix'
158
-
159
- return Matrix.empty unless first_row
160
-
161
- from_row ||= first_row(sheet)
162
- to_row ||= last_row(sheet)
163
- from_column ||= first_column(sheet)
164
- to_column ||= last_column(sheet)
165
-
166
- Matrix.rows(from_row.upto(to_row).map do |row|
167
- from_column.upto(to_column).map do |col|
168
- cell(row, col, sheet)
169
- end
170
- end)
171
122
  end
172
123
 
173
124
  def inspect
@@ -181,7 +132,7 @@ class Roo::Base
181
132
  options = (args.last.is_a?(Hash) ? args.pop : {})
182
133
 
183
134
  case args[0]
184
- when Fixnum
135
+ when Integer
185
136
  find_by_row(args[0])
186
137
  when :all
187
138
  find_by_conditions(options)
@@ -223,7 +174,7 @@ class Roo::Base
223
174
 
224
175
  def cell_type_by_value(value)
225
176
  case value
226
- when Fixnum then :float
177
+ when Integer then :float
227
178
  when String, Float then :string
228
179
  else
229
180
  fail ArgumentError, "Type for #{value} not set"
@@ -254,16 +205,16 @@ class Roo::Base
254
205
  "Number of sheets: #{sheets.size}\n"\
255
206
  "Sheets: #{sheets.join(', ')}\n"
256
207
  n = 1
257
- sheets.each do|sheet|
208
+ sheets.each do |sheet|
258
209
  self.default_sheet = sheet
259
- result << 'Sheet ' + n.to_s + ":\n"
210
+ result << "Sheet " + n.to_s + ":\n"
260
211
  if first_row
261
212
  result << " First row: #{first_row}\n"
262
213
  result << " Last row: #{last_row}\n"
263
214
  result << " First column: #{::Roo::Utils.number_to_letter(first_column)}\n"
264
215
  result << " Last column: #{::Roo::Utils.number_to_letter(last_column)}"
265
216
  else
266
- result << ' - empty -'
217
+ result << " - empty -"
267
218
  end
268
219
  result << "\n" if sheet != sheets.last
269
220
  n += 1
@@ -272,32 +223,6 @@ class Roo::Base
272
223
  end
273
224
  end
274
225
 
275
- # returns an XML representation of all sheets of a spreadsheet file
276
- def to_xml
277
- Nokogiri::XML::Builder.new do |xml|
278
- xml.spreadsheet do
279
- sheets.each do |sheet|
280
- self.default_sheet = sheet
281
- xml.sheet(name: sheet) do |x|
282
- if first_row && last_row && first_column && last_column
283
- # sonst gibt es Fehler bei leeren Blaettern
284
- first_row.upto(last_row) do |row|
285
- first_column.upto(last_column) do |col|
286
- next if empty?(row, col)
287
-
288
- x.cell(cell(row, col),
289
- row: row,
290
- column: col,
291
- type: celltype(row, col))
292
- end
293
- end
294
- end
295
- end
296
- end
297
- end
298
- end.to_xml
299
- end
300
-
301
226
  # when a method like spreadsheet.a42 is called
302
227
  # convert it to a call of spreadsheet.cell('a',42)
303
228
  def method_missing(m, *args)
@@ -325,6 +250,8 @@ class Roo::Base
325
250
 
326
251
  # iterate through all worksheets of a document
327
252
  def each_with_pagename
253
+ return to_enum(:each_with_pagename) { sheets.size } unless block_given?
254
+
328
255
  sheets.each do |s|
329
256
  yield sheet(s, true)
330
257
  end
@@ -363,39 +290,42 @@ class Roo::Base
363
290
  clean_sheet_if_need(options)
364
291
  search_or_set_header(options)
365
292
  headers = @headers ||
366
- Hash[(first_column..last_column).map do |col|
367
- [cell(@header_line, col), col]
368
- end]
293
+ (first_column..last_column).each_with_object({}) do |col, hash|
294
+ hash[cell(@header_line, col)] = col
295
+ end
369
296
 
370
297
  @header_line.upto(last_row) do |line|
371
- yield(Hash[headers.map { |k, v| [k, cell(line, v)] }])
298
+ yield(headers.each_with_object({}) { |(k, v), hash| hash[k] = cell(line, v) })
372
299
  end
373
300
  end
374
301
  end
375
302
 
376
303
  def parse(options = {})
377
- ary = []
378
- each(options) do |row|
379
- yield(row) if block_given?
380
- ary << row
304
+ results = each(options).map do |row|
305
+ block_given? ? yield(row) : row
381
306
  end
382
- ary
307
+
308
+ options[:headers] == true ? results : results.drop(1)
383
309
  end
384
310
 
385
311
  def row_with(query, return_headers = false)
386
312
  line_no = 0
313
+ closest_mismatched_headers = []
387
314
  each do |row|
388
315
  line_no += 1
389
316
  headers = query.map { |q| row.grep(q)[0] }.compact
390
-
391
317
  if headers.length == query.length
392
318
  @header_line = line_no
393
319
  return return_headers ? headers : line_no
394
- elsif line_no > 100
395
- raise Roo::HeaderRowNotFoundError
320
+ else
321
+ closest_mismatched_headers = headers if headers.length > closest_mismatched_headers.length
322
+ if line_no > 100
323
+ break
324
+ end
396
325
  end
397
326
  end
398
- raise Roo::HeaderRowNotFoundError
327
+ missing_headers = query.select { |q| closest_mismatched_headers.grep(q).empty? }
328
+ raise Roo::HeaderRowNotFoundError, missing_headers
399
329
  end
400
330
 
401
331
  protected
@@ -408,7 +338,7 @@ class Roo::Base
408
338
  filename = File.basename(filename, File.extname(filename))
409
339
  end
410
340
 
411
- if uri?(filename) && (qs_begin = filename.rindex('?'))
341
+ if uri?(filename) && (qs_begin = filename.rindex("?"))
412
342
  filename = filename[0..qs_begin - 1]
413
343
  end
414
344
  exts = Array(exts)
@@ -434,7 +364,7 @@ class Roo::Base
434
364
  # Diese Methode ist eine temp. Loesung, um zu erforschen, ob der
435
365
  # Zugriff mit numerischen Keys schneller ist.
436
366
  def key_to_num(str)
437
- r, c = str.split(',')
367
+ r, c = str.split(",")
438
368
  [r.to_i, c.to_i]
439
369
  end
440
370
 
@@ -449,10 +379,6 @@ class Roo::Base
449
379
 
450
380
  private
451
381
 
452
- def track_tmpdir!(tmpdir)
453
- (@tmpdirs ||= []) << tmpdir
454
- end
455
-
456
382
  def clean_sheet_if_need(options)
457
383
  return unless options[:clean]
458
384
  options.delete(:clean)
@@ -500,9 +426,9 @@ class Roo::Base
500
426
 
501
427
  def find_by_conditions(options)
502
428
  rows = first_row.upto(last_row)
503
- header_for = Hash[1.upto(last_column).map do |col|
504
- [col, cell(@header_line, col)]
505
- end]
429
+ header_for = 1.upto(last_column).each_with_object({}) do |col, hash|
430
+ hash[col] = cell(@header_line, col)
431
+ end
506
432
 
507
433
  # are all conditions met?
508
434
  conditions = options[:conditions]
@@ -517,9 +443,9 @@ class Roo::Base
517
443
  rows.map { |i| row(i) }
518
444
  else
519
445
  rows.map do |i|
520
- Hash[1.upto(row(i).size).map do |j|
521
- [header_for.fetch(j), cell(i, j)]
522
- end]
446
+ 1.upto(row(i).size).each_with_object({}) do |j, hash|
447
+ hash[header_for.fetch(j)] = cell(i, j)
448
+ end
523
449
  end
524
450
  end
525
451
  end
@@ -535,11 +461,26 @@ class Roo::Base
535
461
  initialize(@filename)
536
462
  end
537
463
 
464
+ def find_basename(filename)
465
+ if uri?(filename)
466
+ require "uri"
467
+ uri = URI.parse filename
468
+ File.basename(uri.path)
469
+ elsif !is_stream?(filename)
470
+ File.basename(filename)
471
+ end
472
+ end
473
+
538
474
  def make_tmpdir(prefix = nil, root = nil, &block)
539
- prefix = "#{TEMP_PREFIX}#{prefix}"
475
+ warn "[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead"
476
+ prefix = "#{Roo::TEMP_PREFIX}#{prefix}"
477
+ root ||= ENV["ROO_TMP"]
540
478
 
541
- ::Dir.mktmpdir(prefix, root || ENV['ROO_TMP'], &block).tap do |result|
542
- block_given? || track_tmpdir!(result)
479
+ if block_given?
480
+ # folder is deleted at end of block
481
+ ::Dir.mktmpdir(prefix, root, &block)
482
+ else
483
+ self.class.make_tempdir(self, prefix, root)
543
484
  end
544
485
  end
545
486
 
@@ -552,14 +493,17 @@ class Roo::Base
552
493
  end
553
494
 
554
495
  def sanitize_value(v)
555
- v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/, '')
496
+ v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/, "")
556
497
  end
557
498
 
558
499
  def set_headers(hash = {})
559
500
  # try to find header row with all values or give an error
560
501
  # then create new hash by indexing strings and keeping integers for header array
561
- @headers = row_with(hash.values, true)
562
- @headers = Hash[hash.keys.zip(@headers.map { |x| header_index(x) })]
502
+ header_row = row_with(hash.values, true)
503
+ @headers = {}
504
+ hash.each_with_index do |(key, _), index|
505
+ @headers[key] = header_index(header_row[index])
506
+ end
563
507
  end
564
508
 
565
509
  def header_index(query)
@@ -577,7 +521,7 @@ class Roo::Base
577
521
  # converts cell coordinate to numeric values of row,col
578
522
  def normalize(row, col)
579
523
  if row.is_a?(::String)
580
- if col.is_a?(::Fixnum)
524
+ if col.is_a?(::Integer)
581
525
  # ('A',1):
582
526
  # ('B', 5) -> (5, 2)
583
527
  row, col = col, row
@@ -592,17 +536,17 @@ class Roo::Base
592
536
  end
593
537
 
594
538
  def uri?(filename)
595
- filename.start_with?('http://', 'https://')
539
+ filename.start_with?("http://", "https://", "ftp://")
596
540
  rescue
597
541
  false
598
542
  end
599
543
 
600
544
  def download_uri(uri, tmpdir)
601
- require 'open-uri'
602
- tempfilename = File.join(tmpdir, File.basename(uri))
545
+ require "open-uri"
546
+ tempfilename = File.join(tmpdir, find_basename(uri))
603
547
  begin
604
- File.open(tempfilename, 'wb') do |file|
605
- open(uri, 'User-Agent' => "Ruby/#{RUBY_VERSION}") do |net|
548
+ File.open(tempfilename, "wb") do |file|
549
+ URI.open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
606
550
  file.write(net.read)
607
551
  end
608
552
  end
@@ -613,15 +557,15 @@ class Roo::Base
613
557
  end
614
558
 
615
559
  def open_from_stream(stream, tmpdir)
616
- tempfilename = File.join(tmpdir, 'spreadsheet')
617
- File.open(tempfilename, 'wb') do |file|
560
+ tempfilename = File.join(tmpdir, "spreadsheet")
561
+ File.open(tempfilename, "wb") do |file|
618
562
  file.write(stream[7..-1])
619
563
  end
620
- File.join(tmpdir, 'spreadsheet')
564
+ File.join(tmpdir, "spreadsheet")
621
565
  end
622
566
 
623
567
  def unzip(filename, tmpdir)
624
- require 'zip/filesystem'
568
+ require "zip/filesystem"
625
569
 
626
570
  Zip::File.open(filename) do |zip|
627
571
  process_zipfile_packed(zip, tmpdir)
@@ -633,8 +577,8 @@ class Roo::Base
633
577
  case sheet
634
578
  when nil
635
579
  fail ArgumentError, "Error: sheet 'nil' not valid"
636
- when Fixnum
637
- sheets.fetch(sheet - 1) do
580
+ when Integer
581
+ sheets.fetch(sheet) do
638
582
  fail RangeError, "sheet index #{sheet} not found"
639
583
  end
640
584
  when String
@@ -646,90 +590,20 @@ class Roo::Base
646
590
  end
647
591
  end
648
592
 
649
- def process_zipfile_packed(zip, tmpdir, path = '')
593
+ def process_zipfile_packed(zip, tmpdir, path = "")
650
594
  if zip.file.file? path
651
595
  # extract and return filename
652
- File.open(File.join(tmpdir, path), 'wb') do |file|
596
+ File.open(File.join(tmpdir, path), "wb") do |file|
653
597
  file.write(zip.read(path))
654
598
  end
655
599
  File.join(tmpdir, path)
656
600
  else
657
601
  ret = nil
658
- path += '/' unless path.empty?
602
+ path += "/" unless path.empty?
659
603
  zip.dir.foreach(path) do |filename|
660
604
  ret = process_zipfile_packed(zip, tmpdir, path + filename)
661
605
  end
662
606
  ret
663
607
  end
664
608
  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
- 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")
678
- end
679
- end
680
-
681
- # The content of a cell in the csv output
682
- def cell_to_csv(row, col, sheet)
683
- return '' if empty?(row, col, sheet)
684
-
685
- onecell = cell(row, col, sheet)
686
-
687
- case celltype(row, col, sheet)
688
- when :string
689
- %("#{onecell.gsub('"', '""')}") unless onecell.empty?
690
- when :boolean
691
- # TODO: this only works for excelx
692
- onecell = self.sheet_for(sheet).cells[[row, col]].formatted_value
693
- %("#{onecell.gsub('"', '""').downcase}")
694
- when :float, :percentage
695
- if onecell == onecell.to_i
696
- onecell.to_i.to_s
697
- else
698
- onecell.to_s
699
- end
700
- when :formula
701
- case onecell
702
- when String
703
- %("#{onecell.gsub('"', '""')}") unless onecell.empty?
704
- when Float
705
- if onecell == onecell.to_i
706
- onecell.to_i.to_s
707
- else
708
- onecell.to_s
709
- end
710
- when DateTime
711
- onecell.to_s
712
- else
713
- fail "unhandled onecell-class #{onecell.class}"
714
- end
715
- when :date, :datetime
716
- onecell.to_s
717
- when :time
718
- integer_to_timestring(onecell)
719
- when :link
720
- %("#{onecell.url.gsub('"', '""')}")
721
- else
722
- fail "unhandled celltype #{celltype(row, col, sheet)}"
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 -= h * 3600
730
- m = (content / 60.0).floor
731
- content -= m * 60
732
- s = content
733
- sprintf('%02d:%02d:%02d', h, m, s)
734
- end
735
609
  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.".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
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