roo 2.0.1 → 2.7.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 (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