jagthedrummer-roo 1.3.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/History.txt +225 -0
  2. data/README.markdown +55 -0
  3. data/examples/roo_soap_client.rb +53 -0
  4. data/examples/roo_soap_server.rb +29 -0
  5. data/examples/write_me.rb +33 -0
  6. data/lib/roo.rb +29 -0
  7. data/lib/roo/excel.rb +469 -0
  8. data/lib/roo/excelx.rb +604 -0
  9. data/lib/roo/generic_spreadsheet.rb +626 -0
  10. data/lib/roo/google.rb +381 -0
  11. data/lib/roo/openoffice.rb +454 -0
  12. data/lib/roo/roo_rails_helper.rb +82 -0
  13. data/lib/roo/version.rb +9 -0
  14. data/test/1900_base.xls +0 -0
  15. data/test/1904_base.xls +0 -0
  16. data/test/Bibelbund.csv +3741 -0
  17. data/test/Bibelbund.ods +0 -0
  18. data/test/Bibelbund.xls +0 -0
  19. data/test/Bibelbund.xlsx +0 -0
  20. data/test/Bibelbund1.ods +0 -0
  21. data/test/bad_excel_date.xls +0 -0
  22. data/test/bbu.ods +0 -0
  23. data/test/bbu.xls +0 -0
  24. data/test/bbu.xlsx +0 -0
  25. data/test/bode-v1.ods.zip +0 -0
  26. data/test/bode-v1.xls.zip +0 -0
  27. data/test/boolean.ods +0 -0
  28. data/test/boolean.xls +0 -0
  29. data/test/boolean.xlsx +0 -0
  30. data/test/borders.ods +0 -0
  31. data/test/borders.xls +0 -0
  32. data/test/borders.xlsx +0 -0
  33. data/test/bug-row-column-fixnum-float.xls +0 -0
  34. data/test/datetime.ods +0 -0
  35. data/test/datetime.xls +0 -0
  36. data/test/datetime.xlsx +0 -0
  37. data/test/datetime_floatconv.xls +0 -0
  38. data/test/emptysheets.ods +0 -0
  39. data/test/emptysheets.xls +0 -0
  40. data/test/false_encoding.xls +0 -0
  41. data/test/formula.ods +0 -0
  42. data/test/formula.xls +0 -0
  43. data/test/formula.xlsx +0 -0
  44. data/test/formula_parse_error.xls +0 -0
  45. data/test/html-escape.ods +0 -0
  46. data/test/no_spreadsheet_file.txt +1 -0
  47. data/test/numbers1.csv +18 -0
  48. data/test/numbers1.ods +0 -0
  49. data/test/numbers1.xls +0 -0
  50. data/test/numbers1.xlsx +0 -0
  51. data/test/only_one_sheet.ods +0 -0
  52. data/test/only_one_sheet.xls +0 -0
  53. data/test/only_one_sheet.xlsx +0 -0
  54. data/test/paragraph.ods +0 -0
  55. data/test/paragraph.xls +0 -0
  56. data/test/paragraph.xlsx +0 -0
  57. data/test/ric.ods +0 -0
  58. data/test/simple_spreadsheet.ods +0 -0
  59. data/test/simple_spreadsheet.xls +0 -0
  60. data/test/simple_spreadsheet.xlsx +0 -0
  61. data/test/simple_spreadsheet_from_italo.ods +0 -0
  62. data/test/simple_spreadsheet_from_italo.xls +0 -0
  63. data/test/skipped_tests.rb +789 -0
  64. data/test/style.ods +0 -0
  65. data/test/style.xls +0 -0
  66. data/test/style.xlsx +0 -0
  67. data/test/test_helper.rb +19 -0
  68. data/test/test_roo.rb +1822 -0
  69. data/test/time-test.csv +2 -0
  70. data/test/time-test.ods +0 -0
  71. data/test/time-test.xls +0 -0
  72. data/test/time-test.xlsx +0 -0
  73. data/test/whitespace.ods +0 -0
  74. data/test/whitespace.xls +0 -0
  75. data/test/whitespace.xlsx +0 -0
  76. metadata +182 -0
@@ -0,0 +1,626 @@
1
+ require 'rubygems'
2
+ require 'builder'
3
+
4
+ # Base class for all other types of spreadsheets
5
+ class GenericSpreadsheet
6
+
7
+ attr_reader :default_sheet
8
+
9
+ # sets the line with attribute names (default: 1)
10
+ attr_accessor :header_line
11
+
12
+ def initialize
13
+ end
14
+
15
+ # set the working sheet in the document
16
+ def default_sheet=(sheet)
17
+ if sheet.kind_of? Fixnum
18
+ if sheet >= 0 and sheet <= sheets.length
19
+ sheet = self.sheets[sheet-1]
20
+ else
21
+ raise RangeError
22
+ end
23
+ elsif sheet.kind_of?(String)
24
+ raise RangeError if ! self.sheets.include?(sheet)
25
+ else
26
+ raise TypeError, "what are you trying to set as default sheet?"
27
+ end
28
+ @default_sheet = sheet
29
+ check_default_sheet
30
+ @first_row[sheet] = @last_row[sheet] = @first_column[sheet] = @last_column[sheet] = nil
31
+ @cells_read[sheet] = false
32
+ end
33
+
34
+ # first non-empty column as a letter
35
+ def first_column_as_letter(sheet=nil)
36
+ GenericSpreadsheet.number_to_letter(first_column(sheet))
37
+ end
38
+
39
+ # last non-empty column as a letter
40
+ def last_column_as_letter(sheet=nil)
41
+ GenericSpreadsheet.number_to_letter(last_column(sheet))
42
+ end
43
+
44
+ # returns the number of the first non-empty row
45
+ def first_row(sheet=nil)
46
+ if sheet == nil
47
+ sheet = @default_sheet
48
+ end
49
+ read_cells(sheet) unless @cells_read[sheet]
50
+ if @first_row[sheet]
51
+ return @first_row[sheet]
52
+ end
53
+ impossible_value = 999_999 # more than a spreadsheet can hold
54
+ result = impossible_value
55
+ @cell[sheet].each_pair {|key,value|
56
+ y,x = key # _to_string(key).split(',')
57
+ y = y.to_i
58
+ result = [result, y].min if value
59
+ } if @cell[sheet]
60
+ result = nil if result == impossible_value
61
+ @first_row[sheet] = result
62
+ result
63
+ end
64
+
65
+ # returns the number of the last non-empty row
66
+ def last_row(sheet=nil)
67
+ sheet = @default_sheet unless sheet
68
+ read_cells(sheet) unless @cells_read[sheet]
69
+ if @last_row[sheet]
70
+ return @last_row[sheet]
71
+ end
72
+ impossible_value = 0
73
+ result = impossible_value
74
+ @cell[sheet].each_pair {|key,value|
75
+ y,x = key # _to_string(key).split(',')
76
+ y = y.to_i
77
+ result = [result, y].max if value
78
+ } if @cell[sheet]
79
+ result = nil if result == impossible_value
80
+ @last_row[sheet] = result
81
+ result
82
+ end
83
+
84
+ # returns the number of the first non-empty column
85
+ def first_column(sheet=nil)
86
+ if sheet == nil
87
+ sheet = @default_sheet
88
+ end
89
+ read_cells(sheet) unless @cells_read[sheet]
90
+ if @first_column[sheet]
91
+ return @first_column[sheet]
92
+ end
93
+ impossible_value = 999_999 # more than a spreadsheet can hold
94
+ result = impossible_value
95
+ @cell[sheet].each_pair {|key,value|
96
+ y,x = key # _to_string(key).split(',')
97
+ x = x # .to_i
98
+ result = [result, x].min if value
99
+ } if @cell[sheet]
100
+ result = nil if result == impossible_value
101
+ @first_column[sheet] = result
102
+ result
103
+ end
104
+
105
+ # returns the number of the last non-empty column
106
+ def last_column(sheet=nil)
107
+ sheet = @default_sheet unless sheet
108
+ read_cells(sheet) unless @cells_read[sheet]
109
+ if @last_column[sheet]
110
+ return @last_column[sheet]
111
+ end
112
+ impossible_value = 0
113
+ result = impossible_value
114
+ @cell[sheet].each_pair {|key,value|
115
+ y,x = key # _to_string(key).split(',')
116
+ x = x.to_i
117
+ result = [result, x].max if value
118
+ } if @cell[sheet]
119
+ result = nil if result == impossible_value
120
+ @last_column[sheet] = result
121
+ result
122
+ end
123
+
124
+ # returns a rectangular area (default: all cells) as yaml-output
125
+ # you can add additional attributes with the prefix parameter like:
126
+ # oo.to_yaml({"file"=>"flightdata_2007-06-26", "sheet" => "1"})
127
+ def to_yaml(prefix={}, from_row=nil, from_column=nil, to_row=nil, to_column=nil,sheet=nil)
128
+ sheet = @default_sheet unless sheet
129
+ result = "--- \n"
130
+ (from_row||first_row(sheet)).upto(to_row||last_row(sheet)) do |row|
131
+ (from_column||first_column(sheet)).upto(to_column||last_column(sheet)) do |col|
132
+ unless empty?(row,col,sheet)
133
+ result << "cell_#{row}_#{col}: \n"
134
+ prefix.each {|k,v|
135
+ result << " #{k}: #{v} \n"
136
+ }
137
+ result << " row: #{row} \n"
138
+ result << " col: #{col} \n"
139
+ result << " celltype: #{self.celltype(row,col,sheet)} \n"
140
+ if self.celltype(row,col,sheet) == :time
141
+ result << " value: #{GenericSpreadsheet.integer_to_timestring( self.cell(row,col,sheet))} \n"
142
+ else
143
+ result << " value: #{self.cell(row,col,sheet)} \n"
144
+ end
145
+ end
146
+ end
147
+ end
148
+ result
149
+ end
150
+
151
+ # write the current spreadsheet to stdout or into a file
152
+ def to_csv(filename=nil,sheet=nil)
153
+ sheet = @default_sheet unless sheet
154
+ if filename
155
+ file = File.open(filename,"w") # do |file|
156
+ write_csv_content(file,sheet)
157
+ file.close
158
+ else
159
+ write_csv_content(STDOUT,sheet)
160
+ end
161
+ true
162
+ end
163
+
164
+ # find a row either by row number or a condition
165
+ # Caution: this works only within the default sheet -> set default_sheet before you call this method
166
+ # (experimental. see examples in the test_roo.rb file)
167
+ def find(*args) # :nodoc
168
+ result_array = false
169
+ args.each {|arg,val|
170
+ if arg.class == Hash
171
+ arg.each { |hkey,hval|
172
+ if hkey == :array and hval == true
173
+ result_array = true
174
+ end
175
+ }
176
+ end
177
+ }
178
+ column_with = {}
179
+ 1.upto(last_column) do |col|
180
+ column_with[cell(@header_line,col)] = col
181
+ end
182
+ result = Array.new
183
+ #-- id
184
+ if args[0].class == Fixnum
185
+ rownum = args[0]
186
+ if @header_line
187
+ tmp = {}
188
+ else
189
+ tmp = []
190
+ end
191
+ 1.upto(self.row(rownum).size) {|j|
192
+ x = ''
193
+ column_with.each { |key,val|
194
+ if val == j
195
+ x = key
196
+ end
197
+ }
198
+ if @header_line
199
+ tmp[x] = cell(rownum,j)
200
+ else
201
+ tmp[j-1] = cell(rownum,j)
202
+ end
203
+
204
+ }
205
+ if @header_line
206
+ result = [ tmp ]
207
+ else
208
+ result = tmp
209
+ end
210
+ #-- :all
211
+ elsif args[0] == :all
212
+ if args[1].class == Hash
213
+ args[1].each {|key,val|
214
+ if key == :conditions
215
+ column_with = {}
216
+ 1.upto(last_column) do |col|
217
+ column_with[cell(@header_line,col)] = col
218
+ end
219
+ conditions = val
220
+ first_row.upto(last_row) do |i|
221
+ # are all conditions met?
222
+ found = 1
223
+ conditions.each { |key,val|
224
+ if cell(i,column_with[key]) == val
225
+ found *= 1
226
+ else
227
+ found *= 0
228
+ end
229
+ }
230
+ if found > 0
231
+ tmp = {}
232
+ 1.upto(self.row(i).size) {|j|
233
+ x = ''
234
+ column_with.each { |key,val|
235
+ if val == j
236
+ x = key
237
+ end
238
+ }
239
+ tmp[x] = cell(i,j)
240
+ }
241
+ if result_array
242
+ result << self.row(i)
243
+ else
244
+ result << tmp
245
+ end
246
+ end
247
+ end
248
+ end # :conditions
249
+ }
250
+ end
251
+ end
252
+ result
253
+ end
254
+
255
+ # returns all values in this row as an array
256
+ # row numbers are 1,2,3,... like in the spreadsheet
257
+ def row(rownumber,sheet=nil)
258
+ sheet = @default_sheet unless sheet
259
+ read_cells(sheet) unless @cells_read[sheet]
260
+ result = []
261
+ first_column(sheet).upto(last_column(sheet)) do |col|
262
+ result << cell(rownumber,col,sheet)
263
+ end
264
+ result
265
+ end
266
+
267
+ # returns all values in this column as an array
268
+ # column numbers are 1,2,3,... like in the spreadsheet
269
+ def column(columnnumber,sheet=nil)
270
+ if columnnumber.class == String
271
+ columnnumber = Roo::Excel.letter_to_number(columnnumber)
272
+ end
273
+ sheet = @default_sheet unless sheet
274
+ read_cells(sheet) unless @cells_read[sheet]
275
+ result = []
276
+ first_row(sheet).upto(last_row(sheet)) do |row|
277
+ result << cell(row,columnnumber,sheet)
278
+ end
279
+ result
280
+ end
281
+
282
+ # reopens and read a spreadsheet document
283
+ def reload
284
+ ds = @default_sheet
285
+ initialize(@filename) if self.class == Roo::Openoffice or
286
+ self.class == Roo::Excel
287
+ initialize(@spreadsheetkey,@user,@password) if self.class == Roo::Google
288
+ self.default_sheet = ds
289
+ #@first_row = @last_row = @first_column = @last_column = nil
290
+ end
291
+
292
+ # true if cell is empty
293
+ def empty?(row, col, sheet=nil)
294
+ sheet = @default_sheet unless sheet
295
+ read_cells(sheet) unless @cells_read[sheet] or self.class == Roo::Excel
296
+ row,col = normalize(row,col)
297
+ return true unless cell(row, col, sheet)
298
+ return true if celltype(row, col, sheet) == :string && cell(row, col, sheet).empty?
299
+ return true if row < first_row(sheet) || row > last_row(sheet) || col < first_column(sheet) || col > last_column(sheet)
300
+ false
301
+ end
302
+
303
+ # recursively removes the current temporary directory
304
+ # this is only needed if you work with zipped files or files via the web
305
+ def remove_tmp
306
+ if File.exists?(@tmpdir)
307
+ FileUtils::rm_r(@tmpdir)
308
+ end
309
+ end
310
+
311
+ # Returns information of the spreadsheet document and all sheets within
312
+ # this document.
313
+ def info
314
+ result = "File: #{File.basename(@filename)}\n"+
315
+ "Number of sheets: #{sheets.size}\n"+
316
+ "Sheets: #{sheets.map{|sheet| sheet+", "}.to_s[0..-3]}\n"
317
+ n = 1
318
+ sheets.each {|sheet|
319
+ self.default_sheet = sheet
320
+ result << "Sheet " + n.to_s + ":\n"
321
+ unless first_row
322
+ result << " - empty -"
323
+ else
324
+ result << " First row: #{first_row}\n"
325
+ result << " Last row: #{last_row}\n"
326
+ result << " First column: #{GenericSpreadsheet.number_to_letter(first_column)}\n"
327
+ result << " Last column: #{GenericSpreadsheet.number_to_letter(last_column)}"
328
+ end
329
+ result << "\n" if sheet != sheets.last
330
+ n += 1
331
+ }
332
+ result
333
+ end
334
+
335
+ def to_xml
336
+ xml_document = ''
337
+ xml = Builder::XmlMarkup.new(:target => xml_document, :indent => 2)
338
+ xml.instruct! :xml, :version =>"1.0", :encoding => "utf-8"
339
+ xml.spreadsheet {
340
+ self.sheets.each do |sheet|
341
+ self.default_sheet = sheet
342
+ xml.sheet(:name => sheet) { |x|
343
+ if first_row and last_row and first_column and last_column
344
+ # sonst gibt es Fehler bei leeren Blaettern
345
+ first_row.upto(last_row) do |row|
346
+ first_column.upto(last_column) do |col|
347
+ unless empty?(row,col)
348
+ x.cell(cell(row,col),
349
+ :row =>row,
350
+ :column => col,
351
+ :type => celltype(row,col))
352
+ end
353
+ end
354
+ end
355
+ end
356
+ }
357
+ end
358
+ }
359
+ xml_document
360
+ end
361
+
362
+ protected
363
+
364
+ def file_type_check(filename, ext, name)
365
+ new_expression = {
366
+ '.ods' => 'Openoffice.new',
367
+ '.xls' => 'Excel.new',
368
+ '.xlsx' => 'Excelx.new',
369
+ }
370
+ case ext
371
+ when '.ods', '.xls', '.xlsx'
372
+ correct_class = "use #{new_expression[ext]} to handle #{ext} spreadsheet files"
373
+ else
374
+ raise "unknown file type: #{ext}"
375
+ end
376
+ if File.extname(filename).downcase != ext
377
+ case @file_warning
378
+ when :error
379
+ warn correct_class
380
+ raise TypeError, "#{filename} is not #{name} file"
381
+ when :warning
382
+ warn "are you sure, this is #{name} spreadsheet file?"
383
+ warn correct_class
384
+ when :ignore
385
+ # ignore
386
+ else
387
+ raise "#{@file_warning} illegal state of file_warning"
388
+ end
389
+ end
390
+ end
391
+
392
+ # konvertiert einen Key in der Form "12,45" (=row,column) in
393
+ # ein Array mit numerischen Werten ([12,45])
394
+ # Diese Methode ist eine temp. Loesung, um zu erforschen, ob der
395
+ # Zugriff mit numerischen Keys schneller ist.
396
+ def key_to_num(str)
397
+ r,c = str.split(',')
398
+ r = r.to_i
399
+ c = c.to_i
400
+ [r,c]
401
+ end
402
+
403
+ # siehe: key_to_num
404
+ def key_to_string(arr)
405
+ "#{arr[0]},#{arr[1]}"
406
+ end
407
+
408
+ private
409
+
410
+ # converts cell coordinate to numeric values of row,col
411
+ def normalize(row,col)
412
+ if row.class == String
413
+ if col.class == Fixnum
414
+ # ('A',1):
415
+ # ('B', 5) -> (5, 2)
416
+ row, col = col, row
417
+ else
418
+ raise ArgumentError
419
+ end
420
+ end
421
+ if col.class == String
422
+ col = GenericSpreadsheet.letter_to_number(col)
423
+ end
424
+ return row,col
425
+ end
426
+
427
+ # def open_from_uri(uri)
428
+ # require 'open-uri' ;
429
+ # tempfilename = File.join(@tmpdir, File.basename(uri))
430
+ # f = File.open(tempfilename,"wb")
431
+ # begin
432
+ # open(uri) do |net|
433
+ # f.write(net.read)
434
+ # end
435
+ # rescue
436
+ # raise "could not open #{uri}"
437
+ # end
438
+ # f.close
439
+ # File.join(@tmpdir, File.basename(uri))
440
+ # end
441
+
442
+ # OpenURI::HTTPError
443
+ # def open_from_uri(uri)
444
+ # require 'open-uri'
445
+ # #existiert URL?
446
+ # r = Net::HTTP.get_response(URI.parse(uri))
447
+ # raise "URL nicht verfuegbar" unless r.is_a? Net::HTTPOK
448
+ # tempfilename = File.join(@tmpdir, File.basename(uri))
449
+ # f = File.open(tempfilename,"wb")
450
+ # open(uri) do |net|
451
+ # f.write(net.read)
452
+ # end
453
+ # # rescue
454
+ # # raise "could not open #{uri}"
455
+ # # end
456
+ # f.close
457
+ # File.join(@tmpdir, File.basename(uri))
458
+ # end
459
+
460
+ def open_from_uri(uri)
461
+ require 'open-uri'
462
+ response = ''
463
+ begin
464
+ open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") { |net|
465
+ response = net.read
466
+ tempfilename = File.join(@tmpdir, File.basename(uri))
467
+ f = File.open(tempfilename,"wb")
468
+ f.write(response)
469
+ f.close
470
+ }
471
+ rescue OpenURI::HTTPError
472
+ raise "could not open #{uri}"
473
+ end
474
+ File.join(@tmpdir, File.basename(uri))
475
+ end
476
+
477
+ def open_from_stream(stream)
478
+ tempfilename = File.join(@tmpdir, "spreadsheet")
479
+ f = File.open(tempfilename,"wb")
480
+ f.write(stream[7..-1])
481
+ f.close
482
+ File.join(@tmpdir, "spreadsheet")
483
+ end
484
+
485
+ # convert a number to something like 'AB' (1 => 'A', 2 => 'B', ...)
486
+ def self.number_to_letter(n)
487
+ letters=""
488
+ while n > 0
489
+ num = n%26
490
+ letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num-1,1] + letters
491
+ n = n.div(26)
492
+ end
493
+ letters
494
+ end
495
+
496
+ # convert letters like 'AB' to a number ('A' => 1, 'B' => 2, ...)
497
+ def self.letter_to_number(letters)
498
+ result = 0
499
+ while letters && letters.length > 0
500
+ character = letters[0,1].upcase
501
+ num = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".index(character)
502
+ raise ArgumentError, "invalid column character '#{letters[0,1]}'" if num == nil
503
+ num += 1
504
+ result = result * 26 + num
505
+ letters = letters[1..-1]
506
+ end
507
+ result
508
+ end
509
+
510
+ def unzip(filename)
511
+ ret = nil
512
+ Zip::ZipFile.open(filename) do |zip|
513
+ ret = process_zipfile_packed zip
514
+ end
515
+ ret
516
+ end
517
+
518
+ # check if default_sheet was set and exists in sheets-array
519
+ def check_default_sheet
520
+ sheet_found = false
521
+ raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil
522
+ if sheets.index(@default_sheet)
523
+ sheet_found = true
524
+ end
525
+ if ! sheet_found
526
+ raise RangeError, "sheet '#{@default_sheet}' not found"
527
+ end
528
+ #raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil
529
+ end
530
+
531
+ def process_zipfile_packed(zip, path='')
532
+ ret=nil
533
+ if zip.file.file? path
534
+ # extract and return filename
535
+ @tmpdir = "oo_"+$$.to_s
536
+ unless File.exists?(@tmpdir)
537
+ FileUtils::mkdir(@tmpdir)
538
+ end
539
+ file = File.open(File.join(@tmpdir, path),"wb")
540
+ file.write(zip.read(path))
541
+ file.close
542
+ return File.join(@tmpdir, path)
543
+ else
544
+ unless path.empty?
545
+ path += '/'
546
+ end
547
+ zip.dir.foreach(path) do |filename|
548
+ ret = process_zipfile_packed(zip, path + filename)
549
+ end
550
+ end
551
+ ret
552
+ end
553
+
554
+ def write_csv_content(file=nil,sheet=nil)
555
+ file = STDOUT unless file
556
+ if first_row(sheet) # sheet is not empty
557
+ # first_row(sheet).upto(last_row(sheet)) do |row|
558
+ 1.upto(last_row(sheet)) do |row|
559
+ 1.upto(last_column(sheet)) do |col|
560
+ file.print(",") if col > 1
561
+ onecell = cell(row,col,sheet)
562
+ onecelltype = celltype(row,col,sheet)
563
+ file.print one_cell_output(onecelltype,onecell,empty?(row,col,sheet))
564
+ end
565
+ file.print("\n")
566
+ end # sheet not empty
567
+ end
568
+ end
569
+
570
+ def one_cell_output(onecelltype,onecell,empty)
571
+ str = ""
572
+ if empty
573
+ str += ''
574
+ else
575
+ case onecelltype
576
+ when :string
577
+ if onecell == ""
578
+ str << ''
579
+ else
580
+ onecell.gsub!(/"/,'""')
581
+ str << ('"'+onecell+'"')
582
+ end
583
+ when :float,:percentage
584
+ if onecell == onecell.to_i
585
+ str << onecell.to_i.to_s
586
+ else
587
+ str << onecell.to_s
588
+ end
589
+ when :formula
590
+ if onecell.class == String
591
+ if onecell == ""
592
+ str << ''
593
+ else
594
+ onecell.gsub!(/"/,'""')
595
+ str << '"'+onecell+'"'
596
+ end
597
+ elsif onecell.class == Float
598
+ if onecell == onecell.to_i
599
+ str << onecell.to_i.to_s
600
+ else
601
+ str << onecell.to_s
602
+ end
603
+ else
604
+ raise "unhandled onecell-class "+onecell.class.to_s
605
+ end
606
+ when :date
607
+ str << onecell.to_s
608
+ when :time
609
+ str << GenericSpreadsheet.integer_to_timestring(onecell)
610
+ else
611
+ raise "unhandled celltype "+onecelltype.to_s
612
+ end
613
+ end
614
+ str
615
+ end
616
+
617
+ # converts an integer value to a time string like '02:05:06'
618
+ def self.integer_to_timestring(content)
619
+ h = (content/3600.0).floor
620
+ content = content - h*3600
621
+ m = (content/60.0).floor
622
+ content = content - m*60
623
+ s = content
624
+ sprintf("%02d:%02d:%02d",h,m,s)
625
+ end
626
+ end