roo 2.0.1 → 2.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -0
  3. data/.github/ISSUE_TEMPLATE +10 -0
  4. data/.gitignore +4 -0
  5. data/.travis.yml +10 -6
  6. data/CHANGELOG.md +116 -1
  7. data/Gemfile +3 -4
  8. data/Gemfile_ruby2 +30 -0
  9. data/Guardfile +1 -2
  10. data/README.md +56 -22
  11. data/Rakefile +1 -1
  12. data/lib/roo/base.rb +108 -245
  13. data/lib/roo/constants.rb +5 -0
  14. data/lib/roo/csv.rb +94 -87
  15. data/lib/roo/errors.rb +11 -0
  16. data/lib/roo/excelx/cell/base.rb +94 -0
  17. data/lib/roo/excelx/cell/boolean.rb +27 -0
  18. data/lib/roo/excelx/cell/date.rb +28 -0
  19. data/lib/roo/excelx/cell/datetime.rb +111 -0
  20. data/lib/roo/excelx/cell/empty.rb +19 -0
  21. data/lib/roo/excelx/cell/number.rb +87 -0
  22. data/lib/roo/excelx/cell/string.rb +19 -0
  23. data/lib/roo/excelx/cell/time.rb +43 -0
  24. data/lib/roo/excelx/cell.rb +33 -4
  25. data/lib/roo/excelx/comments.rb +33 -0
  26. data/lib/roo/excelx/coordinate.rb +12 -0
  27. data/lib/roo/excelx/extractor.rb +3 -4
  28. data/lib/roo/excelx/format.rb +64 -0
  29. data/lib/roo/excelx/shared.rb +32 -0
  30. data/lib/roo/excelx/shared_strings.rb +124 -4
  31. data/lib/roo/excelx/sheet.rb +12 -7
  32. data/lib/roo/excelx/sheet_doc.rb +108 -97
  33. data/lib/roo/excelx/styles.rb +1 -1
  34. data/lib/roo/excelx.rb +61 -103
  35. data/lib/roo/formatters/base.rb +15 -0
  36. data/lib/roo/formatters/csv.rb +84 -0
  37. data/lib/roo/formatters/matrix.rb +23 -0
  38. data/lib/roo/formatters/xml.rb +31 -0
  39. data/lib/roo/formatters/yaml.rb +40 -0
  40. data/lib/roo/libre_office.rb +1 -2
  41. data/lib/roo/link.rb +21 -2
  42. data/lib/roo/open_office.rb +468 -523
  43. data/lib/roo/spreadsheet.rb +3 -1
  44. data/lib/roo/tempdir.rb +21 -0
  45. data/lib/roo/utils.rb +7 -7
  46. data/lib/roo/version.rb +1 -1
  47. data/lib/roo.rb +8 -3
  48. data/roo.gemspec +2 -1
  49. data/spec/helpers.rb +5 -0
  50. data/spec/lib/roo/base_spec.rb +229 -0
  51. data/spec/lib/roo/csv_spec.rb +19 -0
  52. data/spec/lib/roo/excelx_spec.rb +97 -11
  53. data/spec/lib/roo/openoffice_spec.rb +18 -1
  54. data/spec/lib/roo/spreadsheet_spec.rb +20 -0
  55. data/spec/lib/roo/utils_spec.rb +1 -1
  56. data/spec/spec_helper.rb +5 -5
  57. data/test/all_ss.rb +12 -11
  58. data/test/excelx/cell/test_base.rb +63 -0
  59. data/test/excelx/cell/test_boolean.rb +36 -0
  60. data/test/excelx/cell/test_date.rb +38 -0
  61. data/test/excelx/cell/test_datetime.rb +45 -0
  62. data/test/excelx/cell/test_empty.rb +7 -0
  63. data/test/excelx/cell/test_number.rb +74 -0
  64. data/test/excelx/cell/test_string.rb +28 -0
  65. data/test/excelx/cell/test_time.rb +30 -0
  66. data/test/formatters/test_csv.rb +119 -0
  67. data/test/formatters/test_matrix.rb +76 -0
  68. data/test/formatters/test_xml.rb +78 -0
  69. data/test/formatters/test_yaml.rb +20 -0
  70. data/test/helpers/test_accessing_files.rb +60 -0
  71. data/test/helpers/test_comments.rb +43 -0
  72. data/test/helpers/test_formulas.rb +9 -0
  73. data/test/helpers/test_labels.rb +103 -0
  74. data/test/helpers/test_sheets.rb +55 -0
  75. data/test/helpers/test_styles.rb +62 -0
  76. data/test/roo/test_base.rb +182 -0
  77. data/test/roo/test_csv.rb +60 -0
  78. data/test/roo/test_excelx.rb +325 -0
  79. data/test/roo/test_libre_office.rb +9 -0
  80. data/test/roo/test_open_office.rb +289 -0
  81. data/test/test_helper.rb +116 -18
  82. data/test/test_roo.rb +362 -2088
  83. metadata +70 -4
  84. 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
- return nil unless @tmpdirs
42
- @tmpdirs.each { |dir| ::FileUtils.remove_entry(dir) }
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
- "<##{ self.class }:#{ self.object_id.to_s(8) } #{ self.instance_variables.join(' ') }>"
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 Fixnum
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 , sheet)
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 Fixnum then :float
175
+ when Integer then :float
226
176
  when String, Float then :string
227
177
  else
228
- raise ArgumentError, "Type for #{value} not set"
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
- unless first_row
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 === index ? index : sheets[index]
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
- if block_given?
356
- if options.empty?
357
- 1.upto(last_row) do |line|
358
- yield row(line)
359
- end
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
- to_enum(:each, options)
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
- ary = []
379
- each(options) do |row|
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
- ary
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
- fail "Couldn't find header row."
317
+ raise Roo::HeaderRowNotFoundError
397
318
  end
398
319
  end
399
- fail "Couldn't find header row."
320
+ raise Roo::HeaderRowNotFoundError
400
321
  end
401
322
 
402
323
  protected
403
324
 
404
- def file_type_check(filename, ext, name, warning_level, packed = nil)
325
+ def file_type_check(filename, exts, name, warning_level, packed = nil)
405
326
  if packed == :zip
406
- # lalala.ods.zip => lalala.ods
407
- # hier wird KEIN unzip gemacht, sondern nur der Name der Datei
408
- # getestet, falls es eine gepackte Datei ist.
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
- if File.extname(filename).downcase != ext
416
- case warning_level
417
- when :error
418
- warn file_type_warning_message(filename, ext)
419
- fail TypeError, "#{filename} is not #{name} file"
420
- when :warning
421
- warn "are you sure, this is #{name} spreadsheet file?"
422
- warn file_type_warning_message(filename, ext)
423
- when :ignore
424
- # ignore
425
- else
426
- fail "#{warning_level} illegal state of file_warning"
427
- end
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
- unless File.file?(filename)
479
- fail IOError, "file #{filename} does not exist"
480
- end
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, ext)
485
- "use #{Roo::CLASS_FOR_EXTENSION.fetch(ext.sub('.', '').to_sym)}.new to handle #{ext} spreadsheet files. This has #{File.extname(filename).downcase}"
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 type: #{ext}"
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
- prefix = if prefix
537
- TEMP_PREFIX + prefix
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
- TEMP_PREFIX
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?(::Fixnum)
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
- if col.is_a?(::String)
589
- col = ::Roo::Utils.letter_to_number(col)
590
- end
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, File.basename(uri))
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 Fixnum
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? sheet
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