hmcgowan-roo 1.3.5 → 1.3.6
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/README.markdown +8 -2
- data/lib/roo/excel.rb +45 -80
- data/lib/roo/excelx.rb +1 -5
- data/lib/roo/generic_spreadsheet.rb +2 -12
- data/lib/roo/google.rb +1 -43
- data/lib/roo/openoffice.rb +1 -5
- data/lib/roo/version.rb +1 -1
- data/lib/roo.rb +18 -0
- data/test/1900_base.xls +0 -0
- data/test/1904_base.xls +0 -0
- data/test/skipped_tests.rb +789 -0
- data/test/test_roo.rb +572 -3789
- data/test/whitespace.ods +0 -0
- data/test/whitespace.xls +0 -0
- data/test/whitespace.xlsx +0 -0
- metadata +8 -3
- data/test/numbers1_excel.csv +0 -18
data/README.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# README for Roo
|
2
2
|
|
3
|
-
|
3
|
+
1.3.5 is now available on Rubyforge. You can install the official release with 'gem install roo' or refer to the installation instructions below for the latest development gem.
|
4
4
|
|
5
5
|
|
6
6
|
## Installation
|
@@ -35,7 +35,7 @@ This is now the official roo repository and I'll be making a release on RubyForg
|
|
35
35
|
s.cell(1,'A',s.sheets[0]) # same cell
|
36
36
|
|
37
37
|
# almost all methods have an optional argument 'sheet'.
|
38
|
-
# If this parameter is
|
38
|
+
# If this parameter is omitted, the default_sheet will be used.
|
39
39
|
|
40
40
|
s.info # prints infos about the spreadsheet file
|
41
41
|
|
@@ -44,6 +44,12 @@ This is now the official roo repository and I'll be making a release on RubyForg
|
|
44
44
|
s.first_column # the number of the first column
|
45
45
|
s.last_column # the number of the last column
|
46
46
|
|
47
|
+
# limited font information is available
|
48
|
+
|
49
|
+
s.font(1,1).bold?
|
50
|
+
s.font(1,1).italic?
|
51
|
+
s.font(1,1).underline?
|
52
|
+
|
47
53
|
|
48
54
|
see http://roo.rubyforge.org for a more complete tutorial
|
49
55
|
|
data/lib/roo/excel.rb
CHANGED
@@ -6,6 +6,26 @@ rescue LoadError => e
|
|
6
6
|
false
|
7
7
|
end
|
8
8
|
|
9
|
+
# The Spreadsheet library has a bug in handling Excel
|
10
|
+
# base dates so if the file is a 1904 base date then
|
11
|
+
# dates are off by a day. 1900 base dates work fine
|
12
|
+
module Spreadsheet
|
13
|
+
module Excel
|
14
|
+
class Row < Spreadsheet::Row
|
15
|
+
def _date data # :nodoc:
|
16
|
+
return data if data.is_a?(Date)
|
17
|
+
date = @worksheet.date_base + data.to_i
|
18
|
+
if LEAP_ERROR > @worksheet.date_base
|
19
|
+
date -= 1
|
20
|
+
end
|
21
|
+
date
|
22
|
+
end
|
23
|
+
public :_datetime
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
9
29
|
# ruby-spreadsheet has a font object so we're extending it
|
10
30
|
# with our own functionality but still providing full access
|
11
31
|
# to the user for other font information
|
@@ -55,11 +75,7 @@ class Excel < GenericSpreadsheet
|
|
55
75
|
raise IOError, "file #{@filename} does not exist"
|
56
76
|
end
|
57
77
|
@workbook = Spreadsheet.open(filename)
|
58
|
-
@default_sheet =
|
59
|
-
# no need to set default_sheet if there is only one sheet in the document
|
60
|
-
if self.sheets.size == 1
|
61
|
-
@default_sheet = self.sheets.first
|
62
|
-
end
|
78
|
+
@default_sheet = self.sheets.first
|
63
79
|
ensure
|
64
80
|
#if ENV["roo_local"] != "thomas-p"
|
65
81
|
FileUtils::rm_r(@tmpdir)
|
@@ -128,38 +144,6 @@ class Excel < GenericSpreadsheet
|
|
128
144
|
end
|
129
145
|
end
|
130
146
|
|
131
|
-
# returns the first non empty column
|
132
|
-
def first_column(sheet=nil)
|
133
|
-
sheet = @default_sheet unless sheet
|
134
|
-
return @first_column[sheet] if @first_column[sheet]
|
135
|
-
fr, lr, fc, lc = get_firsts_lasts(sheet)
|
136
|
-
fc
|
137
|
-
end
|
138
|
-
|
139
|
-
# returns the last non empty column
|
140
|
-
def last_column(sheet=nil)
|
141
|
-
sheet = @default_sheet unless sheet
|
142
|
-
return @last_column[sheet] if @last_column[sheet]
|
143
|
-
fr, lr, fc, lc = get_firsts_lasts(sheet)
|
144
|
-
lc
|
145
|
-
end
|
146
|
-
|
147
|
-
# returns the first non empty row
|
148
|
-
def first_row(sheet=nil)
|
149
|
-
sheet = @default_sheet unless sheet
|
150
|
-
return @first_row[sheet] if @first_row[sheet]
|
151
|
-
fr, lr, fc, lc = get_firsts_lasts(sheet)
|
152
|
-
fr
|
153
|
-
end
|
154
|
-
|
155
|
-
# returns the last non empty row
|
156
|
-
def last_row(sheet=nil)
|
157
|
-
sheet = @default_sheet unless sheet
|
158
|
-
return @last_row[sheet] if @last_row[sheet]
|
159
|
-
fr, lr, fc, lc = get_firsts_lasts(sheet)
|
160
|
-
lr
|
161
|
-
end
|
162
|
-
|
163
147
|
# returns NO formula in excel spreadsheets
|
164
148
|
def formula(row,col,sheet=nil)
|
165
149
|
raise EXCEL_NO_FORMULAS
|
@@ -192,42 +176,6 @@ class Excel < GenericSpreadsheet
|
|
192
176
|
end
|
193
177
|
|
194
178
|
private
|
195
|
-
# determine the first and last boundaries
|
196
|
-
def get_firsts_lasts(sheet=nil)
|
197
|
-
|
198
|
-
# 2008-09-14 BEGINf
|
199
|
-
fr=lr=fc=lc=nil
|
200
|
-
sheet = @default_sheet unless sheet
|
201
|
-
if ! @cells_read[sheet]
|
202
|
-
read_cells(sheet)
|
203
|
-
end
|
204
|
-
if @cell[sheet] # nur wenn ueberhaupt Zellen belegt sind
|
205
|
-
@cell[sheet].each {|cellitem|
|
206
|
-
key = cellitem.first
|
207
|
-
y,x = key
|
208
|
-
|
209
|
-
if cellitem[1].class != String or
|
210
|
-
(cellitem[1].class == String and cellitem[1] != "")
|
211
|
-
fr = y unless fr
|
212
|
-
fr = y if y < fr
|
213
|
-
|
214
|
-
lr = y unless lr
|
215
|
-
lr = y if y > lr
|
216
|
-
|
217
|
-
fc = x unless fc
|
218
|
-
fc = x if x < fc
|
219
|
-
|
220
|
-
lc = x unless lc
|
221
|
-
lc = x if x > lc
|
222
|
-
end
|
223
|
-
}
|
224
|
-
end
|
225
|
-
@first_row[sheet] = fr
|
226
|
-
@last_row[sheet] = lr
|
227
|
-
@first_column[sheet] = fc
|
228
|
-
@last_column[sheet] = lc
|
229
|
-
return fr, lr, fc, lc
|
230
|
-
end
|
231
179
|
|
232
180
|
# converts name of a sheet to index (0,1,2,..)
|
233
181
|
def sheet_no(name)
|
@@ -355,7 +303,7 @@ class Excel < GenericSpreadsheet
|
|
355
303
|
(0..row.size).each do |cell_index|
|
356
304
|
cell = row.at(cell_index)
|
357
305
|
next if cell.nil? #skip empty cells
|
358
|
-
next if cell.class == Spreadsheet::Formula
|
306
|
+
next if cell.class == Spreadsheet::Formula && cell.value.nil? # skip empty formla cells
|
359
307
|
if date_or_time?(row, cell_index)
|
360
308
|
vt, v = read_cell_date_or_time(row, cell_index)
|
361
309
|
else
|
@@ -371,12 +319,20 @@ class Excel < GenericSpreadsheet
|
|
371
319
|
end # worksheet
|
372
320
|
@cells_read[sheet] = true
|
373
321
|
end
|
374
|
-
|
322
|
+
|
323
|
+
# Get the contents of a cell, accounting for the
|
324
|
+
# way formula stores the value
|
325
|
+
def read_cell_content(row, idx)
|
326
|
+
cell = row.at(idx)
|
327
|
+
cell = cell.value if cell.class == Spreadsheet::Formula
|
328
|
+
cell
|
329
|
+
end
|
330
|
+
|
375
331
|
# Test the cell to see if it's a valid date/time.
|
376
332
|
def date_or_time?(row, idx)
|
377
333
|
format = row.format(idx)
|
378
334
|
if format.date_or_time?
|
379
|
-
cell = row
|
335
|
+
cell = read_cell_content(row, idx)
|
380
336
|
true if Float(cell) > 0 rescue false
|
381
337
|
else
|
382
338
|
false
|
@@ -387,7 +343,8 @@ class Excel < GenericSpreadsheet
|
|
387
343
|
# Read the date-time cell and convert to,
|
388
344
|
# the date-time values for Roo
|
389
345
|
def read_cell_date_or_time(row, idx)
|
390
|
-
cell = row
|
346
|
+
cell = read_cell_content(row, idx)
|
347
|
+
cell = cell.to_s.to_f
|
391
348
|
if cell < 1.0
|
392
349
|
value_type = :time
|
393
350
|
f = cell*24.0*60.0*60.0
|
@@ -399,7 +356,11 @@ class Excel < GenericSpreadsheet
|
|
399
356
|
s = secs
|
400
357
|
value = h*3600+m*60+s
|
401
358
|
else
|
402
|
-
|
359
|
+
if row.at(idx).class == Spreadsheet::Formula
|
360
|
+
datetime = row._datetime(cell)
|
361
|
+
else
|
362
|
+
datetime = row.datetime(idx)
|
363
|
+
end
|
403
364
|
if datetime.hour != 0 or
|
404
365
|
datetime.min != 0 or
|
405
366
|
datetime.sec != 0
|
@@ -407,7 +368,11 @@ class Excel < GenericSpreadsheet
|
|
407
368
|
value = datetime
|
408
369
|
else
|
409
370
|
value_type = :date
|
410
|
-
|
371
|
+
if row.at(idx).class == Spreadsheet::Formula
|
372
|
+
value = row._date(cell)
|
373
|
+
else
|
374
|
+
value = row.date(idx)
|
375
|
+
end
|
411
376
|
value = sprintf("%04d-%02d-%02d",value.year,value.month,value.day)
|
412
377
|
end
|
413
378
|
end
|
@@ -418,7 +383,7 @@ class Excel < GenericSpreadsheet
|
|
418
383
|
# Read the cell and based on the class,
|
419
384
|
# return the values for Roo
|
420
385
|
def read_cell(row, idx)
|
421
|
-
cell = row
|
386
|
+
cell = read_cell_content(row, idx)
|
422
387
|
case cell
|
423
388
|
when Float, Integer, Fixnum, Bignum
|
424
389
|
value_type = :float
|
data/lib/roo/excelx.rb
CHANGED
@@ -128,11 +128,7 @@ class Excelx < GenericSpreadsheet
|
|
128
128
|
FileUtils::rm_r(@tmpdir)
|
129
129
|
#end
|
130
130
|
end
|
131
|
-
@default_sheet =
|
132
|
-
# no need to set default_sheet if there is only one sheet in the document
|
133
|
-
if self.sheets.size == 1
|
134
|
-
@default_sheet = self.sheets.first
|
135
|
-
end
|
131
|
+
@default_sheet = self.sheets.first
|
136
132
|
@cell = Hash.new
|
137
133
|
@cell_type = Hash.new
|
138
134
|
@formula = Hash.new
|
@@ -258,18 +258,8 @@ class GenericSpreadsheet
|
|
258
258
|
sheet = @default_sheet unless sheet
|
259
259
|
read_cells(sheet) unless @cells_read[sheet]
|
260
260
|
result = []
|
261
|
-
|
262
|
-
|
263
|
-
y,x = key # _to_string(key).split(',')
|
264
|
-
x = x.to_i
|
265
|
-
y = y.to_i
|
266
|
-
if y == rownumber
|
267
|
-
tmp_arr[x] = value
|
268
|
-
end
|
269
|
-
}
|
270
|
-
result = tmp_arr[1..-1]
|
271
|
-
while result && result[-1] == nil
|
272
|
-
result = result[0..-2]
|
261
|
+
first_column(sheet).upto(last_column(sheet)) do |col|
|
262
|
+
result << cell(rownumber,col,sheet)
|
273
263
|
end
|
274
264
|
result
|
275
265
|
end
|
data/lib/roo/google.rb
CHANGED
@@ -109,10 +109,7 @@ class Google < GenericSpreadsheet
|
|
109
109
|
#-- ----------------------------------------------------------------------
|
110
110
|
#-- TODO: Behandlung von Berechtigungen hier noch einbauen ???
|
111
111
|
#-- ----------------------------------------------------------------------
|
112
|
-
|
113
|
-
if self.sheets.size == 1
|
114
|
-
@default_sheet = self.sheets.first
|
115
|
-
end
|
112
|
+
@default_sheet = self.sheets.first
|
116
113
|
end
|
117
114
|
|
118
115
|
# returns an array of sheet names in the spreadsheet
|
@@ -241,28 +238,6 @@ class Google < GenericSpreadsheet
|
|
241
238
|
theformulas
|
242
239
|
end
|
243
240
|
|
244
|
-
# returns all values in this row as an array
|
245
|
-
# row numbers are 1,2,3,... like in the spreadsheet
|
246
|
-
def row(rownumber,sheet=nil)
|
247
|
-
sheet = @default_sheet unless sheet
|
248
|
-
read_cells(sheet) unless @cells_read[sheet]
|
249
|
-
result = []
|
250
|
-
tmp_arr = []
|
251
|
-
@cell[sheet].each_pair {|key,value|
|
252
|
-
y,x = key.split(',')
|
253
|
-
x = x.to_i
|
254
|
-
y = y.to_i
|
255
|
-
if y == rownumber
|
256
|
-
tmp_arr[x] = value
|
257
|
-
end
|
258
|
-
}
|
259
|
-
result = tmp_arr[1..-1]
|
260
|
-
while result[-1] == nil
|
261
|
-
result = result[0..-2]
|
262
|
-
end
|
263
|
-
result
|
264
|
-
end
|
265
|
-
|
266
241
|
# true, if the cell is empty
|
267
242
|
def empty?(row, col, sheet=nil)
|
268
243
|
value = cell(row, col, sheet)
|
@@ -273,23 +248,6 @@ class Google < GenericSpreadsheet
|
|
273
248
|
value.empty?
|
274
249
|
end
|
275
250
|
|
276
|
-
# returns all values in this column as an array
|
277
|
-
# column numbers are 1,2,3,... like in the spreadsheet
|
278
|
-
#--
|
279
|
-
#TODO: refactoring nach GenericSpreadsheet?
|
280
|
-
def column(columnnumber, sheet=nil)
|
281
|
-
if columnnumber.class == String
|
282
|
-
columnnumber = GenericSpreadsheet.letter_to_number(columnnumber)
|
283
|
-
end
|
284
|
-
sheet = @default_sheet unless sheet
|
285
|
-
read_cells(sheet) unless @cells_read[sheet]
|
286
|
-
result = []
|
287
|
-
first_row(sheet).upto(last_row(sheet)) do |row|
|
288
|
-
result << cell(row,columnnumber,sheet)
|
289
|
-
end
|
290
|
-
result
|
291
|
-
end
|
292
|
-
|
293
251
|
# sets the cell to the content of 'value'
|
294
252
|
# a formula can be set in the form of '=SUM(...)'
|
295
253
|
def set_value(row,col,value,sheet=nil)
|
data/lib/roo/openoffice.rb
CHANGED
@@ -43,11 +43,7 @@ class Openoffice < GenericSpreadsheet
|
|
43
43
|
FileUtils::rm_r(@tmpdir)
|
44
44
|
#end
|
45
45
|
end
|
46
|
-
@default_sheet =
|
47
|
-
# no need to set default_sheet if there is only one sheet in the document
|
48
|
-
if self.sheets.size == 1
|
49
|
-
@default_sheet = self.sheets.first
|
50
|
-
end
|
46
|
+
@default_sheet = self.sheets.first
|
51
47
|
@cell = Hash.new
|
52
48
|
@cell_type = Hash.new
|
53
49
|
@formula = Hash.new
|
data/lib/roo/version.rb
CHANGED
data/lib/roo.rb
CHANGED
@@ -1,4 +1,22 @@
|
|
1
1
|
module Roo
|
2
|
+
class Spreadsheet
|
3
|
+
class << self
|
4
|
+
def open(file)
|
5
|
+
case File.extname(file)
|
6
|
+
when '.xls'
|
7
|
+
Excel.new(file)
|
8
|
+
when '.xlsx'
|
9
|
+
Excelx.new(file)
|
10
|
+
when '.ods'
|
11
|
+
Openoffice.new(file)
|
12
|
+
when ''
|
13
|
+
Google.new(file)
|
14
|
+
else
|
15
|
+
raise ArgumentError, "Don't know how to open file #{filename}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
2
20
|
end
|
3
21
|
|
4
22
|
require 'roo/version'
|
data/test/1900_base.xls
ADDED
Binary file
|
data/test/1904_base.xls
ADDED
Binary file
|