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
data/History.txt ADDED
@@ -0,0 +1,225 @@
1
+ == 1.2.3 2009-01-04
2
+
3
+ * bugfix
4
+ * fixed encoding in #cell at exported Google-spreadsheets (.xls)
5
+
6
+ == 1.2.2 2008-12-14
7
+
8
+ * 2 enhancements
9
+ * added celltype :datetime in Excelx
10
+ * added celltype :datetime in Google
11
+
12
+ == 1.2.1 2008-11-13
13
+
14
+ * 1 enhancement
15
+ * added celltype :datetime in Openoffice and Excel
16
+
17
+ == 1.2.0 2008-08-24
18
+ * 3 major enhancements
19
+ * Excelx: improved the detection of cell type and conversion into roo types
20
+ * All: to_csv: changed boundaries from first_row,1..last_row,last_column to 1,1..last_row,last_column
21
+ * All: Environment variable "ROO_TMP" indicate where temporary directories will be created (if not set the default is the current working directory)
22
+ * 2 bugfixes
23
+ * Excel: improved the detection of last_row/last_column (parseexcel-gem bug?)
24
+ * Excel/Excelx/Openoffice: temporary directories were not removed at opening a file of the wrong type
25
+ == 1.1.0 2008-07-26
26
+ * 2 major enhancements
27
+ * Excel: speed improvements
28
+ * Changed the behavior of reading files with the wrong type
29
+ * 3 bugfixes
30
+ * Google: added normalize in set_value method
31
+ * Excel: last_row in Excel class did not work properly under some circumstances
32
+ * all: fixed a bug in #to_xml if there is an empty sheet
33
+ == 1.0.2 2008-07-04
34
+ * 2 bugfixes
35
+ * Excelx: fixed a bug when there are .xml.rels files in the XLSX archive
36
+ * Excelx: fixed a bug with celltype recognition (see comment with "2008-07-03")
37
+ == 1.0.1 2008-06-30
38
+ * 1 bugfix
39
+ * Excel: row/column method Fixnum/Float confusion
40
+ == 1.0.0 2008-05-28
41
+ * 2 major enhancements
42
+ * support of Excel's new .xlsx file format
43
+ * method #to_xml for exporting a spreadsheet to an xml representation
44
+ * 1 bugfix
45
+ * fixed a bug with excel-spreadsheet character conversion under Macintosh Darwin
46
+ == 0.9.4 2008-04-22
47
+ * 1 bugfix
48
+ * fixed a bug with excel-spreadsheet character conversion under Solaris
49
+ == 0.9.3 2008-03-25
50
+ * 1 bugfix
51
+ * no more tmp directories if an invalid spreadsheet file was openend
52
+ == 0.9.2 2008-03-24
53
+ * 1 enhancement
54
+ * new celltype :time
55
+ * 1 bugfix
56
+ * time values like '23:15' are handled as seconds from midnight
57
+ == 0.9.1 2008-03-23
58
+ * 1 enhancement
59
+ * additional 'sheet' parameter in Google#set_value
60
+ * 1 bugfix
61
+ * fixed a bug within Google#set_value. thanks to davecahill <dpcahill@gmail.com> for the patch.
62
+ == 0.9.0 2008-01-24
63
+ * 1 enhancement:
64
+ * better support of roo spreadsheets in rails views
65
+ == 0.8.5 2008-01-16
66
+ * 1 bugfix
67
+ * fixed a bug within #to_cvs and explicit call of a sheet
68
+ == 0.8.4 2008-01-01
69
+ * 1 bugfix
70
+ * fixed 'find_by_condition' for excel sheets (header_line= --> GenericSpredsheet)
71
+ == 0.8.3 2007-12-31
72
+ * 2 bugfixes
73
+ * another fix for the encoding issue in excel sheet-names
74
+ * reactived the Excel#find method which has been disappeared in the last restructoring, moved to GenericSpreadsheet
75
+ == 0.8.2 2007-12-28
76
+ * 1 enhancement:
77
+ * basename() only in method #info
78
+ * 2 bugfixes
79
+ * changed logging-method to mysql-database in test code with AR, table column 'class' => 'class_name'
80
+ * reactived the Excel#to_csv method which has been disappeared in the last restructoring
81
+ == 0.8.1 2007-12-22
82
+ * 3 bugfixes
83
+ * fixed a bug with first/last-row/column in empty sheet
84
+ * #info prints now '- empty -' if a sheet within a document is empty
85
+ * tried to fix the iconv conversion problem
86
+ == 0.8.0 2007-12-15
87
+ * 2 enhancements:
88
+ * Google online spreadsheets were implemented
89
+ * some methods common to more than one class were factored out to the GenericSpreadsheet (virtual) class
90
+ == 0.7.0 2007-11-23
91
+ * 6 enhancements:
92
+ * Openoffice/Excel: the most methods can be called with an option 'sheet'
93
+ parameter which will be used instead of the default sheet
94
+ * Excel: improved the speed of CVS output
95
+ * Openoffice/Excel: new method #column
96
+ * Openoffice/Excel: new method #find
97
+ * Openoffice/Excel: new method #info
98
+ * better exception if a spreadsheet file does not exist
99
+ == 0.6.1 2007-10-06
100
+ * 2 enhancements:
101
+ * Openoffice: percentage-values are now treated as numbers (not strings)
102
+ * Openoffice: refactoring
103
+ * 1 bugfix
104
+ * Openoffice: repeating date-values in a line are now handled correctly
105
+ == 0.6.0 2007-10-06
106
+ * 1 enhancement:
107
+ * csv-output to stdout or file
108
+ == 0.5.4 2007-08-27
109
+ * 1 bugfix
110
+ * Openoffice: fixed a bug with internal representation of a spreadsheet (thanks to Ric Kamicar for the patch)
111
+ == 0.5.3 2007-08-26
112
+ * 2 enhancements:
113
+ * Openoffice: can now read zip-ed files
114
+ * Openoffice: can now read files from http://-URL over the net
115
+ == 0.5.2 2007-08-26
116
+ * 1 bugfix
117
+ * excel: removed debugging output
118
+ == 0.5.1 2007-08-26
119
+ * 4 enhancements:
120
+ * Openoffice: Exception if an illegal sheet-name is selected
121
+ * Openoffice/Excel: no need to set a default_sheet if there is only one in
122
+ the document
123
+ * Excel: can now read zip-ed files
124
+ * Excel: can now read files from http://-URL over the net
125
+
126
+ == 0.5.0 2007-07-20
127
+ * 3 enhancements:
128
+ * Excel-objects: the methods default_sheet= and sheets can now handle names instead of numbers
129
+ * changed the celltype methods to return symbols, not strings anymore (possible values are :formula, :float, :string, :date, :percentage (if you need strings you can convert it with .to_s)
130
+ * tests can now run on the client machine (not only my machine), if there are not public released files involved these tests are skipped
131
+
132
+ == 0.4.1 2007-06-27
133
+ * 1 bugfix
134
+ * there was ONE false require-statement which led to misleading error messageswhen this gem was used
135
+
136
+ == 0.4.0 2007-06-27
137
+ * 7 enhancements:
138
+ * robustness: Exception if no default_sheet was set
139
+ * new method reload() implemented
140
+ * about 15 % more method documentation
141
+ * optimization: huge increase of speed (no need to use fixed borders anymore)
142
+ * added the method 'formulas' which gives you all formulas in a spreadsheet
143
+ * added the method 'set' which can set cells to a certain value
144
+ * added the method 'to_yaml' which can produce output for importing in a (rails) database
145
+ * 4 bugfixes
146
+ * ..row_as_letter methods were nonsense - removed
147
+ * @cells_read should be reset if the default_sheet is changed
148
+ * error in excel-part: strings are now converted to utf-8 (the parsexcel-gem gave me an error with my test data, which could not converted to .to_s using latin1 encoding)
149
+ * fixed bug when default_sheet is changed
150
+
151
+ == 0.3.0 2007-06-20
152
+ * 1 enhancement:
153
+ * Openoffice: formula support
154
+
155
+ == 0.2.7 2007-06-20
156
+ * 1 bugfix:
157
+ * Excel: float-numbers were truncated to integer
158
+
159
+ == 0.2.6 2007-06-19
160
+ * 1 bugfix:
161
+ * Openoffice: two or more consecutive cells with string content failed
162
+
163
+ == 0.2.5 2007-06-17
164
+
165
+ * 2 enhancements:
166
+ * Excel: row method implemented
167
+ * more tests
168
+ * 1 bugfix:
169
+ * Openoffice: row method fixed
170
+
171
+ == 0.2.4 2007-06-16
172
+ * 1 bugfix:
173
+ * ID 11605 Two cols with same value: crash roo (openoffice version only)
174
+
175
+ == 0.2.3 2007-06-02
176
+ * 3 enhancements:
177
+ * more robust call att Excel#default_sheet= when called with a name
178
+ * new method empty?
179
+ * refactoring
180
+ * 1 bugfix:
181
+ * bugfix in Excel#celltype
182
+ * bugfix (running under windows only) in closing the temp file before removing it
183
+
184
+ == 0.2.2 2007-06-01
185
+ * 1 bugfix:
186
+ * correct pathname for running with windows
187
+
188
+
189
+ == 0.2.2 2007-06-01
190
+ * 1 bugfix:
191
+ * incorrect dependencies fixed
192
+
193
+ == 0.2.0 2007-06-01
194
+ * 1 major enhancement:
195
+ * support for MS-Excel Spreadsheets
196
+
197
+ == 0.1.2 2007-05-31
198
+ * 1 major enhancement:
199
+ * cells with more than one character, like 'AA' can now be handled
200
+
201
+ == 0.1.1 2007-05-31
202
+ * 1 Bugfix
203
+ * Bugfix in first/last methods
204
+
205
+ == 0.1.0 2007-05-31
206
+
207
+ * 1 major enhancement:
208
+ * new methods first/last row/column
209
+ * new method officeversion
210
+
211
+ == 0.0.3 2007-05-30
212
+
213
+ * 1 minor enhancement:
214
+ * new method row()
215
+
216
+ == 0.0.2 2007-05-30
217
+
218
+ * 2 major enhancement:
219
+ * fixed some bugs
220
+ * more ways to access a cell
221
+
222
+ == 0.0.1 2007-05-25
223
+
224
+ * 1 major enhancement:
225
+ * Initial release
data/README.txt ADDED
@@ -0,0 +1,43 @@
1
+ README for roo
2
+ ==============
3
+
4
+ Installation:
5
+
6
+ sudo gem install roo
7
+
8
+ Usage:
9
+
10
+ require 'rubygems'
11
+ require 'roo'
12
+
13
+ s = Openoffice.new("myspreadsheet.ods") # creates an Openoffice Spreadsheet instance
14
+ s = Excel.new("myspreadsheet.xls") # creates an Excel Spreadsheet instance
15
+ s = Google.new("myspreadsheetkey_at_google") # creates an Google Spreadsheet instance
16
+ s = Excelx.new("myspreadsheet.xlsx") # creates an Excel Spreadsheet instance for Excel .xlsx files
17
+
18
+ s.default_sheet = s.sheets.first # first sheet in the spreadsheet file will be used
19
+
20
+ # s.sheet is an array which holds the names of the sheets within
21
+ # a spreadsheet.
22
+ # you can also write
23
+ # s.default_sheet = s.sheets[3] or
24
+ # s.default_sheet = 'Sheet 3'
25
+
26
+ s.cell(1,1) # returns the content of the first row/first cell in the sheet
27
+ s.cell('A',1) # same cell
28
+ s.cell(1,'A') # same cell
29
+ s.cell(1,'A',s.sheets[0]) # same cell
30
+
31
+ # almost all methods have an optional argument 'sheet'.
32
+ # If this parameter is ommitted, the default_sheet will be used.
33
+
34
+ s.info # prints infos about the spreadsheet file
35
+
36
+ s.first_row # the number of the first row
37
+ s.last_row # the number of the last row
38
+ s.first_column # the number of the first column
39
+ s.last_column # the number of the last column
40
+
41
+
42
+ see http://roo.rubyforge.org for a more complete tutorial
43
+
data/lib/roo/excel.rb ADDED
@@ -0,0 +1,455 @@
1
+ require 'rubygems'
2
+ gem 'spreadsheet', '>= 0.6.3.1'
3
+ require 'spreadsheet'
4
+ CHARGUESS = false
5
+ require 'charguess' if CHARGUESS
6
+
7
+ # ruby-spreadsheet has a font object so we're extending it
8
+ # with our own functionality but still providing full access
9
+ # to the user for other font information
10
+ module ExcelFontExtensions
11
+ def bold?(*args)
12
+ #From ruby-spreadsheet doc: 100 <= weight <= 1000, bold => 700, normal => 400
13
+ case weight
14
+ when 700
15
+ true
16
+ else
17
+ false
18
+ end
19
+ end
20
+
21
+ def italic?
22
+ italic
23
+ end
24
+
25
+ def underline?
26
+ underline != :none
27
+ end
28
+
29
+ end
30
+
31
+ # Class for handling Excel-Spreadsheets
32
+ class Excel < GenericSpreadsheet
33
+
34
+ EXCEL_NO_FORMULAS = 'formulas are not supported for excel spreadsheets'
35
+
36
+ # Creates a new Excel spreadsheet object.
37
+ # Parameter packed: :zip - File is a zip-file
38
+ def initialize(filename, packed = nil, file_warning = :error)
39
+ super()
40
+ @file_warning = file_warning
41
+ @tmpdir = "oo_"+$$.to_s
42
+ @tmpdir = File.join(ENV['ROO_TMP'], @tmpdir) if ENV['ROO_TMP']
43
+ unless File.exists?(@tmpdir)
44
+ FileUtils::mkdir(@tmpdir)
45
+ end
46
+ filename = open_from_uri(filename) if filename[0,7] == "http://"
47
+ filename = open_from_stream(filename[7..-1]) if filename[0,7] == "stream:"
48
+ filename = unzip(filename) if packed and packed == :zip
49
+ begin
50
+ file_type_check(filename,'.xls','an Excel')
51
+ @filename = filename
52
+ unless File.file?(@filename)
53
+ raise IOError, "file #{@filename} does not exist"
54
+ end
55
+ @workbook = Spreadsheet.open(filename)
56
+ @default_sheet = nil
57
+ # no need to set default_sheet if there is only one sheet in the document
58
+ if self.sheets.size == 1
59
+ @default_sheet = self.sheets.first
60
+ end
61
+ ensure
62
+ #if ENV["roo_local"] != "thomas-p"
63
+ FileUtils::rm_r(@tmpdir)
64
+ #end
65
+ end
66
+ @cell = Hash.new
67
+ @cell_type = Hash.new
68
+ @formula = Hash.new
69
+ @first_row = Hash.new
70
+ @last_row = Hash.new
71
+ @first_column = Hash.new
72
+ @last_column = Hash.new
73
+ @header_line = 1
74
+ @cells_read = Hash.new
75
+ @fonts = Hash.new
76
+ end
77
+
78
+ # returns an array of sheet names in the spreadsheet
79
+ def sheets
80
+ result = []
81
+ @workbook.worksheets.each do |worksheet|
82
+ # TODO: is there a better way to do conversion?
83
+ if CHARGUESS
84
+ encoding = CharGuess::guess(worksheet.name)
85
+ encoding = 'unicode' unless encoding
86
+
87
+
88
+ result << Iconv.new('utf-8',encoding).iconv(
89
+ worksheet.name
90
+ )
91
+ else
92
+ result << platform_specific_iconv(worksheet.name)
93
+ end
94
+ end
95
+ return result
96
+ end
97
+
98
+ # returns the content of a cell. The upper left corner is (1,1) or ('A',1)
99
+ def cell(row,col,sheet=nil)
100
+ sheet = @default_sheet unless sheet
101
+ raise ArgumentError unless sheet
102
+ read_cells(sheet) unless @cells_read[sheet]
103
+ raise "should be read" unless @cells_read[sheet]
104
+ row,col = normalize(row,col)
105
+ if celltype(row,col,sheet) == :date
106
+ yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
107
+ return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
108
+ end
109
+ if celltype(row,col,sheet) == :string
110
+ return platform_specific_iconv(@cell[sheet][[row,col]])
111
+ else
112
+ return @cell[sheet][[row,col]]
113
+ end
114
+ end
115
+
116
+ # returns the type of a cell:
117
+ # * :float
118
+ # * :string,
119
+ # * :date
120
+ # * :percentage
121
+ # * :formula
122
+ # * :time
123
+ # * :datetime
124
+ def celltype(row,col,sheet=nil)
125
+ sheet = @default_sheet unless sheet
126
+ read_cells(sheet) unless @cells_read[sheet]
127
+ row,col = normalize(row,col)
128
+ begin
129
+ if @formula[sheet][[row,col]]
130
+ return :formula
131
+ else
132
+ @cell_type[sheet][[row,col]]
133
+ end
134
+ rescue
135
+ puts "Error in sheet #{sheet}, row #{row}, col #{col}"
136
+ raise
137
+ end
138
+ end
139
+
140
+ # returns the first non empty column
141
+ def first_column(sheet=nil)
142
+ sheet = @default_sheet unless sheet
143
+ return @first_column[sheet] if @first_column[sheet]
144
+ fr, lr, fc, lc = get_firsts_lasts(sheet)
145
+ fc
146
+ end
147
+
148
+ # returns the last non empty column
149
+ def last_column(sheet=nil)
150
+ sheet = @default_sheet unless sheet
151
+ return @last_column[sheet] if @last_column[sheet]
152
+ fr, lr, fc, lc = get_firsts_lasts(sheet)
153
+ lc
154
+ end
155
+
156
+ # returns the first non empty row
157
+ def first_row(sheet=nil)
158
+ sheet = @default_sheet unless sheet
159
+ return @first_row[sheet] if @first_row[sheet]
160
+ fr, lr, fc, lc = get_firsts_lasts(sheet)
161
+ fr
162
+ end
163
+
164
+ # returns the last non empty row
165
+ def last_row(sheet=nil)
166
+ sheet = @default_sheet unless sheet
167
+ return @last_row[sheet] if @last_row[sheet]
168
+ fr, lr, fc, lc = get_firsts_lasts(sheet)
169
+ lr
170
+ end
171
+
172
+ # returns NO formula in excel spreadsheets
173
+ def formula(row,col,sheet=nil)
174
+ raise EXCEL_NO_FORMULAS
175
+ end
176
+
177
+ # raises an exception because formulas are not supported for excel files
178
+ def formula?(row,col,sheet=nil)
179
+ raise EXCEL_NO_FORMULAS
180
+ end
181
+
182
+ # returns NO formulas in excel spreadsheets
183
+ def formulas(sheet=nil)
184
+ raise EXCEL_NO_FORMULAS
185
+ end
186
+
187
+ # Given a cell, return the cell's font
188
+ def font(row, col, sheet=nil)
189
+ sheet = @default_sheet unless sheet
190
+ read_cells(sheet) unless @cells_read[sheet]
191
+ row,col = normalize(row,col)
192
+ @fonts[sheet][[row,col]]
193
+ end
194
+
195
+ # shows the internal representation of all cells
196
+ # mainly for debugging purposes
197
+ def to_s(sheet=nil)
198
+ sheet = @default_sheet unless sheet
199
+ read_cells(sheet) unless @cells_read[sheet]
200
+ @cell[sheet].inspect
201
+ end
202
+
203
+ private
204
+ # determine the first and last boundaries
205
+ def get_firsts_lasts(sheet=nil)
206
+
207
+ # 2008-09-14 BEGINf
208
+ fr=lr=fc=lc=nil
209
+ sheet = @default_sheet unless sheet
210
+ if ! @cells_read[sheet]
211
+ read_cells(sheet)
212
+ end
213
+ if @cell[sheet] # nur wenn ueberhaupt Zellen belegt sind
214
+ @cell[sheet].each {|cellitem|
215
+ key = cellitem.first
216
+ y,x = key
217
+
218
+ if cellitem[1].class != String or
219
+ (cellitem[1].class == String and cellitem[1] != "")
220
+ fr = y unless fr
221
+ fr = y if y < fr
222
+
223
+ lr = y unless lr
224
+ lr = y if y > lr
225
+
226
+ fc = x unless fc
227
+ fc = x if x < fc
228
+
229
+ lc = x unless lc
230
+ lc = x if x > lc
231
+ end
232
+ }
233
+ end
234
+ @first_row[sheet] = fr
235
+ @last_row[sheet] = lr
236
+ @first_column[sheet] = fc
237
+ @last_column[sheet] = lc
238
+ return fr, lr, fc, lc
239
+ end
240
+
241
+ # converts name of a sheet to index (0,1,2,..)
242
+ def sheet_no(name)
243
+ return name-1 if name.kind_of?(Fixnum)
244
+ i = 0
245
+ @workbook.worksheets.each do |worksheet|
246
+ # TODO: is there a better way to do conversion?
247
+ return i if name == platform_specific_iconv(worksheet.name)
248
+ #Iconv.new('utf-8','unicode').iconv(
249
+ # @workbook.worksheet(i).name
250
+ # )
251
+ i += 1
252
+ end
253
+ raise StandardError, "sheet '#{name}' not found"
254
+ end
255
+
256
+ def empty_row?(row)
257
+ content = false
258
+ row.compact.each {|elem|
259
+ if elem != ''
260
+ content = true
261
+ end
262
+ }
263
+ ! content
264
+ end
265
+
266
+ def empty_column?(col)
267
+ content = false
268
+ col.compact.each {|elem|
269
+ if elem != ''
270
+ content = true
271
+ end
272
+ }
273
+ ! content
274
+ end
275
+
276
+ def platform_specific_iconv(value)
277
+ case RUBY_PLATFORM.downcase
278
+ when /darwin/
279
+ result = Iconv.new('utf-8','utf-8').iconv(value)
280
+ when /solaris/
281
+ result = Iconv.new('utf-8','utf-8').iconv(value)
282
+ when /mswin32/
283
+ result = Iconv.new('utf-8','iso-8859-1').iconv(value)
284
+ else
285
+ result = value
286
+ end # case
287
+ if every_second_null?(result)
288
+ result = remove_every_second_null(result)
289
+ end
290
+ result
291
+ end
292
+
293
+ def every_second_null?(str)
294
+ result = true
295
+ return false if str.length < 2
296
+ 0.upto(str.length/2-1) do |i|
297
+ c = str[i*2,1]
298
+ n = str[i*2+1,1]
299
+ if n != "\000"
300
+ result = false
301
+ break
302
+ end
303
+ end
304
+ result
305
+ end
306
+
307
+ def remove_every_second_null(str)
308
+ result = ''
309
+ 0.upto(str.length/2-1) do |i|
310
+ c = str[i*2,1]
311
+ result += c
312
+ end
313
+ result
314
+ end
315
+
316
+ # helper function to set the internal representation of cells
317
+ def set_cell_values(sheet,row,col,i,v,vt,formula,tr,font)
318
+ #key = "#{y},#{x+i}"
319
+ key = [row,col+i]
320
+ @cell_type[sheet] = {} unless @cell_type[sheet]
321
+ @cell_type[sheet][key] = vt
322
+ @formula[sheet] = {} unless @formula[sheet]
323
+ @formula[sheet][key] = formula if formula
324
+ @cell[sheet] = {} unless @cell[sheet]
325
+ @fonts[sheet] = {} unless @fonts[sheet]
326
+ @fonts[sheet][key] = font
327
+
328
+ case vt # @cell_type[sheet][key]
329
+ when :float
330
+ @cell[sheet][key] = v.to_f
331
+ when :string
332
+ @cell[sheet][key] = v
333
+ when :date
334
+ @cell[sheet][key] = v
335
+ when :datetime
336
+ @cell[sheet][key] = DateTime.new(v.year,v.month,v.day,v.hour,v.min,v.sec)
337
+ when :percentage
338
+ @cell[sheet][key] = v.to_f
339
+ when :time
340
+ @cell[sheet][key] = v
341
+ else
342
+ @cell[sheet][key] = v
343
+ end
344
+ end
345
+
346
+ # read all cells in the selected sheet
347
+ def read_cells(sheet=nil)
348
+ sheet = @default_sheet unless sheet
349
+ raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
350
+ raise RangeError unless self.sheets.include? sheet
351
+
352
+ if @cells_read[sheet]
353
+ raise "sheet #{sheet} already read"
354
+ end
355
+
356
+ worksheet = @workbook.worksheet(sheet_no(sheet))
357
+ row_index=1
358
+ worksheet.each(0) do |row|
359
+ (0..row.size).each do |cell_index|
360
+ cell = row.at(cell_index)
361
+ next if cell.nil? #skip empty cells
362
+ next if cell.class == Spreadsheet::Formula
363
+ if date_or_time?(row, cell_index)
364
+ vt, v = read_cell_date_or_time(row, cell_index)
365
+ else
366
+ vt, v = read_cell(row, cell_index)
367
+ end
368
+ formula = tr = nil #TODO:???
369
+ col_index = cell_index + 1
370
+ font = row.format(cell_index).font
371
+ font.extend(ExcelFontExtensions)
372
+ set_cell_values(sheet,row_index,col_index,0,v,vt,formula,tr,font)
373
+ end #row
374
+ row_index += 1
375
+ end # worksheet
376
+ @cells_read[sheet] = true
377
+ end
378
+
379
+ # Test the cell to see if it's a valid date/time.
380
+ def date_or_time?(row, idx)
381
+ format = row.format(idx)
382
+ if format.date_or_time?
383
+ cell = row.at(idx)
384
+ cell.to_s.to_f > 0 ? true : false # cell value must be numeric
385
+ else
386
+ false
387
+ end
388
+ end
389
+ private :date_or_time?
390
+
391
+ # Read the date-time cell and convert to,
392
+ # the date-time values for Roo
393
+ def read_cell_date_or_time(row, idx)
394
+ cell = row.at(idx).to_s.to_f
395
+ if cell < 1.0
396
+ value_type = :time
397
+ f = cell*24.0*60.0*60.0
398
+ secs = f.round
399
+ h = (secs / 3600.0).floor
400
+ secs = secs - 3600*h
401
+ m = (secs / 60.0).floor
402
+ secs = secs - 60*m
403
+ s = secs
404
+ value = h*3600+m*60+s
405
+ else
406
+ datetime = row.datetime(idx)
407
+ if datetime.hour != 0 or
408
+ datetime.min != 0 or
409
+ datetime.sec != 0
410
+ value_type = :datetime
411
+ value = datetime
412
+ else
413
+ value_type = :date
414
+ value = row.date(idx)
415
+ value = sprintf("%04d-%02d-%02d",value.year,value.month,value.day)
416
+ end
417
+ end
418
+ return value_type, value
419
+ end
420
+ private :read_cell_date_or_time
421
+
422
+ # Read the cell and based on the class,
423
+ # return the values for Roo
424
+ def read_cell(row, idx)
425
+ cell = row.at(idx)
426
+ case cell
427
+ when Float, Integer, Fixnum, Bignum
428
+ value_type = :float
429
+ value = cell.to_f
430
+ when String, TrueClass, FalseClass
431
+ value_type = :string
432
+ value = cell.to_s
433
+ else
434
+ value_type = cell.class.to_s.downcase.to_sym
435
+ value = nil
436
+ end # case
437
+ return value_type, value
438
+ end
439
+ private :read_cell
440
+
441
+ #TODO: testing only
442
+ # def inject_null_characters(str)
443
+ # if str.class != String
444
+ # return str
445
+ # end
446
+ # new_str=''
447
+ # 0.upto(str.size-1) do |i|
448
+ # new_str += str[i,1]
449
+ # new_str += "\000"
450
+ # end
451
+ # new_str
452
+ # end
453
+ #
454
+
455
+ end