roo 2.6.0 → 2.8.3

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 (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