hmcgowan-roo 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/History.txt +225 -0
  2. data/README.txt +43 -0
  3. data/lib/roo/excel.rb +455 -0
  4. data/lib/roo/excelx.rb +654 -0
  5. data/lib/roo/generic_spreadsheet.rb +636 -0
  6. data/lib/roo/google.rb +411 -0
  7. data/lib/roo/openoffice.rb +508 -0
  8. data/lib/roo/roo_rails_helper.rb +81 -0
  9. data/lib/roo/version.rb +9 -0
  10. data/lib/roo.rb +11 -0
  11. data/test/Bibelbund.csv +3741 -0
  12. data/test/Bibelbund.ods +0 -0
  13. data/test/Bibelbund.xls +0 -0
  14. data/test/Bibelbund.xlsx +0 -0
  15. data/test/Bibelbund1.ods +0 -0
  16. data/test/bbu.ods +0 -0
  17. data/test/bbu.xls +0 -0
  18. data/test/bbu.xlsx +0 -0
  19. data/test/bode-v1.ods.zip +0 -0
  20. data/test/bode-v1.xls.zip +0 -0
  21. data/test/boolean.ods +0 -0
  22. data/test/boolean.xls +0 -0
  23. data/test/boolean.xlsx +0 -0
  24. data/test/borders.ods +0 -0
  25. data/test/borders.xls +0 -0
  26. data/test/borders.xlsx +0 -0
  27. data/test/bug-row-column-fixnum-float.xls +0 -0
  28. data/test/datetime.ods +0 -0
  29. data/test/datetime.xls +0 -0
  30. data/test/datetime.xlsx +0 -0
  31. data/test/emptysheets.ods +0 -0
  32. data/test/emptysheets.xls +0 -0
  33. data/test/false_encoding.xls +0 -0
  34. data/test/formula.ods +0 -0
  35. data/test/formula.xls +0 -0
  36. data/test/formula.xlsx +0 -0
  37. data/test/html-escape.ods +0 -0
  38. data/test/no_spreadsheet_file.txt +1 -0
  39. data/test/numbers1.csv +18 -0
  40. data/test/numbers1.ods +0 -0
  41. data/test/numbers1.xls +0 -0
  42. data/test/numbers1.xlsx +0 -0
  43. data/test/numbers1_excel.csv +18 -0
  44. data/test/only_one_sheet.ods +0 -0
  45. data/test/only_one_sheet.xls +0 -0
  46. data/test/only_one_sheet.xlsx +0 -0
  47. data/test/ric.ods +0 -0
  48. data/test/simple_spreadsheet.ods +0 -0
  49. data/test/simple_spreadsheet.xls +0 -0
  50. data/test/simple_spreadsheet.xlsx +0 -0
  51. data/test/simple_spreadsheet_from_italo.ods +0 -0
  52. data/test/simple_spreadsheet_from_italo.xls +0 -0
  53. data/test/style.ods +0 -0
  54. data/test/style.xls +0 -0
  55. data/test/style.xlsx +0 -0
  56. data/test/test_helper.rb +19 -0
  57. data/test/test_roo.rb +4946 -0
  58. data/test/time-test.csv +2 -0
  59. data/test/time-test.ods +0 -0
  60. data/test/time-test.xls +0 -0
  61. data/test/time-test.xlsx +0 -0
  62. metadata +225 -0
@@ -0,0 +1,508 @@
1
+
2
+ require 'rubygems'
3
+ require 'rexml/document'
4
+ require 'fileutils'
5
+ require 'zip/zipfilesystem'
6
+ require 'date'
7
+ require 'base64'
8
+ require 'cgi'
9
+
10
+ class Openoffice < GenericSpreadsheet
11
+
12
+ @@nr = 0
13
+
14
+ # initialization and opening of a spreadsheet file
15
+ # values for packed: :zip
16
+ def initialize(filename, packed=nil, file_warning=:error) #, create = false)
17
+ @file_warning = file_warning
18
+ super()
19
+ @tmpdir = "oo_"+$$.to_s
20
+ @tmpdir = File.join(ENV['ROO_TMP'], @tmpdir) if ENV['ROO_TMP']
21
+ unless File.exists?(@tmpdir)
22
+ FileUtils::mkdir(@tmpdir)
23
+ end
24
+ filename = open_from_uri(filename) if filename[0,7] == "http://"
25
+ filename = unzip(filename) if packed and packed == :zip
26
+ begin
27
+ file_type_check(filename,'.ods','an openoffice')
28
+ #if create and ! File.exists?(filename)
29
+ # self.create_openoffice(filename)
30
+ #end
31
+ @cells_read = Hash.new
32
+ #TODO: @cells_read[:default] = false
33
+ @filename = filename
34
+ unless File.file?(@filename)
35
+ raise IOError, "file #{@filename} does not exist"
36
+ end
37
+ @@nr += 1
38
+ @file_nr = @@nr
39
+ extract_content
40
+ file = File.new(File.join(@tmpdir, @file_nr.to_s+"_roo_content.xml"))
41
+ @doc = REXML::Document.new file
42
+ file.close
43
+ ensure
44
+ #if ENV["roo_local"] != "thomas-p"
45
+ FileUtils::rm_r(@tmpdir)
46
+ #end
47
+ end
48
+ @default_sheet = nil
49
+ # no need to set default_sheet if there is only one sheet in the document
50
+ if self.sheets.size == 1
51
+ @default_sheet = self.sheets.first
52
+ end
53
+ @cell = Hash.new
54
+ @cell_type = Hash.new
55
+ @formula = Hash.new
56
+ @first_row = Hash.new
57
+ @last_row = Hash.new
58
+ @first_column = Hash.new
59
+ @last_column = Hash.new
60
+ @style = Hash.new
61
+ @style_defaults = Hash.new { |h,k| h[k] = [] }
62
+ @style_definitions = Hash.new
63
+ @header_line = 1
64
+ end
65
+
66
+ # creates a new empty openoffice-spreadsheet file
67
+ def create_openoffice(filename) #:nodoc:
68
+ #TODO: a better way for creating the file contents
69
+ # now you have to call mkbase64...rb to create an include file with all
70
+ # the empty files in an openoffice zip-file
71
+ load 'base64include.rb'
72
+ # puts @@empty_spreadsheet
73
+ f = File.open(filename,'wb')
74
+ f.print(Base64.decode64(@@empty_spreadsheet))
75
+ f.close
76
+ end
77
+
78
+ # Returns the content of a spreadsheet-cell.
79
+ # (1,1) is the upper left corner.
80
+ # (1,1), (1,'A'), ('A',1), ('a',1) all refers to the
81
+ # cell at the first line and first row.
82
+ def cell(row, col, sheet=nil)
83
+ sheet = @default_sheet unless sheet
84
+ read_cells(sheet) unless @cells_read[sheet]
85
+ row,col = normalize(row,col)
86
+ if celltype(row,col,sheet) == :date
87
+ yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
88
+ return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
89
+ end
90
+ @cell[sheet][[row,col]]
91
+ end
92
+
93
+ # Returns the formula at (row,col).
94
+ # Returns nil if there is no formula.
95
+ # The method #formula? checks if there is a formula.
96
+ def formula(row,col,sheet=nil)
97
+ sheet = @default_sheet unless sheet
98
+ read_cells(sheet) unless @cells_read[sheet]
99
+ row,col = normalize(row,col)
100
+ if @formula[sheet][[row,col]] == nil
101
+ return nil
102
+ else
103
+ return @formula[sheet][[row,col]]["oooc:".length..-1]
104
+ end
105
+ end
106
+
107
+ # true, if there is a formula
108
+ def formula?(row,col,sheet=nil)
109
+ sheet = @default_sheet unless sheet
110
+ read_cells(sheet) unless @cells_read[sheet]
111
+ row,col = normalize(row,col)
112
+ formula(row,col) != nil
113
+ end
114
+
115
+ class Font
116
+ attr_accessor :bold, :italic, :underline
117
+
118
+ def bold?
119
+ @bold == 'bold'
120
+ end
121
+
122
+ def italic?
123
+ @italic == 'italic'
124
+ end
125
+
126
+ def underline?
127
+ @underline != nil
128
+ end
129
+ end
130
+
131
+ # Given a cell, return the cell's style
132
+ def font(row, col, sheet=nil)
133
+ sheet = @default_sheet unless sheet
134
+ read_cells(sheet) unless @cells_read[sheet]
135
+ row,col = normalize(row,col)
136
+ style_name = @style[sheet][[row,col]] || @style_defaults[sheet][col - 1] || 'Default'
137
+ @style_definitions[style_name]
138
+ end
139
+
140
+ # set a cell to a certain value
141
+ # (this will not be saved back to the spreadsheet file!)
142
+ def set(row,col,value,sheet=nil) #:nodoc:
143
+ sheet = @default_sheet unless sheet
144
+ read_cells(sheet) unless @cells_read[sheet]
145
+ row,col = normalize(row,col)
146
+ set_value(row,col,value,sheet)
147
+ if value.class == Fixnum
148
+ set_type(row,col,:float,sheet)
149
+ elsif value.class == String
150
+ set_type(row,col,:string,sheet)
151
+ elsif value.class == Float
152
+ set_type(row,col,:string,sheet)
153
+ else
154
+ raise ArgumentError, "Type for "+value.to_s+" not set"
155
+ end
156
+ end
157
+
158
+ # returns the type of a cell:
159
+ # * :float
160
+ # * :string
161
+ # * :date
162
+ # * :percentage
163
+ # * :formula
164
+ # * :time
165
+ # * :datetime
166
+ def celltype(row,col,sheet=nil)
167
+ sheet = @default_sheet unless sheet
168
+ read_cells(sheet) unless @cells_read[sheet]
169
+ row,col = normalize(row,col)
170
+ if @formula[sheet][[row,col]]
171
+ return :formula
172
+ else
173
+ @cell_type[sheet][[row,col]]
174
+ end
175
+ end
176
+
177
+ # returns an array of sheet names in the spreadsheet
178
+ def sheets
179
+ return_sheets = []
180
+ oo_document_count = 0
181
+ @doc.each_element do |oo_document|
182
+ oo_document_count += 1
183
+ oo_element_count = 0
184
+ oo_document.each_element do |oo_element|
185
+ oo_element_count += 1
186
+ if oo_element.name == "body"
187
+ oo_element.each_element do |be|
188
+ if be.name == "spreadsheet"
189
+ be.each_element do |se|
190
+ if se.name == "table"
191
+ return_sheets << se.attributes['name']
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ return_sheets
200
+ end
201
+
202
+ # version of the openoffice document
203
+ # at 2007 this is always "1.0"
204
+ def officeversion
205
+ oo_version
206
+ @officeversion
207
+ end
208
+
209
+ # shows the internal representation of all cells
210
+ # mainly for debugging purposes
211
+ def to_s(sheet=nil)
212
+ sheet = @default_sheet unless sheet
213
+ read_cells(sheet) unless @cells_read[sheet]
214
+ @cell[sheet].inspect
215
+ end
216
+
217
+ # save spreadsheet
218
+ def save #:nodoc:
219
+ 42
220
+ end
221
+
222
+ # returns each formula in the selected sheet as an array of elements
223
+ # [row, col, formula]
224
+ def formulas(sheet=nil)
225
+ theformulas = Array.new
226
+ sheet = @default_sheet unless sheet
227
+ read_cells(sheet) unless @cells_read[sheet]
228
+ first_row(sheet).upto(last_row(sheet)) {|row|
229
+ first_column(sheet).upto(last_column(sheet)) {|col|
230
+ if formula?(row,col,sheet)
231
+ f = [row, col, formula(row,col,sheet)]
232
+ theformulas << f
233
+ end
234
+ }
235
+ }
236
+ theformulas
237
+ end
238
+
239
+ private
240
+
241
+ # read the version of the OO-Version
242
+ def oo_version
243
+ @doc.each_element do |oo_document|
244
+ @officeversion = oo_document.attributes['version']
245
+ end
246
+ end
247
+
248
+ # helper function to set the internal representation of cells
249
+ def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v,style_name)
250
+ key = [y,x+i]
251
+ @cell_type[sheet] = {} unless @cell_type[sheet]
252
+ @cell_type[sheet][key] = Openoffice.oo_type_2_roo_type(vt)
253
+ @formula[sheet] = {} unless @formula[sheet]
254
+ @formula[sheet][key] = formula if formula
255
+ @cell[sheet] = {} unless @cell[sheet]
256
+ @style[sheet] = {} unless @style[sheet]
257
+ @style[sheet][key] = style_name
258
+ case @cell_type[sheet][key]
259
+ when :float
260
+ @cell[sheet][key] = v.to_f
261
+ when :string
262
+ @cell[sheet][key] = str_v
263
+ when :date
264
+ if tr.attributes['date-value'].size != "XXXX-XX-XX".size
265
+ #-- dann ist noch eine Uhrzeit vorhanden
266
+ #-- "1961-11-21T12:17:18"
267
+ @cell[sheet][key] = DateTime.parse(tr.attributes['date-value'])
268
+ @cell_type[sheet][key] = :datetime
269
+ else
270
+ @cell[sheet][key] = tr.attributes['date-value']
271
+ end
272
+ when :percentage
273
+ @cell[sheet][key] = v.to_f
274
+ when :time
275
+ hms = v.split(':')
276
+ @cell[sheet][key] = hms[0].to_i*3600 + hms[1].to_i*60 + hms[2].to_i
277
+ else
278
+ @cell[sheet][key] = v
279
+ end
280
+ end
281
+
282
+ # read all cells in the selected sheet
283
+ #--
284
+ # the following construct means '4 blanks'
285
+ # some content <text:s text:c="3"/>
286
+ #++
287
+ def read_cells(sheet=nil)
288
+ sheet = @default_sheet unless sheet
289
+ sheet_found = false
290
+ raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
291
+ raise RangeError unless self.sheets.include? sheet
292
+ oo_document_count = 0
293
+ @doc.each_element do |oo_document|
294
+ # @officeversion = oo_document.attributes['version']
295
+ oo_document_count += 1
296
+ oo_element_count = 0
297
+ oo_document.each_element do |oo_element|
298
+ oo_element_count += 1
299
+ if oo_element.name == "body"
300
+ oo_element.each_element do |be|
301
+ if be.name == "spreadsheet"
302
+ be.each_element do |se|
303
+ if se.name == "table"
304
+ if se.attributes['name']==sheet
305
+ sheet_found = true
306
+ x=1
307
+ y=1
308
+ se.each_element do |te|
309
+ if te.name == "table-column"
310
+ rep = te.attributes["number-columns-repeated"]
311
+ @style_defaults[sheet] << te.attributes["default-cell-style-name"]
312
+ elsif te.name == "table-row"
313
+ if te.attributes['number-rows-repeated']
314
+ skip_y = te.attributes['number-rows-repeated'].to_i
315
+ y = y + skip_y - 1 # minus 1 because this line will be counted as a line element
316
+ end
317
+ te.each_element do |tr|
318
+ if tr.name == 'table-cell'
319
+ skip = tr.attributes['number-columns-repeated']
320
+ formula = tr.attributes['formula']
321
+ vt = tr.attributes['value-type']
322
+ v = tr.attributes['value']
323
+ style_name = tr.attributes['style-name']
324
+ if vt == 'string'
325
+ str_v = ''
326
+ # insert \n if there is more than one paragraph
327
+ para_count = 0
328
+ tr.each_element do |str|
329
+ if str.name == 'p'
330
+ v = str.text
331
+ str_v += "\n" if para_count > 0
332
+ para_count += 1
333
+ if str.children.size > 1
334
+ str_v = children_to_string(str.children)
335
+ else
336
+ str.children.each {|child|
337
+ str_v = str_v + child.to_s #.text
338
+ }
339
+ end
340
+ str_v.gsub!(/&apos;/,"'") # special case not supported by unescapeHTML
341
+ str_v = CGI.unescapeHTML(str_v)
342
+ end # == 'p'
343
+ end
344
+ elsif vt == 'time'
345
+ tr.each_element do |str|
346
+ if str.name == 'p'
347
+ v = str.text
348
+ end
349
+ end
350
+ elsif vt == '' or vt == nil
351
+ #
352
+ elsif vt == 'date'
353
+ #
354
+ elsif vt == 'percentage'
355
+ #
356
+ elsif vt == 'float'
357
+ #
358
+ elsif vt == 'boolean'
359
+ v = tr.attributes['boolean-value']
360
+ #
361
+ else
362
+ # raise "unknown type #{vt}"
363
+ end
364
+ if skip
365
+ if v != nil or tr.attributes['date-value']
366
+ 0.upto(skip.to_i-1) do |i|
367
+ set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v,style_name)
368
+ end
369
+ end
370
+ x += (skip.to_i - 1)
371
+ end # if skip
372
+ set_cell_values(sheet,x,y,0,v,vt,formula,tr,str_v,style_name)
373
+ x += 1
374
+ end
375
+ end
376
+ y += 1
377
+ x = 1
378
+ end
379
+ end
380
+ end # sheet
381
+ end
382
+ end
383
+ end
384
+ end
385
+ elsif oo_element.name == "automatic-styles"
386
+ read_styles(oo_element)
387
+ end
388
+ end
389
+ end
390
+ if !sheet_found
391
+ raise RangeError
392
+ end
393
+ @cells_read[sheet] = true
394
+ end
395
+
396
+ def read_styles(style_elements)
397
+ @style_definitions['Default'] = Openoffice::Font.new
398
+ style_elements.each do |style|
399
+ next unless style.name == 'style'
400
+ style_name = style.attributes['name']
401
+ style.each do |properties|
402
+ font = Openoffice::Font.new
403
+ font.bold = properties.attributes['font-weight']
404
+ font.italic = properties.attributes['font-style']
405
+ font.underline = properties.attributes['text-underline-style']
406
+ @style_definitions[style_name] = font
407
+ end
408
+ end
409
+ end
410
+
411
+ # Checks if the default_sheet exists. If not an RangeError exception is
412
+ # raised
413
+ def check_default_sheet
414
+ sheet_found = false
415
+ raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil
416
+ @doc.each_element do |oo_document|
417
+ oo_element_count = 0
418
+ oo_document.each_element do |oo_element|
419
+ oo_element_count += 1
420
+ if oo_element.name == "body"
421
+ oo_element.each_element do |be|
422
+ if be.name == "spreadsheet"
423
+ be.each_element do |se|
424
+ if se.name == "table"
425
+ if se.attributes['name'] == @default_sheet
426
+ sheet_found = true
427
+ end # sheet
428
+ end
429
+ end
430
+ end
431
+ end
432
+ end
433
+ end
434
+ end
435
+ if ! sheet_found
436
+ raise RangeError, "sheet '#{@default_sheet}' not found"
437
+ end
438
+ end
439
+
440
+ def process_zipfile(zip, path='')
441
+ if zip.file.file? path
442
+ if path == "content.xml"
443
+ open(File.join(@tmpdir, @file_nr.to_s+'_roo_content.xml'),'wb') {|f|
444
+ f << zip.read(path)
445
+ }
446
+ end
447
+ else
448
+ unless path.empty?
449
+ path += '/'
450
+ end
451
+ zip.dir.foreach(path) do |filename|
452
+ process_zipfile(zip, path+filename)
453
+ end
454
+ end
455
+ end
456
+
457
+ def extract_content
458
+ Zip::ZipFile.open(@filename) do |zip|
459
+ process_zipfile(zip)
460
+ end
461
+ end
462
+
463
+ def set_value(row,col,value,sheet=nil)
464
+ sheet = @default_value unless sheet
465
+ @cell[sheet][[row,col]] = value
466
+ end
467
+
468
+ def set_type(row,col,type,sheet=nil)
469
+ sheet = @default_value unless sheet
470
+ @cell_type[sheet][[row,col]] = type
471
+ end
472
+
473
+ A_ROO_TYPE = {
474
+ "float" => :float,
475
+ "string" => :string,
476
+ "date" => :date,
477
+ "percentage" => :percentage,
478
+ "time" => :time,
479
+ }
480
+
481
+ def Openoffice.oo_type_2_roo_type(ootype)
482
+ return A_ROO_TYPE[ootype]
483
+ end
484
+
485
+ # helper method to convert compressed spaces and other elements within
486
+ # an text into a string
487
+ def children_to_string(children)
488
+ result = ''
489
+ children.each {|child|
490
+ if child.class == REXML::Text
491
+ result = result + child.to_s
492
+ else
493
+ if child.name == 's'
494
+ compressed_spaces = child.attributes['c'].to_i
495
+ # no explicit number means a count of 1:
496
+ if compressed_spaces == 0
497
+ compressed_spaces = 1
498
+ end
499
+ result = result + " "*compressed_spaces
500
+ else
501
+ result = result + child.to_s
502
+ end
503
+ end
504
+ }
505
+ result
506
+ end
507
+
508
+ end # class
@@ -0,0 +1,81 @@
1
+ def spreadsheet(spreadsheet, sheets, options={})
2
+ coordinates = true # default
3
+ o=""
4
+ if options[:coordinates] != nil
5
+ o << ":coordinates uebergeben: #{options[:coordinates]}"
6
+ coordinates = options[:coordinates]
7
+ end
8
+ if options[:bgcolor]
9
+ bgcolor = options[:bgcolor]
10
+ else
11
+ bgcolor = false
12
+ end
13
+
14
+ sheets.each { |sheet|
15
+ @rspreadsheet.default_sheet = sheet
16
+ linenumber = @rspreadsheet.first_row(sheet)
17
+ if options[:first_row]
18
+ linenumber += (options[:first_row]-1)
19
+ end
20
+ o << '<table border="0" cellspacing="1" cellpadding="1">'
21
+ if options[:first_row]
22
+ first_row = options[:first_row]
23
+ end
24
+ if options[:last_row]
25
+ last_row = options[:last_row]
26
+ end
27
+ if options[:first_column]
28
+ first_column = options[:first_column]
29
+ end
30
+ if options[:last_column]
31
+ last_column = options[:last_column]
32
+ end
33
+ first_row = @rspreadsheet.first_row(sheet) unless first_row
34
+ last_row = @rspreadsheet.last_row(sheet) unless last_row
35
+ first_column = @rspreadsheet.first_column(sheet) unless first_column
36
+ last_column = @rspreadsheet.last_column(sheet) unless last_column
37
+ if coordinates
38
+ o << " <tr>"
39
+ o << " <td>&nbsp;</td>"
40
+ @rspreadsheet.first_column(sheet).upto(@rspreadsheet.last_column(sheet)) {|c|
41
+ if c < first_column or c > last_column
42
+ next
43
+ end
44
+ o << " <td>"
45
+ o << " <b>#{GenericSpreadsheet.number_to_letter(c)}</b>"
46
+ o << " </td>"
47
+ }
48
+ o << "</tr>"
49
+ end
50
+ @rspreadsheet.first_row.upto(@rspreadsheet.last_row) do |y|
51
+ if first_row and (y < first_row or y > last_row)
52
+ next
53
+ end
54
+ o << "<tr>"
55
+ if coordinates
56
+ o << "<td><b>#{linenumber.to_s}</b></td>"
57
+ end
58
+ linenumber += 1
59
+ @rspreadsheet.first_column(sheet).upto(@rspreadsheet.last_column(sheet)) do |x|
60
+ if x < first_column or x > last_column
61
+ next
62
+ end
63
+ if bgcolor
64
+ o << "<td bgcolor=\"#{bgcolor}\">"
65
+ else
66
+ o << '<td bgcolor="lightgreen">'
67
+ end
68
+ if @rspreadsheet.cell(y,x).to_s.empty?
69
+ o << "&nbsp;"
70
+ else
71
+ o << "#{@rspreadsheet.cell(y,x)}"
72
+ end
73
+ o << "</td>"
74
+ end
75
+ o << "</tr>"
76
+ end
77
+ o << "</table>"
78
+ } # each sheet
79
+ return o
80
+ end
81
+
@@ -0,0 +1,9 @@
1
+ module Roo #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 1
4
+ MINOR = 2
5
+ TINY = 3
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/lib/roo.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Roo
2
+ end
3
+
4
+ require 'roo/version'
5
+ # require 'roo/spreadsheetparser' TODO:
6
+ require 'roo/generic_spreadsheet'
7
+ require 'roo/openoffice'
8
+ require 'roo/excel'
9
+ require 'roo/excelx'
10
+ require 'roo/google'
11
+ require 'roo/roo_rails_helper'