roo 1.2.0 → 1.2.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.
- data/History.txt +3 -0
- data/Manifest.txt +2 -0
- data/lib/roo/excel.rb +89 -102
- data/lib/roo/excelx.rb +14 -18
- data/lib/roo/generic_spreadsheet.rb +29 -7
- data/lib/roo/google.rb +2 -0
- data/lib/roo/openoffice.rb +33 -16
- data/lib/roo/version.rb +1 -1
- data/test/datetime.ods +0 -0
- data/test/datetime.xls +0 -0
- data/test/test_helper.rb +1 -1
- data/test/test_roo.rb +754 -227
- data/website/index.html +29 -10
- data/website/index.txt +7 -1
- metadata +6 -4
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
data/lib/roo/excel.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
gem 'parseexcel', '>= 0.5.2'
|
3
3
|
require 'parseexcel'
|
4
|
-
CHARGUESS=false
|
4
|
+
CHARGUESS = false
|
5
5
|
require 'charguess' if CHARGUESS
|
6
6
|
|
7
7
|
module Spreadsheet # :nodoc
|
@@ -29,6 +29,7 @@ class Excel < GenericSpreadsheet
|
|
29
29
|
FileUtils::mkdir(@tmpdir)
|
30
30
|
end
|
31
31
|
filename = open_from_uri(filename) if filename[0,7] == "http://"
|
32
|
+
filename = open_from_stream(filename[7..-1]) if filename[0,7] == "stream:"
|
32
33
|
filename = unzip(filename) if packed and packed == :zip
|
33
34
|
begin
|
34
35
|
file_type_check(filename,'.xls','an Excel')
|
@@ -61,7 +62,8 @@ class Excel < GenericSpreadsheet
|
|
61
62
|
# returns an array of sheet names in the spreadsheet
|
62
63
|
def sheets
|
63
64
|
result = []
|
64
|
-
0.upto(@workbook.
|
65
|
+
#0.upto(@workbook.worksheets.size - 1) do |i| # spreadsheet
|
66
|
+
0.upto(@workbook.sheet_count - 1) do |i| # parseexcel
|
65
67
|
# TODO: is there a better way to do conversion?
|
66
68
|
if CHARGUESS
|
67
69
|
encoding = CharGuess::guess(@workbook.worksheet(i).name)
|
@@ -81,13 +83,15 @@ class Excel < GenericSpreadsheet
|
|
81
83
|
# returns the content of a cell. The upper left corner is (1,1) or ('A',1)
|
82
84
|
def cell(row,col,sheet=nil)
|
83
85
|
sheet = @default_sheet unless sheet
|
86
|
+
raise ArgumentError unless sheet
|
84
87
|
read_cells(sheet) unless @cells_read[sheet]
|
88
|
+
raise "should be read" unless @cells_read[sheet]
|
85
89
|
row,col = normalize(row,col)
|
86
90
|
if celltype(row,col,sheet) == :date
|
87
|
-
yyyy,mm,dd = @cell[sheet][
|
91
|
+
yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
|
88
92
|
return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
|
89
93
|
end
|
90
|
-
return @cell[sheet][
|
94
|
+
return @cell[sheet][[row,col]]
|
91
95
|
end
|
92
96
|
|
93
97
|
# returns the type of a cell:
|
@@ -97,14 +101,20 @@ class Excel < GenericSpreadsheet
|
|
97
101
|
# * :percentage
|
98
102
|
# * :formula
|
99
103
|
# * :time
|
104
|
+
# * :datetime
|
100
105
|
def celltype(row,col,sheet=nil)
|
101
106
|
sheet = @default_sheet unless sheet
|
102
107
|
read_cells(sheet) unless @cells_read[sheet]
|
103
108
|
row,col = normalize(row,col)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
109
|
+
begin
|
110
|
+
if @formula[sheet][[row,col]]
|
111
|
+
return :formula
|
112
|
+
else
|
113
|
+
@cell_type[sheet][[row,col]]
|
114
|
+
end
|
115
|
+
rescue
|
116
|
+
puts "Error in sheet #{sheet}, row #{row}, col #{col}"
|
117
|
+
raise
|
108
118
|
end
|
109
119
|
end
|
110
120
|
|
@@ -155,86 +165,45 @@ class Excel < GenericSpreadsheet
|
|
155
165
|
raise EXCEL_NO_FORMULAS
|
156
166
|
end
|
157
167
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
def get_firsts_lasts_parseexcel(sheet=nil)
|
168
|
+
# shows the internal representation of all cells
|
169
|
+
# mainly for debugging purposes
|
170
|
+
def to_s(sheet=nil)
|
162
171
|
sheet = @default_sheet unless sheet
|
163
|
-
|
164
|
-
|
165
|
-
worksheet = @workbook.worksheet(sheet_no(sheet))
|
166
|
-
unless worksheet.min_row
|
167
|
-
fr = nil
|
168
|
-
else
|
169
|
-
fr = worksheet.min_row + 1
|
170
|
-
end
|
171
|
-
unless worksheet.max_row
|
172
|
-
lr = nil
|
173
|
-
else
|
174
|
-
lr = worksheet.max_row + 1
|
175
|
-
end
|
176
|
-
unless worksheet.min_col
|
177
|
-
fc = nil
|
178
|
-
else
|
179
|
-
fc = worksheet.min_col + 1
|
180
|
-
end
|
181
|
-
unless worksheet.max_col
|
182
|
-
lc = nil
|
183
|
-
else
|
184
|
-
lc = worksheet.max_col + 1
|
185
|
-
end
|
186
|
-
if lr
|
187
|
-
# 2007-11-05 BEGIN
|
188
|
-
# parsexcel liefert (mir unverstaendlich) eine Zeile als letzte Zeile
|
189
|
-
# zurueck, die aber leer ist. Deshalb Korrekturfunktion, die wirklich
|
190
|
-
# die letzte nicht leere Zeile liefert.
|
191
|
-
# 2008-07-23 meine Loesung funtionierte auch noch nicht unter allen
|
192
|
-
# Umstaenden row() == nil ergaenzt
|
193
|
-
while row(lr,sheet) == nil || empty_row?(row(lr,sheet))
|
194
|
-
lr -= 1
|
195
|
-
end
|
196
|
-
end
|
197
|
-
# 2007-11-05 END
|
198
|
-
|
199
|
-
if lc
|
200
|
-
letzte_spalte_leer = true
|
201
|
-
until ! letzte_spalte_leer
|
202
|
-
worksheet.each(0) {|reihe|
|
203
|
-
if reihe
|
204
|
-
cell = reihe.at(lc-1)
|
205
|
-
if cell
|
206
|
-
case cell.type
|
207
|
-
when :numeric, :date
|
208
|
-
letzte_spalte_leer = false
|
209
|
-
when :text
|
210
|
-
letzte_spalte_leer = false if cell.to_s != ""
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
}
|
215
|
-
lc -= 1 if letzte_spalte_leer
|
216
|
-
#puts "letzte Spalte auf #{lc} verringert" if letzte_spalte_leer
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
return fr, lr, fc, lc
|
172
|
+
read_cells(sheet) unless @cells_read[sheet]
|
173
|
+
@cell[sheet].inspect
|
221
174
|
end
|
222
175
|
|
176
|
+
private
|
223
177
|
# determine the first and last boundaries
|
224
178
|
def get_firsts_lasts(sheet=nil)
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
179
|
+
|
180
|
+
# 2008-09-14 BEGINf
|
181
|
+
fr=lr=fc=lc=nil
|
182
|
+
sheet = @default_sheet unless sheet
|
183
|
+
if ! @cells_read[sheet]
|
184
|
+
read_cells(sheet)
|
185
|
+
end
|
186
|
+
if @cell[sheet] # nur wenn ueberhaupt Zellen belegt sind
|
187
|
+
@cell[sheet].each {|cellitem|
|
188
|
+
key = cellitem.first
|
189
|
+
y,x = key
|
190
|
+
|
191
|
+
if cellitem[1].class != String or
|
192
|
+
(cellitem[1].class == String and cellitem[1] != "")
|
193
|
+
fr = y unless fr
|
194
|
+
fr = y if y < fr
|
195
|
+
|
196
|
+
lr = y unless lr
|
197
|
+
lr = y if y > lr
|
198
|
+
|
199
|
+
fc = x unless fc
|
200
|
+
fc = x if x < fc
|
201
|
+
|
202
|
+
lc = x unless lc
|
203
|
+
lc = x if x > lc
|
204
|
+
end
|
205
|
+
}
|
236
206
|
end
|
237
|
-
# 2007-11-05 END
|
238
207
|
@first_row[sheet] = fr
|
239
208
|
@last_row[sheet] = lr
|
240
209
|
@first_column[sheet] = fc
|
@@ -246,6 +215,7 @@ class Excel < GenericSpreadsheet
|
|
246
215
|
def sheet_no(name)
|
247
216
|
return name-1 if name.kind_of?(Fixnum)
|
248
217
|
0.upto(@workbook.sheet_count - 1) do |i|
|
218
|
+
#0.upto(@workbook.worksheets.size - 1) do |i|
|
249
219
|
# TODO: is there a better way to do conversion?
|
250
220
|
return i if name == platform_specific_iconv(
|
251
221
|
@workbook.worksheet(i).name)
|
@@ -317,19 +287,22 @@ class Excel < GenericSpreadsheet
|
|
317
287
|
|
318
288
|
# helper function to set the internal representation of cells
|
319
289
|
def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v)
|
320
|
-
key = "#{y},#{x+i}"
|
290
|
+
#key = "#{y},#{x+i}"
|
291
|
+
key = [y,x+i]
|
321
292
|
@cell_type[sheet] = {} unless @cell_type[sheet]
|
322
293
|
@cell_type[sheet][key] = vt
|
323
294
|
@formula[sheet] = {} unless @formula[sheet]
|
324
295
|
@formula[sheet][key] = formula if formula
|
325
296
|
@cell[sheet] = {} unless @cell[sheet]
|
326
|
-
case @cell_type[sheet][key]
|
297
|
+
case vt # @cell_type[sheet][key]
|
327
298
|
when :float
|
328
299
|
@cell[sheet][key] = v.to_f
|
329
300
|
when :string
|
330
301
|
@cell[sheet][key] = str_v
|
331
302
|
when :date
|
332
303
|
@cell[sheet][key] = v
|
304
|
+
when :datetime
|
305
|
+
@cell[sheet][key] = DateTime.new(v.year,v.month,v.day,v.hour,v.min,v.sec)
|
333
306
|
when :percentage
|
334
307
|
@cell[sheet][key] = v.to_f
|
335
308
|
when :time
|
@@ -344,6 +317,11 @@ class Excel < GenericSpreadsheet
|
|
344
317
|
sheet = @default_sheet unless sheet
|
345
318
|
raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
|
346
319
|
raise RangeError unless self.sheets.include? sheet
|
320
|
+
|
321
|
+
if @cells_read[sheet]
|
322
|
+
raise "sheet #{sheet} already read"
|
323
|
+
end
|
324
|
+
|
347
325
|
worksheet = @workbook.worksheet(sheet_no(sheet))
|
348
326
|
skip = 0
|
349
327
|
x =1
|
@@ -352,7 +330,7 @@ class Excel < GenericSpreadsheet
|
|
352
330
|
worksheet.each(skip) { |row_par|
|
353
331
|
if row_par
|
354
332
|
x =1
|
355
|
-
row_par.each do # |void|
|
333
|
+
row_par.each do # |void|
|
356
334
|
cell = row_par.at(x-1)
|
357
335
|
if cell
|
358
336
|
case cell.type
|
@@ -374,17 +352,26 @@ class Excel < GenericSpreadsheet
|
|
374
352
|
s = secs
|
375
353
|
v = h*3600+m*60+s
|
376
354
|
else
|
377
|
-
|
378
|
-
|
379
|
-
|
355
|
+
if cell.datetime.hour != 0 or
|
356
|
+
cell.datetime.min != 0 or
|
357
|
+
cell.datetime.sec != 0 or
|
358
|
+
cell.datetime.msec != 0
|
359
|
+
vt = :datetime
|
360
|
+
v = cell.datetime
|
361
|
+
else
|
362
|
+
vt = :date
|
363
|
+
v = cell.date
|
364
|
+
v = sprintf("%04d-%02d-%02d",v.year,v.month,v.day)
|
365
|
+
end
|
380
366
|
end
|
381
367
|
else
|
382
|
-
vt = cell.type.to_sym
|
368
|
+
vt = cell.type.to_s.downcase.to_sym
|
383
369
|
v = nil
|
384
370
|
end # case
|
385
371
|
formula = tr = nil #TODO:???
|
386
372
|
set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v)
|
387
373
|
end # if cell
|
374
|
+
|
388
375
|
x += 1
|
389
376
|
end
|
390
377
|
end
|
@@ -393,18 +380,18 @@ class Excel < GenericSpreadsheet
|
|
393
380
|
@cells_read[sheet] = true
|
394
381
|
end
|
395
382
|
|
396
|
-
|
397
|
-
# def inject_null_characters(str)
|
398
|
-
# if str.class != String
|
399
|
-
# return str
|
400
|
-
# end
|
401
|
-
# new_str=''
|
402
|
-
# 0.upto(str.size-1) do |i|
|
403
|
-
# new_str += str[i,1]
|
404
|
-
# new_str += "\000"
|
405
|
-
# end
|
406
|
-
# new_str
|
407
|
-
# end
|
408
|
-
#
|
383
|
+
#TODO: testing only
|
384
|
+
# def inject_null_characters(str)
|
385
|
+
# if str.class != String
|
386
|
+
# return str
|
387
|
+
# end
|
388
|
+
# new_str=''
|
389
|
+
# 0.upto(str.size-1) do |i|
|
390
|
+
# new_str += str[i,1]
|
391
|
+
# new_str += "\000"
|
392
|
+
# end
|
393
|
+
# new_str
|
394
|
+
# end
|
395
|
+
#
|
409
396
|
|
410
397
|
end
|
data/lib/roo/excelx.rb
CHANGED
@@ -4,7 +4,6 @@ require 'rexml/document'
|
|
4
4
|
require 'fileutils'
|
5
5
|
require 'zip/zipfilesystem'
|
6
6
|
require 'date'
|
7
|
-
#require 'base64'
|
8
7
|
|
9
8
|
class String
|
10
9
|
def end_with?(str)
|
@@ -156,10 +155,10 @@ class Excelx < GenericSpreadsheet
|
|
156
155
|
read_cells(sheet) unless @cells_read[sheet]
|
157
156
|
row,col = normalize(row,col)
|
158
157
|
if celltype(row,col,sheet) == :date
|
159
|
-
yyyy,mm,dd = @cell[sheet][
|
158
|
+
yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
|
160
159
|
return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
|
161
160
|
end
|
162
|
-
@cell[sheet][
|
161
|
+
@cell[sheet][[row,col]]
|
163
162
|
end
|
164
163
|
|
165
164
|
# Returns the formula at (row,col).
|
@@ -169,10 +168,10 @@ class Excelx < GenericSpreadsheet
|
|
169
168
|
sheet = @default_sheet unless sheet
|
170
169
|
read_cells(sheet) unless @cells_read[sheet]
|
171
170
|
row,col = normalize(row,col)
|
172
|
-
if @formula[sheet][
|
171
|
+
if @formula[sheet][[row,col]] == nil
|
173
172
|
return nil
|
174
173
|
else
|
175
|
-
return @formula[sheet][
|
174
|
+
return @formula[sheet][[row,col]]
|
176
175
|
end
|
177
176
|
end
|
178
177
|
|
@@ -209,15 +208,15 @@ class Excelx < GenericSpreadsheet
|
|
209
208
|
# * :percentage
|
210
209
|
# * :formula
|
211
210
|
# * :time
|
212
|
-
|
211
|
+
# * :datetime
|
212
|
+
def celltype(row,col,sheet=nil)
|
213
213
|
sheet = @default_sheet unless sheet
|
214
214
|
read_cells(sheet) unless @cells_read[sheet]
|
215
215
|
row,col = normalize(row,col)
|
216
|
-
|
217
|
-
if @formula[sheet]["#{row},#{col}"]
|
216
|
+
if @formula[sheet][[row,col]]
|
218
217
|
return :formula
|
219
218
|
else
|
220
|
-
@cell_type[sheet][
|
219
|
+
@cell_type[sheet][[row,col]]
|
221
220
|
end
|
222
221
|
end
|
223
222
|
|
@@ -229,7 +228,7 @@ class Excelx < GenericSpreadsheet
|
|
229
228
|
sheet = @default_sheet unless sheet
|
230
229
|
read_cells(sheet) unless @cells_read[sheet]
|
231
230
|
row,col = normalize(row,col)
|
232
|
-
return @excelx_type[sheet][
|
231
|
+
return @excelx_type[sheet][[row,col]]
|
233
232
|
end
|
234
233
|
|
235
234
|
# returns the internal value of an excelx cell
|
@@ -238,7 +237,7 @@ class Excelx < GenericSpreadsheet
|
|
238
237
|
sheet = @default_sheet unless sheet
|
239
238
|
read_cells(sheet) unless @cells_read[sheet]
|
240
239
|
row,col = normalize(row,col)
|
241
|
-
return @excelx_value[sheet][
|
240
|
+
return @excelx_value[sheet][[row,col]]
|
242
241
|
end
|
243
242
|
|
244
243
|
# returns the internal format of an excel cell
|
@@ -246,7 +245,7 @@ class Excelx < GenericSpreadsheet
|
|
246
245
|
sheet = @default_sheet unless sheet
|
247
246
|
read_cells(sheet) unless @cells_read[sheet]
|
248
247
|
row,col = normalize(row,col)
|
249
|
-
s = @s_attribute[sheet][
|
248
|
+
s = @s_attribute[sheet][[row,col]]
|
250
249
|
result = attribute2format(s)
|
251
250
|
result
|
252
251
|
end
|
@@ -298,7 +297,7 @@ class Excelx < GenericSpreadsheet
|
|
298
297
|
excelx_type=nil,
|
299
298
|
excelx_value=nil,
|
300
299
|
s_attribute=nil)
|
301
|
-
key =
|
300
|
+
key = [y,x+i]
|
302
301
|
@cell_type[sheet] = {} unless @cell_type[sheet]
|
303
302
|
@cell_type[sheet][key] = vt
|
304
303
|
@formula[sheet] = {} unless @formula[sheet]
|
@@ -314,8 +313,6 @@ class Excelx < GenericSpreadsheet
|
|
314
313
|
when :percentage
|
315
314
|
@cell[sheet][key] = v.to_f
|
316
315
|
when :time
|
317
|
-
#hms = v.split(':')
|
318
|
-
#@cell[sheet][key] = hms[0].to_i*3600 + hms[1].to_i*60 + hms[2].to_i
|
319
316
|
@cell[sheet][key] = v.to_f*(24*60*60)
|
320
317
|
else
|
321
318
|
@cell[sheet][key] = v
|
@@ -497,13 +494,13 @@ class Excelx < GenericSpreadsheet
|
|
497
494
|
# sets the value of a cell
|
498
495
|
def set_value(row,col,value,sheet=nil)
|
499
496
|
sheet = @default_value unless sheet
|
500
|
-
@cell[sheet][
|
497
|
+
@cell[sheet][[row,col]] = value
|
501
498
|
end
|
502
499
|
|
503
500
|
# sets the type of a cell
|
504
501
|
def set_type(row,col,type,sheet=nil)
|
505
502
|
sheet = @default_value unless sheet
|
506
|
-
@cell_type[sheet][
|
503
|
+
@cell_type[sheet][[row,col]] = type
|
507
504
|
end
|
508
505
|
|
509
506
|
# read the shared strings xml document
|
@@ -542,7 +539,6 @@ class Excelx < GenericSpreadsheet
|
|
542
539
|
e2.each_element do |e3|
|
543
540
|
if e3.name == 'xf'
|
544
541
|
numFmtId = e3.attributes['numFmtId']
|
545
|
-
# p numFmtId
|
546
542
|
@cellXfs << [numFmtId]
|
547
543
|
end
|
548
544
|
end
|
@@ -53,7 +53,7 @@ class GenericSpreadsheet
|
|
53
53
|
impossible_value = 999_999 # more than a spreadsheet can hold
|
54
54
|
result = impossible_value
|
55
55
|
@cell[sheet].each_pair {|key,value|
|
56
|
-
y,x = key.split(',')
|
56
|
+
y,x = key # _to_string(key).split(',')
|
57
57
|
y = y.to_i
|
58
58
|
result = [result, y].min if value
|
59
59
|
} if @cell[sheet]
|
@@ -72,7 +72,7 @@ class GenericSpreadsheet
|
|
72
72
|
impossible_value = 0
|
73
73
|
result = impossible_value
|
74
74
|
@cell[sheet].each_pair {|key,value|
|
75
|
-
y,x = key.split(',')
|
75
|
+
y,x = key # _to_string(key).split(',')
|
76
76
|
y = y.to_i
|
77
77
|
result = [result, y].max if value
|
78
78
|
} if @cell[sheet]
|
@@ -93,8 +93,8 @@ class GenericSpreadsheet
|
|
93
93
|
impossible_value = 999_999 # more than a spreadsheet can hold
|
94
94
|
result = impossible_value
|
95
95
|
@cell[sheet].each_pair {|key,value|
|
96
|
-
y,x = key.split(',')
|
97
|
-
x = x.to_i
|
96
|
+
y,x = key # _to_string(key).split(',')
|
97
|
+
x = x # .to_i
|
98
98
|
result = [result, x].min if value
|
99
99
|
} if @cell[sheet]
|
100
100
|
result = nil if result == impossible_value
|
@@ -112,7 +112,7 @@ class GenericSpreadsheet
|
|
112
112
|
impossible_value = 0
|
113
113
|
result = impossible_value
|
114
114
|
@cell[sheet].each_pair {|key,value|
|
115
|
-
y,x = key.split(',')
|
115
|
+
y,x = key # _to_string(key).split(',')
|
116
116
|
x = x.to_i
|
117
117
|
result = [result, x].max if value
|
118
118
|
} if @cell[sheet]
|
@@ -227,7 +227,6 @@ class GenericSpreadsheet
|
|
227
227
|
found *= 0
|
228
228
|
end
|
229
229
|
}
|
230
|
-
# p self.row(i) if found > 0
|
231
230
|
if found > 0
|
232
231
|
tmp = {}
|
233
232
|
1.upto(self.row(i).size) {|j|
|
@@ -261,7 +260,7 @@ class GenericSpreadsheet
|
|
261
260
|
result = []
|
262
261
|
tmp_arr = []
|
263
262
|
@cell[sheet].each_pair {|key,value|
|
264
|
-
y,x = key.split(',')
|
263
|
+
y,x = key # _to_string(key).split(',')
|
265
264
|
x = x.to_i
|
266
265
|
y = y.to_i
|
267
266
|
if y == rownumber
|
@@ -400,6 +399,21 @@ class GenericSpreadsheet
|
|
400
399
|
end
|
401
400
|
end
|
402
401
|
|
402
|
+
# konvertiert einen Key in der Form "12,45" (=row,column) in
|
403
|
+
# ein Array mit numerischen Werten ([12,45])
|
404
|
+
# Diese Methode ist eine temp. Loesung, um zu erforschen, ob der
|
405
|
+
# Zugriff mit numerischen Keys schneller ist.
|
406
|
+
def key_to_num(str)
|
407
|
+
r,c = str.split(',')
|
408
|
+
r = r.to_i
|
409
|
+
c = c.to_i
|
410
|
+
[r,c]
|
411
|
+
end
|
412
|
+
|
413
|
+
# siehe: key_to_num
|
414
|
+
def key_to_string(arr)
|
415
|
+
"#{arr[0]},#{arr[1]}"
|
416
|
+
end
|
403
417
|
|
404
418
|
private
|
405
419
|
|
@@ -435,6 +449,14 @@ class GenericSpreadsheet
|
|
435
449
|
File.join(@tmpdir, File.basename(uri))
|
436
450
|
end
|
437
451
|
|
452
|
+
def open_from_stream(stream)
|
453
|
+
tempfilename = File.join(@tmpdir, "spreadsheet")
|
454
|
+
f = File.open(tempfilename,"wb")
|
455
|
+
f.write(stream[7..-1])
|
456
|
+
f.close
|
457
|
+
File.join(@tmpdir, "spreadsheet")
|
458
|
+
end
|
459
|
+
|
438
460
|
# convert a number to something like 'AB' (1 => 'A', 2 => 'B', ...)
|
439
461
|
def self.number_to_letter(n)
|
440
462
|
letters=""
|
data/lib/roo/google.rb
CHANGED
@@ -162,6 +162,7 @@ class Google < GenericSpreadsheet
|
|
162
162
|
# * :percentage
|
163
163
|
# * :formula
|
164
164
|
# * :time
|
165
|
+
# * :datetime
|
165
166
|
def celltype(row, col, sheet=nil)
|
166
167
|
sheet = @default_sheet unless sheet
|
167
168
|
read_cells(sheet) unless @cells_read[sheet]
|
@@ -321,6 +322,7 @@ class Google < GenericSpreadsheet
|
|
321
322
|
# read all cells in a sheet
|
322
323
|
def read_cells(sheet=nil)
|
323
324
|
sheet = @default_sheet unless sheet
|
325
|
+
raise RangeError, "illegal sheet <#{sheet}>" unless sheets.index(sheet)
|
324
326
|
sheet_no = sheets.index(sheet)+1
|
325
327
|
doc = @gs.fulldoc(sheet_no)
|
326
328
|
(doc/"gs:cell").each {|item|
|
data/lib/roo/openoffice.rb
CHANGED
@@ -80,10 +80,10 @@ class Openoffice < GenericSpreadsheet
|
|
80
80
|
read_cells(sheet) unless @cells_read[sheet]
|
81
81
|
row,col = normalize(row,col)
|
82
82
|
if celltype(row,col,sheet) == :date
|
83
|
-
yyyy,mm,dd = @cell[sheet][
|
83
|
+
yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
|
84
84
|
return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
|
85
85
|
end
|
86
|
-
@cell[sheet][
|
86
|
+
@cell[sheet][[row,col]]
|
87
87
|
end
|
88
88
|
|
89
89
|
# Returns the formula at (row,col).
|
@@ -93,10 +93,10 @@ class Openoffice < GenericSpreadsheet
|
|
93
93
|
sheet = @default_sheet unless sheet
|
94
94
|
read_cells(sheet) unless @cells_read[sheet]
|
95
95
|
row,col = normalize(row,col)
|
96
|
-
if @formula[sheet][
|
96
|
+
if @formula[sheet][[row,col]] == nil
|
97
97
|
return nil
|
98
98
|
else
|
99
|
-
return @formula[sheet][
|
99
|
+
return @formula[sheet][[row,col]]["oooc:".length..-1]
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -133,14 +133,15 @@ class Openoffice < GenericSpreadsheet
|
|
133
133
|
# * :percentage
|
134
134
|
# * :formula
|
135
135
|
# * :time
|
136
|
+
# * :datetime
|
136
137
|
def celltype(row,col,sheet=nil)
|
137
138
|
sheet = @default_sheet unless sheet
|
138
139
|
read_cells(sheet) unless @cells_read[sheet]
|
139
140
|
row,col = normalize(row,col)
|
140
|
-
if @formula[sheet][
|
141
|
+
if @formula[sheet][[row,col]]
|
141
142
|
return :formula
|
142
143
|
else
|
143
|
-
@cell_type[sheet][
|
144
|
+
@cell_type[sheet][[row,col]]
|
144
145
|
end
|
145
146
|
end
|
146
147
|
|
@@ -172,7 +173,6 @@ class Openoffice < GenericSpreadsheet
|
|
172
173
|
# version of the openoffice document
|
173
174
|
# at 2007 this is always "1.0"
|
174
175
|
def officeversion
|
175
|
-
# read_cells(false) unless @cells_read
|
176
176
|
oo_version
|
177
177
|
@officeversion
|
178
178
|
end
|
@@ -211,7 +211,6 @@ class Openoffice < GenericSpreadsheet
|
|
211
211
|
|
212
212
|
# read the version of the OO-Version
|
213
213
|
def oo_version
|
214
|
-
#sheet_found = false
|
215
214
|
@doc.each_element do |oo_document|
|
216
215
|
@officeversion = oo_document.attributes['version']
|
217
216
|
end
|
@@ -219,7 +218,7 @@ class Openoffice < GenericSpreadsheet
|
|
219
218
|
|
220
219
|
# helper function to set the internal representation of cells
|
221
220
|
def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v)
|
222
|
-
key =
|
221
|
+
key = [y,x+i]
|
223
222
|
@cell_type[sheet] = {} unless @cell_type[sheet]
|
224
223
|
@cell_type[sheet][key] = Openoffice.oo_type_2_roo_type(vt)
|
225
224
|
@formula[sheet] = {} unless @formula[sheet]
|
@@ -231,7 +230,14 @@ class Openoffice < GenericSpreadsheet
|
|
231
230
|
when :string
|
232
231
|
@cell[sheet][key] = str_v
|
233
232
|
when :date
|
234
|
-
|
233
|
+
if tr.attributes['date-value'].size != "XXXX-XX-XX".size
|
234
|
+
#-- dann ist noch eine Uhrzeit vorhanden
|
235
|
+
#-- "1961-11-21T12:17:18"
|
236
|
+
@cell[sheet][key] = DateTime.parse(tr.attributes['date-value'])
|
237
|
+
@cell_type[sheet][key] = :datetime
|
238
|
+
else
|
239
|
+
@cell[sheet][key] = tr.attributes['date-value']
|
240
|
+
end
|
235
241
|
when :percentage
|
236
242
|
@cell[sheet][key] = v.to_f
|
237
243
|
when :time
|
@@ -264,7 +270,7 @@ class Openoffice < GenericSpreadsheet
|
|
264
270
|
if be.name == "spreadsheet"
|
265
271
|
be.each_element do |se|
|
266
272
|
if se.name == "table"
|
267
|
-
if se.attributes['name']==sheet
|
273
|
+
if se.attributes['name']==sheet
|
268
274
|
sheet_found = true
|
269
275
|
x=1
|
270
276
|
y=1
|
@@ -303,13 +309,24 @@ class Openoffice < GenericSpreadsheet
|
|
303
309
|
str_v.gsub!(/'/,"'")
|
304
310
|
end # == 'p'
|
305
311
|
end
|
306
|
-
|
307
|
-
if vt == 'time'
|
312
|
+
elsif vt == 'time'
|
308
313
|
tr.each_element do |str|
|
309
314
|
if str.name == 'p'
|
310
315
|
v = str.text
|
311
316
|
end
|
312
317
|
end
|
318
|
+
elsif vt == '' or vt == nil
|
319
|
+
#
|
320
|
+
elsif vt == 'date'
|
321
|
+
#
|
322
|
+
elsif vt == 'percentage'
|
323
|
+
#
|
324
|
+
elsif vt == 'float'
|
325
|
+
#
|
326
|
+
elsif vt == 'boolean'
|
327
|
+
#
|
328
|
+
else
|
329
|
+
# raise "unknown type #{vt}"
|
313
330
|
end
|
314
331
|
if skip
|
315
332
|
if v != nil or tr.attributes['date-value']
|
@@ -373,7 +390,7 @@ class Openoffice < GenericSpreadsheet
|
|
373
390
|
def process_zipfile(zip, path='')
|
374
391
|
if zip.file.file? path
|
375
392
|
if path == "content.xml"
|
376
|
-
open(@tmpdir
|
393
|
+
open(File.join(@tmpdir, @file_nr.to_s+'_roo_content.xml'),'wb') {|f|
|
377
394
|
f << zip.read(path)
|
378
395
|
}
|
379
396
|
end
|
@@ -395,12 +412,12 @@ class Openoffice < GenericSpreadsheet
|
|
395
412
|
|
396
413
|
def set_value(row,col,value,sheet=nil)
|
397
414
|
sheet = @default_value unless sheet
|
398
|
-
@cell[sheet][
|
415
|
+
@cell[sheet][[row,col]] = value
|
399
416
|
end
|
400
417
|
|
401
418
|
def set_type(row,col,type,sheet=nil)
|
402
419
|
sheet = @default_value unless sheet
|
403
|
-
@cell_type[sheet][
|
420
|
+
@cell_type[sheet][[row,col]] = type
|
404
421
|
end
|
405
422
|
|
406
423
|
A_ROO_TYPE = {
|