roo 1.10.1 → 1.10.2
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/.gitignore +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +38 -0
- data/History.txt +4 -4
- data/License.txt +20 -0
- data/Manifest.txt +68 -0
- data/README.markdown +109 -0
- data/Rakefile +5 -4
- data/bin/roo +0 -0
- data/examples/roo_soap_client.rb +53 -0
- data/examples/roo_soap_server.rb +29 -0
- data/examples/write_me.rb +33 -0
- data/lib/roo.rb +20 -61
- data/lib/roo/csv.rb +13 -11
- data/lib/roo/excel.rb +108 -219
- data/lib/roo/excel2003xml.rb +312 -0
- data/lib/roo/excelx.rb +205 -341
- data/lib/roo/generic_spreadsheet.rb +371 -268
- data/lib/roo/google.rb +64 -54
- data/lib/roo/openoffice.rb +101 -156
- data/lib/roo/roo_rails_helper.rb +5 -5
- data/lib/roo/worksheet.rb +18 -0
- data/roo.gemspec +43 -0
- data/scripts/txt2html +67 -0
- data/test/all_ss.rb +8 -10
- data/test/{1900_base.xls → files/1900_base.xls} +0 -0
- data/test/{1904_base.xls → files/1904_base.xls} +0 -0
- data/test/{Bibelbund.csv → files/Bibelbund.csv} +0 -0
- data/test/{Bibelbund.ods → files/Bibelbund.ods} +0 -0
- data/test/{Bibelbund.xls → files/Bibelbund.xls} +0 -0
- data/test/{Bibelbund.xlsx → files/Bibelbund.xlsx} +0 -0
- data/test/files/Bibelbund.xml +62518 -0
- data/test/{Bibelbund1.ods → files/Bibelbund1.ods} +0 -0
- data/test/{Pfand_from_windows_phone.xlsx → files/Pfand_from_windows_phone.xlsx} +0 -0
- data/test/files/bad_excel_date.xls +0 -0
- data/test/{bbu.ods → files/bbu.ods} +0 -0
- data/test/{bbu.xls → files/bbu.xls} +0 -0
- data/test/{bbu.xlsx → files/bbu.xlsx} +0 -0
- data/test/files/bbu.xml +152 -0
- data/test/{bode-v1.ods.zip → files/bode-v1.ods.zip} +0 -0
- data/test/{bode-v1.xls.zip → files/bode-v1.xls.zip} +0 -0
- data/test/{boolean.ods → files/boolean.ods} +0 -0
- data/test/{boolean.xls → files/boolean.xls} +0 -0
- data/test/{boolean.xlsx → files/boolean.xlsx} +0 -0
- data/test/files/boolean.xml +112 -0
- data/test/{borders.ods → files/borders.ods} +0 -0
- data/test/{borders.xls → files/borders.xls} +0 -0
- data/test/{borders.xlsx → files/borders.xlsx} +0 -0
- data/test/files/borders.xml +144 -0
- data/test/{bug-row-column-fixnum-float.xls → files/bug-row-column-fixnum-float.xls} +0 -0
- data/test/files/bug-row-column-fixnum-float.xml +127 -0
- data/test/{comments.ods → files/comments.ods} +0 -0
- data/test/{comments.xls → files/comments.xls} +0 -0
- data/test/{comments.xlsx → files/comments.xlsx} +0 -0
- data/test/{csvtypes.csv → files/csvtypes.csv} +0 -0
- data/test/{datetime.ods → files/datetime.ods} +0 -0
- data/test/{datetime.xls → files/datetime.xls} +0 -0
- data/test/{datetime.xlsx → files/datetime.xlsx} +0 -0
- data/test/files/datetime.xml +142 -0
- data/test/{datetime_floatconv.xls → files/datetime_floatconv.xls} +0 -0
- data/test/files/datetime_floatconv.xml +148 -0
- data/test/{dreimalvier.ods → files/dreimalvier.ods} +0 -0
- data/test/{emptysheets.ods → files/emptysheets.ods} +0 -0
- data/test/{emptysheets.xls → files/emptysheets.xls} +0 -0
- data/test/{emptysheets.xlsx → files/emptysheets.xlsx} +0 -0
- data/test/files/emptysheets.xml +105 -0
- data/test/files/excel2003.xml +21140 -0
- data/test/{false_encoding.xls → files/false_encoding.xls} +0 -0
- data/test/files/false_encoding.xml +132 -0
- data/test/{formula.ods → files/formula.ods} +0 -0
- data/test/{formula.xls → files/formula.xls} +0 -0
- data/test/{formula.xlsx → files/formula.xlsx} +0 -0
- data/test/files/formula.xml +134 -0
- data/test/files/formula_parse_error.xls +0 -0
- data/test/files/formula_parse_error.xml +1833 -0
- data/test/{formula_string_error.xlsx → files/formula_string_error.xlsx} +0 -0
- data/test/{html-escape.ods → files/html-escape.ods} +0 -0
- data/test/{matrix.ods → files/matrix.ods} +0 -0
- data/test/{matrix.xls → files/matrix.xls} +0 -0
- data/test/{named_cells.ods → files/named_cells.ods} +0 -0
- data/test/{named_cells.xls → files/named_cells.xls} +0 -0
- data/test/{named_cells.xlsx → files/named_cells.xlsx} +0 -0
- data/test/{no_spreadsheet_file.txt → files/no_spreadsheet_file.txt} +0 -0
- data/test/{numbers1.csv → files/numbers1.csv} +0 -0
- data/test/{numbers1.ods → files/numbers1.ods} +0 -0
- data/test/{numbers1.xls → files/numbers1.xls} +0 -0
- data/test/{numbers1.xlsx → files/numbers1.xlsx} +0 -0
- data/test/files/numbers1.xml +312 -0
- data/test/{only_one_sheet.ods → files/only_one_sheet.ods} +0 -0
- data/test/{only_one_sheet.xls → files/only_one_sheet.xls} +0 -0
- data/test/{only_one_sheet.xlsx → files/only_one_sheet.xlsx} +0 -0
- data/test/files/only_one_sheet.xml +67 -0
- data/test/{paragraph.ods → files/paragraph.ods} +0 -0
- data/test/{paragraph.xls → files/paragraph.xls} +0 -0
- data/test/{paragraph.xlsx → files/paragraph.xlsx} +0 -0
- data/test/files/paragraph.xml +127 -0
- data/test/{prova.xls → files/prova.xls} +0 -0
- data/test/{ric.ods → files/ric.ods} +0 -0
- data/test/{simple_spreadsheet.ods → files/simple_spreadsheet.ods} +0 -0
- data/test/{simple_spreadsheet.xls → files/simple_spreadsheet.xls} +0 -0
- data/test/{simple_spreadsheet.xlsx → files/simple_spreadsheet.xlsx} +0 -0
- data/test/files/simple_spreadsheet.xml +225 -0
- data/test/{simple_spreadsheet_from_italo.ods → files/simple_spreadsheet_from_italo.ods} +0 -0
- data/test/{simple_spreadsheet_from_italo.xls → files/simple_spreadsheet_from_italo.xls} +0 -0
- data/test/files/simple_spreadsheet_from_italo.xml +242 -0
- data/test/{so_datetime.csv → files/so_datetime.csv} +0 -0
- data/test/{style.ods → files/style.ods} +0 -0
- data/test/{style.xls → files/style.xls} +0 -0
- data/test/{style.xlsx → files/style.xlsx} +0 -0
- data/test/files/style.xml +154 -0
- data/test/{time-test.csv → files/time-test.csv} +0 -0
- data/test/{time-test.ods → files/time-test.ods} +0 -0
- data/test/{time-test.xls → files/time-test.xls} +0 -0
- data/test/{time-test.xlsx → files/time-test.xlsx} +0 -0
- data/test/files/time-test.xml +131 -0
- data/test/{type_excel.ods → files/type_excel.ods} +0 -0
- data/test/{type_excel.xlsx → files/type_excel.xlsx} +0 -0
- data/test/{type_excelx.ods → files/type_excelx.ods} +0 -0
- data/test/{type_excelx.xls → files/type_excelx.xls} +0 -0
- data/test/{type_openoffice.xls → files/type_openoffice.xls} +0 -0
- data/test/{type_openoffice.xlsx → files/type_openoffice.xlsx} +0 -0
- data/test/{whitespace.ods → files/whitespace.ods} +0 -0
- data/test/{whitespace.xls → files/whitespace.xls} +0 -0
- data/test/{whitespace.xlsx → files/whitespace.xlsx} +0 -0
- data/test/files/whitespace.xml +184 -0
- data/test/test_generic_spreadsheet.rb +257 -0
- data/test/test_helper.rb +167 -27
- data/test/test_roo.rb +1178 -930
- data/website/index.html +385 -0
- data/website/index.txt +423 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +130 -0
- data/website/template.rhtml +48 -0
- metadata +151 -121
- data/README.txt +0 -110
- data/lib/roo/.csv.rb.swp +0 -0
@@ -1,39 +1,23 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'stringio'
|
3
5
|
|
4
6
|
# Base class for all other types of spreadsheets
|
5
|
-
class GenericSpreadsheet
|
7
|
+
class Roo::GenericSpreadsheet
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
TEMP_PREFIX = "oo_"
|
6
11
|
|
7
|
-
attr_reader :default_sheet
|
12
|
+
attr_reader :default_sheet, :headers
|
8
13
|
|
9
14
|
# sets the line with attribute names (default: 1)
|
10
15
|
attr_accessor :header_line
|
11
16
|
|
12
17
|
protected
|
13
18
|
|
14
|
-
# Helper function for development
|
15
|
-
def fremdrechner? #nodoc
|
16
|
-
eigener = [
|
17
|
-
'C:\Users\thopre',
|
18
|
-
'c:/Users/thopre',
|
19
|
-
'/c/Users/thopre',
|
20
|
-
'/home/tp',
|
21
|
-
].include? ENV['HOME']
|
22
|
-
# if eigener
|
23
|
-
# puts "fremdrechner? ==> false"
|
24
|
-
# else
|
25
|
-
# puts "fremdrechner? ==> true"
|
26
|
-
# end
|
27
|
-
! eigener
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.next_tmpdir
|
31
|
-
tmpdir = "oo_"+$$.to_s+"_"+sprintf("%010d",rand(10_000_000_000))
|
32
|
-
tmpdir
|
33
|
-
end
|
34
|
-
|
35
19
|
def self.split_coordinate(str)
|
36
|
-
letter,number = GenericSpreadsheet.split_coord(str)
|
20
|
+
letter,number = Roo::GenericSpreadsheet.split_coord(str)
|
37
21
|
x = letter_to_number(letter)
|
38
22
|
y = number
|
39
23
|
return y, x
|
@@ -52,41 +36,47 @@ class GenericSpreadsheet
|
|
52
36
|
|
53
37
|
public
|
54
38
|
|
39
|
+
def initialize(filename, packed=nil, file_warning=:error, tmpdir=nil)
|
40
|
+
@cell = Hash.new{|h,k| h[k] = {}}
|
41
|
+
@cell_type = Hash.new{|h,k| h[k] = {}}
|
42
|
+
@cells_read = {}
|
43
|
+
|
44
|
+
@first_row = {}
|
45
|
+
@last_row = {}
|
46
|
+
@first_column = {}
|
47
|
+
@last_column = {}
|
48
|
+
|
49
|
+
@style = {}
|
50
|
+
@style_defaults = Hash.new { |h,k| h[k] = [] }
|
51
|
+
@style_definitions = {}
|
52
|
+
|
53
|
+
@default_sheet = self.sheets.first
|
54
|
+
@formula = {}
|
55
|
+
@header_line = 1
|
56
|
+
end
|
57
|
+
|
55
58
|
# sets the working sheet in the document
|
56
59
|
# 'sheet' can be a number (1 = first sheet) or the name of a sheet.
|
57
60
|
def default_sheet=(sheet)
|
58
|
-
|
59
|
-
if sheet > 0 and sheet <= sheets.length
|
60
|
-
sheet = self.sheets[sheet-1]
|
61
|
-
else
|
62
|
-
raise RangeError
|
63
|
-
end
|
64
|
-
elsif sheet.kind_of?(String)
|
65
|
-
raise RangeError if ! self.sheets.include?(sheet)
|
66
|
-
else
|
67
|
-
raise TypeError, "what are you trying to set as default sheet?"
|
68
|
-
end
|
61
|
+
validate_sheet!(sheet)
|
69
62
|
@default_sheet = sheet
|
70
|
-
check_default_sheet
|
71
63
|
@first_row[sheet] = @last_row[sheet] = @first_column[sheet] = @last_column[sheet] = nil
|
72
64
|
@cells_read[sheet] = false
|
73
65
|
end
|
74
66
|
|
75
67
|
# first non-empty column as a letter
|
76
68
|
def first_column_as_letter(sheet=nil)
|
77
|
-
GenericSpreadsheet.number_to_letter(first_column(sheet))
|
69
|
+
Roo::GenericSpreadsheet.number_to_letter(first_column(sheet))
|
78
70
|
end
|
79
71
|
|
80
72
|
# last non-empty column as a letter
|
81
73
|
def last_column_as_letter(sheet=nil)
|
82
|
-
GenericSpreadsheet.number_to_letter(last_column(sheet))
|
74
|
+
Roo::GenericSpreadsheet.number_to_letter(last_column(sheet))
|
83
75
|
end
|
84
76
|
|
85
77
|
# returns the number of the first non-empty row
|
86
78
|
def first_row(sheet=nil)
|
87
|
-
|
88
|
-
sheet = @default_sheet
|
89
|
-
end
|
79
|
+
sheet ||= @default_sheet
|
90
80
|
read_cells(sheet) unless @cells_read[sheet]
|
91
81
|
if @first_row[sheet]
|
92
82
|
return @first_row[sheet]
|
@@ -94,8 +84,7 @@ class GenericSpreadsheet
|
|
94
84
|
impossible_value = 999_999 # more than a spreadsheet can hold
|
95
85
|
result = impossible_value
|
96
86
|
@cell[sheet].each_pair {|key,value|
|
97
|
-
y
|
98
|
-
y = y.to_i
|
87
|
+
y = key.first.to_i # _to_string(key).split(',')
|
99
88
|
result = [result, y].min if value
|
100
89
|
} if @cell[sheet]
|
101
90
|
result = nil if result == impossible_value
|
@@ -105,7 +94,7 @@ class GenericSpreadsheet
|
|
105
94
|
|
106
95
|
# returns the number of the last non-empty row
|
107
96
|
def last_row(sheet=nil)
|
108
|
-
sheet
|
97
|
+
sheet ||= @default_sheet
|
109
98
|
read_cells(sheet) unless @cells_read[sheet]
|
110
99
|
if @last_row[sheet]
|
111
100
|
return @last_row[sheet]
|
@@ -113,8 +102,7 @@ class GenericSpreadsheet
|
|
113
102
|
impossible_value = 0
|
114
103
|
result = impossible_value
|
115
104
|
@cell[sheet].each_pair {|key,value|
|
116
|
-
y
|
117
|
-
y = y.to_i
|
105
|
+
y = key.first.to_i # _to_string(key).split(',')
|
118
106
|
result = [result, y].max if value
|
119
107
|
} if @cell[sheet]
|
120
108
|
result = nil if result == impossible_value
|
@@ -124,9 +112,7 @@ class GenericSpreadsheet
|
|
124
112
|
|
125
113
|
# returns the number of the first non-empty column
|
126
114
|
def first_column(sheet=nil)
|
127
|
-
|
128
|
-
sheet = @default_sheet
|
129
|
-
end
|
115
|
+
sheet ||= @default_sheet
|
130
116
|
read_cells(sheet) unless @cells_read[sheet]
|
131
117
|
if @first_column[sheet]
|
132
118
|
return @first_column[sheet]
|
@@ -134,8 +120,7 @@ class GenericSpreadsheet
|
|
134
120
|
impossible_value = 999_999 # more than a spreadsheet can hold
|
135
121
|
result = impossible_value
|
136
122
|
@cell[sheet].each_pair {|key,value|
|
137
|
-
|
138
|
-
x = x # .to_i
|
123
|
+
x = key.last.to_i # _to_string(key).split(',')
|
139
124
|
result = [result, x].min if value
|
140
125
|
} if @cell[sheet]
|
141
126
|
result = nil if result == impossible_value
|
@@ -145,7 +130,7 @@ class GenericSpreadsheet
|
|
145
130
|
|
146
131
|
# returns the number of the last non-empty column
|
147
132
|
def last_column(sheet=nil)
|
148
|
-
sheet
|
133
|
+
sheet ||= @default_sheet
|
149
134
|
read_cells(sheet) unless @cells_read[sheet]
|
150
135
|
if @last_column[sheet]
|
151
136
|
return @last_column[sheet]
|
@@ -153,8 +138,7 @@ class GenericSpreadsheet
|
|
153
138
|
impossible_value = 0
|
154
139
|
result = impossible_value
|
155
140
|
@cell[sheet].each_pair {|key,value|
|
156
|
-
|
157
|
-
x = x.to_i
|
141
|
+
x = key.last.to_i # _to_string(key).split(',')
|
158
142
|
result = [result, x].max if value
|
159
143
|
} if @cell[sheet]
|
160
144
|
result = nil if result == impossible_value
|
@@ -166,7 +150,7 @@ class GenericSpreadsheet
|
|
166
150
|
# you can add additional attributes with the prefix parameter like:
|
167
151
|
# oo.to_yaml({"file"=>"flightdata_2007-06-26", "sheet" => "1"})
|
168
152
|
def to_yaml(prefix={}, from_row=nil, from_column=nil, to_row=nil, to_column=nil,sheet=nil)
|
169
|
-
sheet
|
153
|
+
sheet ||= @default_sheet
|
170
154
|
result = "--- \n"
|
171
155
|
return '' unless first_row # empty result if there is no first_row in a sheet
|
172
156
|
|
@@ -181,7 +165,7 @@ class GenericSpreadsheet
|
|
181
165
|
result << " col: #{col} \n"
|
182
166
|
result << " celltype: #{self.celltype(row,col,sheet)} \n"
|
183
167
|
if self.celltype(row,col,sheet) == :time
|
184
|
-
result << " value: #{GenericSpreadsheet.integer_to_timestring( self.cell(row,col,sheet))} \n"
|
168
|
+
result << " value: #{Roo::GenericSpreadsheet.integer_to_timestring( self.cell(row,col,sheet))} \n"
|
185
169
|
else
|
186
170
|
result << " value: #{self.cell(row,col,sheet)} \n"
|
187
171
|
end
|
@@ -193,152 +177,117 @@ class GenericSpreadsheet
|
|
193
177
|
|
194
178
|
# write the current spreadsheet to stdout or into a file
|
195
179
|
def to_csv(filename=nil,sheet=nil)
|
196
|
-
sheet
|
180
|
+
sheet ||= @default_sheet
|
197
181
|
if filename
|
198
|
-
|
199
|
-
|
200
|
-
|
182
|
+
File.open(filename,"w") do |file|
|
183
|
+
write_csv_content(file,sheet)
|
184
|
+
end
|
185
|
+
return true
|
201
186
|
else
|
202
|
-
|
187
|
+
sio = StringIO.new
|
188
|
+
write_csv_content(sio,sheet)
|
189
|
+
sio.rewind
|
190
|
+
return sio.read
|
203
191
|
end
|
204
|
-
true
|
205
192
|
end
|
206
193
|
|
207
194
|
# returns a matrix object from the whole sheet or a rectangular area of a sheet
|
208
195
|
def to_matrix(from_row=nil, from_column=nil, to_row=nil, to_column=nil,sheet=nil)
|
209
|
-
|
210
|
-
arr = []
|
211
|
-
pos = 0
|
212
|
-
return Matrix.rows([]) unless first_row
|
196
|
+
require 'matrix'
|
213
197
|
|
214
|
-
|
215
|
-
|
216
|
-
(from_column||first_column(sheet)).upto(to_column||last_column(sheet)) do |col|
|
198
|
+
sheet ||= @default_sheet
|
199
|
+
return Matrix.empty unless first_row
|
217
200
|
|
218
|
-
|
201
|
+
Matrix.rows((from_row||first_row(sheet)).upto(to_row||last_row(sheet)).map do |row|
|
202
|
+
(from_column||first_column(sheet)).upto(to_column||last_column(sheet)).map do |col|
|
203
|
+
cell(row,col)
|
219
204
|
end
|
220
|
-
|
221
|
-
pos += 1
|
222
|
-
end
|
223
|
-
Matrix.rows(arr)
|
205
|
+
end)
|
224
206
|
end
|
225
207
|
|
226
208
|
# find a row either by row number or a condition
|
227
209
|
# Caution: this works only within the default sheet -> set default_sheet before you call this method
|
228
210
|
# (experimental. see examples in the test_roo.rb file)
|
229
211
|
def find(*args) # :nodoc
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
result_array = true
|
236
|
-
end
|
237
|
-
}
|
238
|
-
end
|
239
|
-
}
|
240
|
-
column_with = {}
|
241
|
-
1.upto(last_column) do |col|
|
242
|
-
column_with[cell(@header_line,col)] = col
|
243
|
-
end
|
244
|
-
result = Array.new
|
212
|
+
options = (args.last.is_a?(Hash) ? args.pop : {})
|
213
|
+
result_array = options[:array]
|
214
|
+
header_for = Hash[1.upto(last_column).map do |col|
|
215
|
+
[col, cell(@header_line,col)]
|
216
|
+
end]
|
245
217
|
#-- id
|
246
218
|
if args[0].class == Fixnum
|
247
219
|
rownum = args[0]
|
248
220
|
if @header_line
|
249
|
-
|
221
|
+
[Hash[1.upto(self.row().size).map {|j|
|
222
|
+
[header_for.fetch(j), cell(rownum,j)]
|
223
|
+
}]]
|
250
224
|
else
|
251
|
-
|
252
|
-
|
253
|
-
1.upto(self.row(rownum).size) {|j|
|
254
|
-
x = ''
|
255
|
-
column_with.each { |key,val|
|
256
|
-
if val == j
|
257
|
-
x = key
|
258
|
-
end
|
225
|
+
self.row(rownum).size.times.map {|j|
|
226
|
+
cell(rownum,j + 1)
|
259
227
|
}
|
260
|
-
if @header_line
|
261
|
-
tmp[x] = cell(rownum,j)
|
262
|
-
else
|
263
|
-
tmp[j-1] = cell(rownum,j)
|
264
|
-
end
|
265
|
-
|
266
|
-
}
|
267
|
-
if @header_line
|
268
|
-
result = [ tmp ]
|
269
|
-
else
|
270
|
-
result = tmp
|
271
228
|
end
|
272
|
-
|
229
|
+
#-- :all
|
273
230
|
elsif args[0] == :all
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
if found > 0
|
293
|
-
tmp = {}
|
294
|
-
1.upto(self.row(i).size) {|j|
|
295
|
-
x = ''
|
296
|
-
column_with.each { |key,val|
|
297
|
-
if val == j
|
298
|
-
x = key
|
299
|
-
end
|
300
|
-
}
|
301
|
-
tmp[x] = cell(i,j)
|
302
|
-
}
|
303
|
-
if result_array
|
304
|
-
result << self.row(i)
|
305
|
-
else
|
306
|
-
result << tmp
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
end # :conditions
|
311
|
-
}
|
231
|
+
rows = first_row.upto(last_row)
|
232
|
+
|
233
|
+
# are all conditions met?
|
234
|
+
if (conditions = options[:conditions]) && !conditions.empty?
|
235
|
+
column_with = header_for.invert
|
236
|
+
rows = rows.select do |i|
|
237
|
+
conditions.all? { |key,val| cell(i,column_with[key]) == val }
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
rows.map do |i|
|
242
|
+
if result_array
|
243
|
+
self.row(i)
|
244
|
+
else
|
245
|
+
Hash[1.upto(self.row(i).size).map do |j|
|
246
|
+
[header_for.fetch(j), cell(i,j)]
|
247
|
+
end]
|
248
|
+
end
|
312
249
|
end
|
313
250
|
end
|
314
|
-
result
|
315
251
|
end
|
316
252
|
|
317
253
|
# returns all values in this row as an array
|
318
254
|
# row numbers are 1,2,3,... like in the spreadsheet
|
319
255
|
def row(rownumber,sheet=nil)
|
320
|
-
sheet
|
256
|
+
sheet ||= @default_sheet
|
321
257
|
read_cells(sheet) unless @cells_read[sheet]
|
322
|
-
|
323
|
-
|
324
|
-
result << cell(rownumber,col,sheet)
|
258
|
+
first_column(sheet).upto(last_column(sheet)).map do |col|
|
259
|
+
cell(rownumber,col,sheet)
|
325
260
|
end
|
326
|
-
result
|
327
261
|
end
|
328
262
|
|
329
263
|
# returns all values in this column as an array
|
330
264
|
# column numbers are 1,2,3,... like in the spreadsheet
|
331
265
|
def column(columnnumber,sheet=nil)
|
332
266
|
if columnnumber.class == String
|
333
|
-
columnnumber = Excel.letter_to_number(columnnumber)
|
267
|
+
columnnumber = Roo::Excel.letter_to_number(columnnumber)
|
334
268
|
end
|
335
|
-
sheet
|
269
|
+
sheet ||= @default_sheet
|
336
270
|
read_cells(sheet) unless @cells_read[sheet]
|
337
|
-
|
338
|
-
|
339
|
-
result << cell(row,columnnumber,sheet)
|
271
|
+
first_row(sheet).upto(last_row(sheet)).map do |row|
|
272
|
+
cell(row,columnnumber,sheet)
|
340
273
|
end
|
341
|
-
|
274
|
+
end
|
275
|
+
|
276
|
+
# set a cell to a certain value
|
277
|
+
# (this will not be saved back to the spreadsheet file!)
|
278
|
+
def set(row,col,value,sheet=nil) #:nodoc:
|
279
|
+
sheet ||= @default_sheet
|
280
|
+
read_cells(sheet) unless @cells_read[sheet]
|
281
|
+
row, col = normalize(row,col)
|
282
|
+
cell_type = case value
|
283
|
+
when Fixnum then :float
|
284
|
+
when String, Float then :string
|
285
|
+
else
|
286
|
+
raise ArgumentError, "Type for #{value} not set"
|
287
|
+
end
|
288
|
+
|
289
|
+
set_value(row,col,value,sheet)
|
290
|
+
set_type(row,col,cell_type,sheet)
|
342
291
|
end
|
343
292
|
|
344
293
|
# reopens and read a spreadsheet document
|
@@ -356,21 +305,12 @@ class GenericSpreadsheet
|
|
356
305
|
|
357
306
|
# true if cell is empty
|
358
307
|
def empty?(row, col, sheet=nil)
|
359
|
-
sheet
|
360
|
-
read_cells(sheet) unless @cells_read[sheet] or self.class == Excel
|
308
|
+
sheet ||= @default_sheet
|
309
|
+
read_cells(sheet) unless @cells_read[sheet] or self.class == Roo::Excel
|
361
310
|
row,col = normalize(row,col)
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
false
|
366
|
-
end
|
367
|
-
|
368
|
-
# recursively removes the current temporary directory
|
369
|
-
# this is only needed if you work with zipped files or files via the web
|
370
|
-
def remove_tmp
|
371
|
-
if File.exists?(@tmpdir)
|
372
|
-
FileUtils::rm_r(@tmpdir)
|
373
|
-
end
|
311
|
+
contents = cell(row, col, sheet)
|
312
|
+
!contents || (celltype(row, col, sheet) == :string && contents.empty?) \
|
313
|
+
|| (row < first_row(sheet) || row > last_row(sheet) || col < first_column(sheet) || col > last_column(sheet))
|
374
314
|
end
|
375
315
|
|
376
316
|
# returns information of the spreadsheet document and all sheets within
|
@@ -388,8 +328,8 @@ class GenericSpreadsheet
|
|
388
328
|
else
|
389
329
|
result << " First row: #{first_row}\n"
|
390
330
|
result << " Last row: #{last_row}\n"
|
391
|
-
result << " First column: #{GenericSpreadsheet.number_to_letter(first_column)}\n"
|
392
|
-
result << " Last column: #{GenericSpreadsheet.number_to_letter(last_column)}"
|
331
|
+
result << " First column: #{Roo::GenericSpreadsheet.number_to_letter(first_column)}\n"
|
332
|
+
result << " Last column: #{Roo::GenericSpreadsheet.number_to_letter(last_column)}"
|
393
333
|
end
|
394
334
|
result << "\n" if sheet != sheets.last
|
395
335
|
n += 1
|
@@ -399,7 +339,7 @@ class GenericSpreadsheet
|
|
399
339
|
|
400
340
|
# returns an XML representation of all sheets of a spreadsheet file
|
401
341
|
def to_xml
|
402
|
-
|
342
|
+
Nokogiri::XML::Builder.new do |xml|
|
403
343
|
xml.spreadsheet {
|
404
344
|
self.sheets.each do |sheet|
|
405
345
|
self.default_sheet = sheet
|
@@ -420,8 +360,7 @@ class GenericSpreadsheet
|
|
420
360
|
}
|
421
361
|
end
|
422
362
|
}
|
423
|
-
end
|
424
|
-
return builder.to_xml
|
363
|
+
end.to_xml
|
425
364
|
end
|
426
365
|
|
427
366
|
# when a method like spreadsheet.a42 is called
|
@@ -430,12 +369,12 @@ class GenericSpreadsheet
|
|
430
369
|
# #aa42 => #cell('aa',42)
|
431
370
|
# #aa42('Sheet1') => #cell('aa',42,'Sheet1')
|
432
371
|
if m =~ /^([a-z]+)(\d)$/
|
433
|
-
col = GenericSpreadsheet.letter_to_number($1)
|
372
|
+
col = Roo::GenericSpreadsheet.letter_to_number($1)
|
434
373
|
row = $2.to_i
|
435
|
-
if args.
|
436
|
-
|
374
|
+
if args.empty?
|
375
|
+
cell(row,col)
|
437
376
|
else
|
438
|
-
|
377
|
+
cell(row,col,args.first)
|
439
378
|
end
|
440
379
|
else
|
441
380
|
super
|
@@ -448,7 +387,7 @@ class GenericSpreadsheet
|
|
448
387
|
# [row, col, formula]
|
449
388
|
def formulas(sheet=nil)
|
450
389
|
theformulas = Array.new
|
451
|
-
sheet
|
390
|
+
sheet ||= @default_sheet
|
452
391
|
read_cells(sheet) unless @cells_read[sheet]
|
453
392
|
return theformulas unless first_row(sheet) # if there is no first row then
|
454
393
|
# there can't be formulas
|
@@ -463,14 +402,127 @@ class GenericSpreadsheet
|
|
463
402
|
end
|
464
403
|
=end
|
465
404
|
|
405
|
+
|
406
|
+
|
407
|
+
# FestivalBobcats fork changes begin here
|
408
|
+
|
409
|
+
|
410
|
+
|
411
|
+
# access different worksheets by calling spreadsheet.sheet(1)
|
412
|
+
# or spreadsheet.sheet('SHEETNAME')
|
413
|
+
def sheet(index,name=false)
|
414
|
+
@default_sheet = String === index ? index : self.sheets[index]
|
415
|
+
name ? [@default_sheet,self] : self
|
416
|
+
end
|
417
|
+
|
418
|
+
# iterate through all worksheets of a document
|
419
|
+
def each_with_pagename
|
420
|
+
self.sheets.each do |s|
|
421
|
+
yield sheet(s,true)
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
# by passing in headers as options, this method returns
|
426
|
+
# specific columns from your header assignment
|
427
|
+
# for example:
|
428
|
+
# xls.sheet('New Prices').parse(:upc => 'UPC', :price => 'Price') would return:
|
429
|
+
# [{:upc => 123456789012, :price => 35.42},..]
|
430
|
+
|
431
|
+
# the queries are matched with regex, so regex options can be passed in
|
432
|
+
# such as :price => '^(Cost|Price)'
|
433
|
+
# case insensitive by default
|
434
|
+
|
435
|
+
|
436
|
+
# by using the :header_search option, you can query for headers
|
437
|
+
# and return a hash of every row with the keys set to the header result
|
438
|
+
# for example:
|
439
|
+
# xls.sheet('New Prices').parse(:header_search => ['UPC*SKU','^Price*\sCost\s'])
|
440
|
+
|
441
|
+
# that example searches for a column titled either UPC or SKU and another
|
442
|
+
# column titled either Price or Cost (regex characters allowed)
|
443
|
+
# * is the wildcard character
|
444
|
+
|
445
|
+
# you can also pass in a :clean => true option to strip the sheet of
|
446
|
+
# odd unicode characters and white spaces around columns
|
447
|
+
|
448
|
+
def each(options={})
|
449
|
+
if options.empty?
|
450
|
+
1.upto(last_row) do |line|
|
451
|
+
yield row(line)
|
452
|
+
end
|
453
|
+
else
|
454
|
+
if options[:clean]
|
455
|
+
options.delete(:clean)
|
456
|
+
@cleaned ||= {}
|
457
|
+
@cleaned[@default_sheet] || clean_sheet(@default_sheet)
|
458
|
+
end
|
459
|
+
|
460
|
+
if options[:header_search]
|
461
|
+
@headers = nil
|
462
|
+
@header_line = row_with(options[:header_search])
|
463
|
+
elsif [:first_row,true].include?(options[:headers])
|
464
|
+
@headers = []
|
465
|
+
row(first_row).each_with_index {|x,i| @headers << [x,i + 1]}
|
466
|
+
else
|
467
|
+
set_headers(options)
|
468
|
+
end
|
469
|
+
|
470
|
+
headers = @headers ||
|
471
|
+
Hash[(first_column..last_column).map do |col|
|
472
|
+
[cell(@header_line,col), col]
|
473
|
+
end]
|
474
|
+
|
475
|
+
@header_line.upto(last_row) do |line|
|
476
|
+
yield(Hash[headers.map {|k,v| [k,cell(line,v)]}])
|
477
|
+
end
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def parse(options={})
|
482
|
+
ary = []
|
483
|
+
if block_given?
|
484
|
+
each(options) {|row| ary << yield(row)}
|
485
|
+
else
|
486
|
+
each(options) {|row| ary << row}
|
487
|
+
end
|
488
|
+
ary
|
489
|
+
end
|
490
|
+
|
491
|
+
def row_with(query,return_headers=false)
|
492
|
+
query.map! {|x| Array(x.split('*'))}
|
493
|
+
line_no = 0
|
494
|
+
each do |row|
|
495
|
+
line_no += 1
|
496
|
+
# makes sure headers is the first part of wildcard search for priority
|
497
|
+
# ex. if UPC and SKU exist for UPC*SKU search, UPC takes the cake
|
498
|
+
headers = query.map do |q|
|
499
|
+
q.map {|i| row.grep(/#{i}/i)[0]}.compact[0]
|
500
|
+
end.compact
|
501
|
+
|
502
|
+
if headers.length == query.length
|
503
|
+
@header_line = line_no
|
504
|
+
return return_headers ? headers : line_no
|
505
|
+
elsif line_no > 100
|
506
|
+
raise "Couldn't find header row."
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
# this method lets you find the worksheet with the most data
|
512
|
+
def longest_sheet
|
513
|
+
sheet(@workbook.worksheets.inject {|m,o|
|
514
|
+
o.row_count > m.row_count ? o : m
|
515
|
+
}.name)
|
516
|
+
end
|
517
|
+
|
466
518
|
protected
|
467
519
|
|
468
|
-
def file_type_check(filename, ext, name, packed=nil)
|
520
|
+
def file_type_check(filename, ext, name, warning_level, packed=nil)
|
469
521
|
new_expression = {
|
470
|
-
'.ods' => 'Openoffice.new',
|
471
|
-
'.xls' => 'Excel.new',
|
472
|
-
'.xlsx' => 'Excelx.new',
|
473
|
-
'.csv' => 'Csv.new',
|
522
|
+
'.ods' => 'Roo::Openoffice.new',
|
523
|
+
'.xls' => 'Roo::Excel.new',
|
524
|
+
'.xlsx' => 'Roo::Excelx.new',
|
525
|
+
'.csv' => 'Roo::Csv.new',
|
474
526
|
}
|
475
527
|
if packed == :zip
|
476
528
|
# lalala.ods.zip => lalala.ods
|
@@ -480,12 +532,12 @@ class GenericSpreadsheet
|
|
480
532
|
end
|
481
533
|
case ext
|
482
534
|
when '.ods', '.xls', '.xlsx', '.csv'
|
483
|
-
correct_class = "use #{new_expression[ext]} to handle #{ext} spreadsheet files"
|
535
|
+
correct_class = "use #{new_expression[ext]} to handle #{ext} spreadsheet files. This has #{File.extname(filename).downcase}"
|
484
536
|
else
|
485
537
|
raise "unknown file type: #{ext}"
|
486
538
|
end
|
487
539
|
if File.extname(filename).downcase != ext
|
488
|
-
case
|
540
|
+
case warning_level
|
489
541
|
when :error
|
490
542
|
warn correct_class
|
491
543
|
raise TypeError, "#{filename} is not #{name} file"
|
@@ -495,7 +547,7 @@ class GenericSpreadsheet
|
|
495
547
|
when :ignore
|
496
548
|
# ignore
|
497
549
|
else
|
498
|
-
raise "#{
|
550
|
+
raise "#{warning_level} illegal state of file_warning"
|
499
551
|
end
|
500
552
|
end
|
501
553
|
end
|
@@ -506,9 +558,7 @@ class GenericSpreadsheet
|
|
506
558
|
# Zugriff mit numerischen Keys schneller ist.
|
507
559
|
def key_to_num(str)
|
508
560
|
r,c = str.split(',')
|
509
|
-
r
|
510
|
-
c = c.to_i
|
511
|
-
[r,c]
|
561
|
+
[r.to_i,c.to_i]
|
512
562
|
end
|
513
563
|
|
514
564
|
# see: key_to_num
|
@@ -518,6 +568,47 @@ class GenericSpreadsheet
|
|
518
568
|
|
519
569
|
private
|
520
570
|
|
571
|
+
def make_tmpdir(tmp_root = nil)
|
572
|
+
Dir.mktmpdir(TEMP_PREFIX, tmp_root || ENV['ROO_TMP']) do |tmpdir|
|
573
|
+
yield tmpdir
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
def clean_sheet(sheet)
|
578
|
+
read_cells(sheet) unless @cells_read[sheet]
|
579
|
+
@cell[sheet].each_pair do |coord,value|
|
580
|
+
if String === value
|
581
|
+
@cell[sheet][coord] = sanitize_value(value)
|
582
|
+
end
|
583
|
+
end
|
584
|
+
@cleaned[sheet] = true
|
585
|
+
end
|
586
|
+
|
587
|
+
def sanitize_value(v)
|
588
|
+
v.strip.unpack('U*').select {|b| b < 127}.pack('U*')
|
589
|
+
end
|
590
|
+
|
591
|
+
def set_headers(hash={})
|
592
|
+
# try to find header row with all values or give an error
|
593
|
+
# then create new hash by indexing strings and keeping integers for header array
|
594
|
+
@headers = row_with(hash.values,true)
|
595
|
+
@headers = Hash[hash.keys.zip(@headers.map {|x| header_index(x)})]
|
596
|
+
end
|
597
|
+
|
598
|
+
def header_index(query)
|
599
|
+
row(@header_line).index(query) + first_column
|
600
|
+
end
|
601
|
+
|
602
|
+
def set_value(row,col,value,sheet=nil)
|
603
|
+
sheet ||= @default_sheet
|
604
|
+
@cell[sheet][[row,col]] = value
|
605
|
+
end
|
606
|
+
|
607
|
+
def set_type(row,col,type,sheet=nil)
|
608
|
+
sheet ||= @default_sheet
|
609
|
+
@cell_type[sheet][[row,col]] = type
|
610
|
+
end
|
611
|
+
|
521
612
|
# converts cell coordinate to numeric values of row,col
|
522
613
|
def normalize(row,col)
|
523
614
|
if row.class == String
|
@@ -530,43 +621,57 @@ class GenericSpreadsheet
|
|
530
621
|
end
|
531
622
|
end
|
532
623
|
if col.class == String
|
533
|
-
col = GenericSpreadsheet.letter_to_number(col)
|
624
|
+
col = Roo::GenericSpreadsheet.letter_to_number(col)
|
534
625
|
end
|
535
626
|
return row,col
|
536
627
|
end
|
537
628
|
|
538
|
-
def
|
629
|
+
def uri?(filename)
|
630
|
+
filename.start_with?("http://", "https://")
|
631
|
+
end
|
632
|
+
|
633
|
+
def open_from_uri(uri, tmpdir)
|
539
634
|
require 'open-uri'
|
540
635
|
response = ''
|
541
636
|
begin
|
542
637
|
open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") { |net|
|
543
638
|
response = net.read
|
544
|
-
tempfilename = File.join(
|
545
|
-
|
546
|
-
|
547
|
-
|
639
|
+
tempfilename = File.join(tmpdir, File.basename(uri))
|
640
|
+
File.open(tempfilename,"wb") do |file|
|
641
|
+
file.write(response)
|
642
|
+
end
|
548
643
|
}
|
549
644
|
rescue OpenURI::HTTPError
|
550
645
|
raise "could not open #{uri}"
|
551
646
|
end
|
552
|
-
File.join(
|
647
|
+
File.join(tmpdir, File.basename(uri))
|
553
648
|
end
|
554
|
-
|
555
|
-
def open_from_stream(stream)
|
556
|
-
tempfilename = File.join(
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
File.join(
|
649
|
+
|
650
|
+
def open_from_stream(stream, tmpdir)
|
651
|
+
tempfilename = File.join(tmpdir, "spreadsheet")
|
652
|
+
File.open(tempfilename,"wb") do |file|
|
653
|
+
file.write(stream[7..-1])
|
654
|
+
end
|
655
|
+
File.join(tmpdir, "spreadsheet")
|
561
656
|
end
|
562
657
|
|
658
|
+
LETTERS = %w{A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
|
659
|
+
|
563
660
|
# convert a number to something like 'AB' (1 => 'A', 2 => 'B', ...)
|
564
661
|
def self.number_to_letter(n)
|
565
662
|
letters=""
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
663
|
+
if n > 26
|
664
|
+
while n % 26 == 0 && n != 0
|
665
|
+
letters << 'Z'
|
666
|
+
n = (n - 26) / 26
|
667
|
+
end
|
668
|
+
while n > 0
|
669
|
+
num = n%26
|
670
|
+
letters = LETTERS[num-1] + letters
|
671
|
+
n = (n / 26)
|
672
|
+
end
|
673
|
+
else
|
674
|
+
letters = LETTERS[n-1]
|
570
675
|
end
|
571
676
|
letters
|
572
677
|
end
|
@@ -576,7 +681,7 @@ class GenericSpreadsheet
|
|
576
681
|
result = 0
|
577
682
|
while letters && letters.length > 0
|
578
683
|
character = letters[0,1].upcase
|
579
|
-
num =
|
684
|
+
num = LETTERS.index(character)
|
580
685
|
raise ArgumentError, "invalid column character '#{letters[0,1]}'" if num == nil
|
581
686
|
num += 1
|
582
687
|
result = result * 26 + num
|
@@ -585,106 +690,105 @@ class GenericSpreadsheet
|
|
585
690
|
result
|
586
691
|
end
|
587
692
|
|
588
|
-
def unzip(filename)
|
589
|
-
ret = nil
|
693
|
+
def unzip(filename, tmpdir)
|
590
694
|
Zip::ZipFile.open(filename) do |zip|
|
591
|
-
|
695
|
+
process_zipfile_packed(zip, tmpdir)
|
592
696
|
end
|
593
|
-
ret
|
594
697
|
end
|
595
698
|
|
596
699
|
# check if default_sheet was set and exists in sheets-array
|
597
|
-
def
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
700
|
+
def validate_sheet!(sheet)
|
701
|
+
case sheet
|
702
|
+
when nil
|
703
|
+
raise ArgumentError, "Error: sheet 'nil' not valid"
|
704
|
+
when Fixnum
|
705
|
+
self.sheets.fetch(sheet-1) do
|
706
|
+
raise RangeError, "sheet index #{sheet} not found"
|
707
|
+
end
|
708
|
+
when String
|
709
|
+
if !sheets.include? sheet
|
710
|
+
raise RangeError, "sheet '#{sheet}' not found"
|
711
|
+
end
|
712
|
+
else
|
713
|
+
raise TypeError, "not a valid sheet type: #{sheet.inspect}"
|
605
714
|
end
|
606
715
|
end
|
607
716
|
|
608
|
-
def process_zipfile_packed(zip, path='')
|
609
|
-
ret=nil
|
717
|
+
def process_zipfile_packed(zip, tmpdir, path='')
|
610
718
|
if zip.file.file? path
|
611
719
|
# extract and return filename
|
612
|
-
|
613
|
-
|
614
|
-
file.close
|
615
|
-
return File.join(@tmpdir, path)
|
616
|
-
else
|
617
|
-
unless path.empty?
|
618
|
-
path += '/'
|
720
|
+
File.open(File.join(tmpdir, path),"wb") do |file|
|
721
|
+
file.write(zip.read(path))
|
619
722
|
end
|
723
|
+
File.join(tmpdir, path)
|
724
|
+
else
|
725
|
+
ret=nil
|
726
|
+
path += '/' unless path.empty?
|
620
727
|
zip.dir.foreach(path) do |filename|
|
621
|
-
ret = process_zipfile_packed(zip, path + filename)
|
728
|
+
ret = process_zipfile_packed(zip, tmpdir, path + filename)
|
622
729
|
end
|
730
|
+
ret
|
623
731
|
end
|
624
|
-
ret
|
625
732
|
end
|
626
733
|
|
627
734
|
# Write all cells to the csv file. File can be a filename or nil. If the this
|
628
735
|
# parameter is nil the output goes to STDOUT
|
629
736
|
def write_csv_content(file=nil,sheet=nil)
|
630
|
-
file
|
737
|
+
file ||= STDOUT
|
631
738
|
if first_row(sheet) # sheet is not empty
|
632
739
|
1.upto(last_row(sheet)) do |row|
|
633
740
|
1.upto(last_column(sheet)) do |col|
|
634
741
|
file.print(",") if col > 1
|
635
|
-
|
636
|
-
onecelltype = celltype(row,col,sheet)
|
637
|
-
file.print one_cell_output(onecelltype,onecell,empty?(row,col,sheet))
|
742
|
+
file.print cell_to_csv(row,col,sheet)
|
638
743
|
end
|
639
744
|
file.print("\n")
|
640
745
|
end # sheet not empty
|
641
746
|
end
|
642
747
|
end
|
643
748
|
|
644
|
-
# The content of a cell in the csv output
|
645
|
-
def
|
646
|
-
|
647
|
-
|
648
|
-
str += ''
|
749
|
+
# The content of a cell in the csv output
|
750
|
+
def cell_to_csv(row, col, sheet)
|
751
|
+
if empty?(row,col,sheet)
|
752
|
+
''
|
649
753
|
else
|
650
|
-
|
754
|
+
onecell = cell(row,col,sheet)
|
755
|
+
|
756
|
+
case celltype(row,col,sheet)
|
651
757
|
when :string
|
652
758
|
unless onecell.empty?
|
653
|
-
|
654
|
-
str << ('"'+one+'"')
|
759
|
+
%{"#{onecell.gsub(/"/,'""')}"}
|
655
760
|
end
|
656
761
|
when :float, :percentage
|
657
762
|
if onecell == onecell.to_i
|
658
|
-
|
763
|
+
onecell.to_i.to_s
|
659
764
|
else
|
660
|
-
|
765
|
+
onecell.to_s
|
661
766
|
end
|
662
767
|
when :formula
|
663
|
-
|
768
|
+
case onecell
|
769
|
+
when String
|
664
770
|
unless onecell.empty?
|
665
|
-
|
666
|
-
str << '"'+one+'"'
|
771
|
+
%{"#{onecell.gsub(/"/,'""')}"}
|
667
772
|
end
|
668
|
-
|
773
|
+
when Float
|
669
774
|
if onecell == onecell.to_i
|
670
|
-
|
775
|
+
onecell.to_i.to_s
|
671
776
|
else
|
672
|
-
|
777
|
+
onecell.to_s
|
673
778
|
end
|
779
|
+
when DateTime
|
780
|
+
onecell.to_s
|
674
781
|
else
|
675
|
-
raise "unhandled onecell-class
|
782
|
+
raise "unhandled onecell-class #{onecell.class}"
|
676
783
|
end
|
677
|
-
when :date
|
678
|
-
|
784
|
+
when :date, :datetime
|
785
|
+
onecell.to_s
|
679
786
|
when :time
|
680
|
-
|
681
|
-
when :datetime
|
682
|
-
str << onecell.to_s
|
787
|
+
Roo::GenericSpreadsheet.integer_to_timestring(onecell)
|
683
788
|
else
|
684
|
-
raise "unhandled celltype "
|
685
|
-
end
|
789
|
+
raise "unhandled celltype #{celltype(row,col,sheet)}"
|
790
|
+
end || ""
|
686
791
|
end
|
687
|
-
str
|
688
792
|
end
|
689
793
|
|
690
794
|
# converts an integer value to a time string like '02:05:06'
|
@@ -696,5 +800,4 @@ class GenericSpreadsheet
|
|
696
800
|
s = content
|
697
801
|
sprintf("%02d:%02d:%02d",h,m,s)
|
698
802
|
end
|
699
|
-
|
700
803
|
end
|