roo 2.6.0 → 2.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) 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/.rubocop.yml +186 -0
  6. data/.travis.yml +14 -11
  7. data/CHANGELOG.md +64 -2
  8. data/Gemfile +2 -4
  9. data/LICENSE +2 -0
  10. data/README.md +36 -10
  11. data/lib/roo/base.rb +82 -225
  12. data/lib/roo/constants.rb +5 -3
  13. data/lib/roo/csv.rb +100 -97
  14. data/lib/roo/excelx/cell/base.rb +26 -12
  15. data/lib/roo/excelx/cell/boolean.rb +9 -6
  16. data/lib/roo/excelx/cell/date.rb +7 -7
  17. data/lib/roo/excelx/cell/datetime.rb +50 -44
  18. data/lib/roo/excelx/cell/empty.rb +3 -2
  19. data/lib/roo/excelx/cell/number.rb +44 -47
  20. data/lib/roo/excelx/cell/string.rb +3 -3
  21. data/lib/roo/excelx/cell/time.rb +17 -16
  22. data/lib/roo/excelx/cell.rb +10 -6
  23. data/lib/roo/excelx/comments.rb +3 -3
  24. data/lib/roo/excelx/coordinate.rb +11 -4
  25. data/lib/roo/excelx/extractor.rb +21 -3
  26. data/lib/roo/excelx/format.rb +38 -31
  27. data/lib/roo/excelx/images.rb +26 -0
  28. data/lib/roo/excelx/relationships.rb +12 -4
  29. data/lib/roo/excelx/shared.rb +10 -3
  30. data/lib/roo/excelx/shared_strings.rb +9 -15
  31. data/lib/roo/excelx/sheet.rb +49 -10
  32. data/lib/roo/excelx/sheet_doc.rb +89 -48
  33. data/lib/roo/excelx/styles.rb +3 -3
  34. data/lib/roo/excelx/workbook.rb +7 -3
  35. data/lib/roo/excelx.rb +50 -19
  36. data/lib/roo/formatters/base.rb +15 -0
  37. data/lib/roo/formatters/csv.rb +84 -0
  38. data/lib/roo/formatters/matrix.rb +23 -0
  39. data/lib/roo/formatters/xml.rb +31 -0
  40. data/lib/roo/formatters/yaml.rb +40 -0
  41. data/lib/roo/helpers/default_attr_reader.rb +20 -0
  42. data/lib/roo/helpers/weak_instance_cache.rb +41 -0
  43. data/lib/roo/open_office.rb +17 -9
  44. data/lib/roo/spreadsheet.rb +1 -1
  45. data/lib/roo/tempdir.rb +5 -10
  46. data/lib/roo/utils.rb +70 -20
  47. data/lib/roo/version.rb +1 -1
  48. data/lib/roo.rb +4 -1
  49. data/roo.gemspec +14 -11
  50. data/spec/lib/roo/base_spec.rb +45 -3
  51. data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
  52. data/spec/lib/roo/excelx/sheet_doc_spec.rb +11 -0
  53. data/spec/lib/roo/excelx_spec.rb +150 -31
  54. data/spec/lib/roo/strict_spec.rb +43 -0
  55. data/spec/lib/roo/utils_spec.rb +25 -3
  56. data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
  57. data/spec/lib/roo_spec.rb +0 -0
  58. data/spec/spec_helper.rb +2 -6
  59. data/test/excelx/cell/test_attr_reader_default.rb +72 -0
  60. data/test/excelx/cell/test_base.rb +5 -0
  61. data/test/excelx/cell/test_datetime.rb +6 -6
  62. data/test/excelx/cell/test_empty.rb +11 -0
  63. data/test/excelx/cell/test_number.rb +9 -0
  64. data/test/excelx/cell/test_string.rb +20 -0
  65. data/test/excelx/cell/test_time.rb +5 -5
  66. data/test/excelx/test_coordinate.rb +51 -0
  67. data/test/formatters/test_csv.rb +136 -0
  68. data/test/formatters/test_matrix.rb +76 -0
  69. data/test/formatters/test_xml.rb +78 -0
  70. data/test/formatters/test_yaml.rb +20 -0
  71. data/test/helpers/test_accessing_files.rb +60 -0
  72. data/test/helpers/test_comments.rb +43 -0
  73. data/test/helpers/test_formulas.rb +9 -0
  74. data/test/helpers/test_labels.rb +103 -0
  75. data/test/helpers/test_sheets.rb +55 -0
  76. data/test/helpers/test_styles.rb +62 -0
  77. data/test/roo/test_base.rb +182 -0
  78. data/test/roo/test_csv.rb +88 -0
  79. data/test/roo/test_excelx.rb +330 -0
  80. data/test/roo/test_libre_office.rb +9 -0
  81. data/test/roo/test_open_office.rb +289 -0
  82. data/test/test_helper.rb +129 -14
  83. data/test/test_roo.rb +32 -1787
  84. metadata +81 -29
  85. data/.github/ISSUE_TEMPLATE +0 -10
  86. data/Gemfile_ruby2 +0 -29
data/lib/roo/base.rb CHANGED
@@ -1,16 +1,24 @@
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
- MAX_ROW_COL = 999_999.freeze
13
- MIN_ROW_COL = 0.freeze
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 '[DEPRECATION] please access TEMP_PREFIX via Roo::TEMP_PREFIX'
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 (1 = first sheet) or the name of a sheet.
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
- %w(first_row last_row first_column last_column).each do |key|
100
- class_eval <<-EOS, __FILE__, __LINE__ + 1
101
- def #{key}(sheet = default_sheet) # def first_row(sheet = default_sheet)
102
- read_cells(sheet) # read_cells(sheet)
103
- @#{key}[sheet] ||= first_last_row_col_for_sheet(sheet)[:#{key}] # @first_row[sheet] ||= first_last_row_col_for_sheet(sheet)[:first_row]
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 << 'Sheet ' + n.to_s + ":\n"
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 << ' - empty -'
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
- Hash[(first_column..last_column).map do |col|
369
- [cell(@header_line, col), 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(Hash[headers.map { |k, v| [k, cell(line, v)] }])
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
- ary = []
380
- each(options) do |row|
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
- ary
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
- elsif line_no > 100
397
- raise Roo::HeaderRowNotFoundError
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
- raise Roo::HeaderRowNotFoundError
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 = Hash[1.upto(last_column).map do |col|
502
- [col, cell(@header_line, 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
- Hash[1.upto(row(i).size).map do |j|
519
- [header_for.fetch(j), cell(i, 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 'uri'
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 '[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead'
473
+ warn "[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead"
548
474
  prefix = "#{Roo::TEMP_PREFIX}#{prefix}"
549
- root ||= ENV['ROO_TMP']
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
- @headers = row_with(hash.values, true)
575
- @headers = Hash[hash.keys.zip(@headers.map { |x| header_index(x) })]
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?('http://', 'https://', 'ftp://')
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 'open-uri'
543
+ require "open-uri"
615
544
  tempfilename = File.join(tmpdir, find_basename(uri))
616
545
  begin
617
- File.open(tempfilename, 'wb') do |file|
618
- open(uri, 'User-Agent' => "Ruby/#{RUBY_VERSION}") do |net|
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, 'spreadsheet')
630
- File.open(tempfilename, 'wb') do |file|
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, 'spreadsheet')
562
+ File.join(tmpdir, "spreadsheet")
634
563
  end
635
564
 
636
565
  def unzip(filename, tmpdir)
637
- require 'zip/filesystem'
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 - 1) do
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), 'wb') do |file|
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 += '/' unless path.empty?
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.".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