roo 0.7.0 → 0.8.0
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 +4 -0
- data/Manifest.txt +2 -0
- data/README.txt +0 -1
- data/Rakefile +12 -2
- data/examples/write_me.rb +33 -0
- data/lib/roo.rb +1 -0
- data/lib/roo/excel.rb +53 -94
- data/lib/roo/generic_spreadsheet.rb +303 -0
- data/lib/roo/google.rb +667 -152
- data/lib/roo/openoffice.rb +13 -259
- data/lib/roo/version.rb +1 -1
- data/test/test_roo.rb +898 -453
- data/website/index.html +74 -11
- data/website/index.txt +52 -9
- metadata +6 -4
data/lib/roo/google.rb
CHANGED
@@ -1,99 +1,180 @@
|
|
1
|
+
require 'rubygems' #TODO:
|
2
|
+
require 'gdata/spreadsheet'
|
3
|
+
#require 'log4r'
|
1
4
|
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# def initialize(address, port = nil)
|
15
|
-
# super(address, port)
|
16
|
-
# self.use_ssl = true
|
17
|
-
# end
|
18
|
-
# end
|
19
|
-
#end
|
20
|
-
#
|
21
|
-
#class GoogleSpreadSheet
|
22
|
-
# GOOGLE_LOGIN_URL = URI.parse('https://www.google.com/accounts/ClientLogin')
|
23
|
-
#
|
24
|
-
# def initialize(spreadsheet_key)
|
25
|
-
# @spreadsheet_key = spreadsheet_key
|
26
|
-
# @headers = nil
|
27
|
-
# @default_sheet = nil
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# def default_sheet=(numberofsheet)
|
31
|
-
# @default_sheet = numberofsheet
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# def authenticate(email, password)
|
35
|
-
# $VERBOSE = nil
|
36
|
-
# response = Net::HTTPS.post_form(GOOGLE_LOGIN_URL,
|
37
|
-
# {'Email' => email,
|
38
|
-
# 'Passwd' => password,
|
39
|
-
# 'source' => "formula",
|
40
|
-
# 'service' => 'wise' })
|
41
|
-
# @headers = { 'Authorization' => "GoogleLogin auth=#{response.body.split(/=/).last}",
|
42
|
-
# 'Content-Type' => 'application/atom+xml'
|
43
|
-
# }
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# def evaluate_cell(cell)
|
47
|
-
# path = "/feeds/cells/#{@spreadsheet_key}/#{@default_sheet}/#{@headers ? "private" : "public"}/basic/#{cell}"
|
48
|
-
#
|
49
|
-
# doc = Hpricot(request(path))
|
50
|
-
# result = (doc/"content[@type='text']").inner_html
|
51
|
-
# end
|
52
|
-
#
|
53
|
-
# def set_entry(entry)
|
54
|
-
# path = "/feeds/cells/#{@spreadsheet_key}/#{@default_sheet}/#{@headers ? 'private' : 'public'}/full"
|
55
|
-
#
|
56
|
-
# post(path, entry)
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# def entry(formula, row=1, col=1)
|
60
|
-
# <<XML
|
61
|
-
#<?xml version='1.0' ?>
|
62
|
-
#<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gs='http://schemas.google.com/spreadsheets/2006'>
|
63
|
-
# <gs:cell row='#{row}' col='#{col}' inputValue='=#{formula}' />
|
64
|
-
#</entry>
|
65
|
-
#XML
|
66
|
-
# end
|
67
|
-
#
|
68
|
-
# def add_to_cell(formula) #puts entry(formula)
|
69
|
-
# set_entry(entry(formula))
|
70
|
-
# end
|
71
|
-
#
|
72
|
-
# private
|
73
|
-
# def request(path)
|
74
|
-
# response, data = get_http.get(path, @headers)
|
75
|
-
# data
|
76
|
-
# end
|
77
|
-
#
|
78
|
-
# def post(path, entry)
|
79
|
-
# get_http.post(path, entry, @headers)
|
80
|
-
# end
|
81
|
-
#
|
82
|
-
# def get_http
|
83
|
-
# http = Net::HTTP.new('spreadsheets.google.com', 80)
|
84
|
-
# #http.set_debug_output $stderr
|
85
|
-
# http
|
86
|
-
# end
|
87
|
-
#end
|
5
|
+
# overwrite some methods from the gdata-gem:
|
6
|
+
module GData
|
7
|
+
class Spreadsheet < GData::Base
|
8
|
+
#-- modified
|
9
|
+
def evaluate_cell(cell, sheet_no=1)
|
10
|
+
raise ArgumentError, "invalid cell: #{cell}" unless cell
|
11
|
+
raise ArgumentError, "invalid sheet_no: #{sheet_no}" unless sheet_no >0 and sheet_no.class == Fixnum
|
12
|
+
path = "/feeds/cells/#{@spreadsheet_id}/#{sheet_no}/#{@headers ? "private" : "public"}/basic/#{cell}"
|
13
|
+
|
14
|
+
doc = Hpricot(request(path))
|
15
|
+
result = (doc/"content").inner_html
|
16
|
+
end
|
88
17
|
|
89
|
-
|
18
|
+
#-- new
|
19
|
+
def sheetlist
|
20
|
+
path = "/feeds/worksheets/#{@spreadsheet_id}/private/basic"
|
21
|
+
doc = Hpricot(request(path))
|
22
|
+
result = []
|
23
|
+
(doc/"content").each { |elem|
|
24
|
+
result << elem.inner_html
|
25
|
+
}
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
# #-- new (testing only)
|
30
|
+
# def raw_url(url)
|
31
|
+
# path = "/feeds/worksheets/#{@spreadsheet_id}/private/basic"
|
32
|
+
# path = url
|
33
|
+
# doc = Hpricot(request(path))
|
34
|
+
# end
|
35
|
+
|
36
|
+
#-- new
|
37
|
+
def save_entry_roo(entry)
|
38
|
+
path = "/feeds/cells/#{@spreadsheet_id}/1/#{@headers ? 'private' : 'public'}/full"
|
39
|
+
post(path, entry)
|
40
|
+
end
|
41
|
+
|
42
|
+
#-- new
|
43
|
+
def entry_roo(formula, row=1, col=1)
|
44
|
+
<<XML
|
45
|
+
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gs='http://schemas.google.com/spreadsheets/2006'>
|
46
|
+
<gs:cell row='#{row}' col='#{col}' inputValue='#{formula}' />
|
47
|
+
</entry>
|
48
|
+
XML
|
49
|
+
end
|
50
|
+
|
51
|
+
#-- new
|
52
|
+
def add_to_cell_roo(row,col,value)
|
53
|
+
save_entry_roo(entry_roo(value,row,col))
|
54
|
+
end
|
55
|
+
|
56
|
+
#-- new
|
57
|
+
def get_one_sheet
|
58
|
+
ath = "/feeds/worksheets/#{@spreadsheet_id}/private/basic"
|
59
|
+
path = "/feeds/cells/#{@spreadsheet_id}/1/private/full"
|
60
|
+
doc = Hpricot(request(path))
|
61
|
+
#pp doc
|
62
|
+
#p doc # TODO:prey:
|
63
|
+
# result = (doc/"content[@type='text']").inner_html
|
64
|
+
# p (doc/"content").inner_html
|
65
|
+
#result = (doc/"content").inner_html.each { |item| item + '#'}
|
66
|
+
#-- result = []
|
67
|
+
#-- (doc/"content").each { |elem|
|
68
|
+
#-- #p elem
|
69
|
+
#-- result << elem.inner_html
|
70
|
+
#-- }
|
71
|
+
#-- result
|
72
|
+
end
|
73
|
+
|
74
|
+
#new
|
75
|
+
def oben_unten_links_rechts(sheet_no)
|
76
|
+
#sheet_no = sheets.index(sheet) + 1
|
77
|
+
path = "/feeds/cells/#{@spreadsheet_id}/#{sheet_no}/private/full"
|
78
|
+
doc = Hpricot(request(path))
|
79
|
+
#(doc/"entry").each {|item|
|
80
|
+
rows = []
|
81
|
+
cols = []
|
82
|
+
(doc/"gs:cell").each {|item|
|
83
|
+
# p item
|
84
|
+
#p item['row']
|
85
|
+
rows.push item['row'].to_i
|
86
|
+
#p item['col']
|
87
|
+
cols.push item['col'].to_i
|
88
|
+
}
|
89
|
+
# $log.debug("row min: #{rows.min}")
|
90
|
+
# $log.debug("row max: #{rows.max}")
|
91
|
+
# $log.debug("col min: #{cols.min}")
|
92
|
+
# $log.debug("col max: #{cols.max}")
|
93
|
+
return rows.min, rows.max, cols.min, cols.max
|
94
|
+
end
|
95
|
+
|
96
|
+
def fulldoc(sheet_no)
|
97
|
+
path = "/feeds/cells/#{@spreadsheet_id}/#{sheet_no}/private/full"
|
98
|
+
doc = Hpricot(request(path))
|
99
|
+
return doc
|
100
|
+
#(doc/"entry").each {|item|
|
101
|
+
rows = []
|
102
|
+
cols = []
|
103
|
+
(doc/"gs:cell").each {|item|
|
104
|
+
# p item
|
105
|
+
#p item['row']
|
106
|
+
rows.push item['row'].to_i
|
107
|
+
#p item['col']
|
108
|
+
cols.push item['col'].to_i
|
109
|
+
}
|
110
|
+
# $log.debug("row min: #{rows.min}")
|
111
|
+
# $log.debug("row max: #{rows.max}")
|
112
|
+
# $log.debug("col min: #{cols.min}")
|
113
|
+
# $log.debug("col max: #{cols.max}")
|
114
|
+
return rows.min, rows.max, cols.min, cols.max
|
115
|
+
end
|
116
|
+
end # class
|
117
|
+
end # module
|
90
118
|
|
91
|
-
|
119
|
+
class Google < GenericSpreadsheet
|
120
|
+
#include Log4r
|
121
|
+
|
122
|
+
attr_accessor :header_line
|
92
123
|
|
93
|
-
|
94
|
-
|
124
|
+
# TIMEOUT_IN_SECONDS = 42
|
125
|
+
# GOOGLE_MAX_ROWS = 99
|
126
|
+
# GOOGLE_MAX_COLS = 10 # TODO:
|
127
|
+
|
128
|
+
# Creates a new Google spreadsheet object.
|
129
|
+
def initialize(spreadsheetkey,user=nil,password=nil)
|
130
|
+
@filename = spreadsheetkey
|
131
|
+
# $log = Logger.new("my_log")
|
132
|
+
# $log.outputters = FileOutputter.new("f1", :filename => "roo.log")
|
133
|
+
|
134
|
+
# $log.debug("created a new Google-object")
|
135
|
+
@spreadsheetkey = spreadsheetkey
|
136
|
+
@user = user
|
137
|
+
@password = password
|
138
|
+
unless user
|
139
|
+
user = ENV['GOOGLE_MAIL']
|
140
|
+
end
|
141
|
+
unless password
|
142
|
+
password = ENV['GOOGLE_PASSWORD']
|
143
|
+
end
|
144
|
+
#p spreadsheetkey
|
145
|
+
#p user
|
146
|
+
#p password
|
147
|
+
#spreadsheetkey = ENV['GOOGLE_KEY']
|
148
|
+
@default_sheet = nil
|
95
149
|
@cell = Hash.new
|
96
150
|
@cell_type = Hash.new
|
151
|
+
@formula = Hash.new
|
152
|
+
@first_row = Hash.new
|
153
|
+
@last_row = Hash.new
|
154
|
+
@first_column = Hash.new
|
155
|
+
@last_column = Hash.new
|
156
|
+
@cells_read = Hash.new
|
157
|
+
@header_line = 1
|
158
|
+
#??? @sheets = Array.new
|
159
|
+
|
160
|
+
@gs = GData::Spreadsheet.new(spreadsheetkey)
|
161
|
+
#@column = FromGData::Spreadsheet.new(spreadsheetkey)
|
162
|
+
@gs.authenticate(user, password)
|
163
|
+
|
164
|
+
#--Test only
|
165
|
+
#@gs.get_one_sheet
|
166
|
+
#@gs.oben_unten_links_rechts
|
167
|
+
#--
|
168
|
+
#-- ----------------------------------------------------------------------
|
169
|
+
#-- Behandlung von Berechtigungen hier noch einbauen
|
170
|
+
#-- ----------------------------------------------------------------------
|
171
|
+
|
172
|
+
#result = gs.add_to_cell formula
|
173
|
+
#puts gs.evaluate_cell('A1')
|
174
|
+
#p gs.evaluate_cell('A1')
|
175
|
+
#puts gs.evaluate_cell('A2')
|
176
|
+
#puts gs.evaluate_cell('A3')
|
177
|
+
|
97
178
|
#Timeout.timeout(TIMEOUT_IN_SECONDS) {
|
98
179
|
# @gs = GoogleSpreadSheet.new(spreadsheetkey)
|
99
180
|
# @gs.authenticate(user, password)
|
@@ -105,90 +186,524 @@ class Google < Openoffice #:nodoc:
|
|
105
186
|
# @spreadsheet= spreadsheet[spreadsheetname]
|
106
187
|
|
107
188
|
#gb = GData::Base.new
|
108
|
-
#gb.authenticate("thopre@gmail.com","
|
189
|
+
#gb.authenticate("thopre@gmail.com","secret")
|
109
190
|
|
110
|
-
g = GData::Spreadsheet.new("ttt")
|
111
|
-
|
191
|
+
#g = GData::Spreadsheet.new("ttt")
|
192
|
+
#@default_sheet = nil
|
193
|
+
if self.sheets.size == 1
|
194
|
+
@default_sheet = self.sheets.first
|
195
|
+
end
|
112
196
|
end
|
113
197
|
|
198
|
+
#def gssheetlist
|
199
|
+
# @gs.sheetlist
|
200
|
+
#end
|
201
|
+
|
202
|
+
# returns an array of sheet names in the spreadsheet
|
114
203
|
def sheets
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
@spreadsheet
|
204
|
+
#if @sheets == []
|
205
|
+
# @sheets = @gs.sheetlist
|
206
|
+
#end
|
207
|
+
#return @sheets
|
208
|
+
#p gssheetlist
|
209
|
+
return @gs.sheetlist
|
122
210
|
end
|
123
211
|
|
124
|
-
def
|
125
|
-
|
212
|
+
#def reload
|
213
|
+
# sav_default_sheet = default_sheet
|
214
|
+
# super
|
215
|
+
# @sheets = sheets #[]
|
216
|
+
# puts "DEBUG: reload: erneutes Einlesen ergibt @sheets=#{@sheets.to_s}"
|
217
|
+
# @default_sheet = sav_default_sheet
|
218
|
+
#end
|
219
|
+
|
220
|
+
# set the working sheet in the document
|
221
|
+
#--
|
222
|
+
# TODO: eigenlich identisch mit Openoffice => refactoring
|
223
|
+
def default_sheet=(sheet)
|
224
|
+
#puts "DEBUG: default_sheet=#{sheet}"
|
225
|
+
if ! sheet.kind_of?(String)
|
226
|
+
raise TypeError, "what are you trying to set as default sheet?"
|
227
|
+
end
|
228
|
+
@default_sheet = sheet
|
229
|
+
check_default_sheet
|
230
|
+
@first_row[sheet] = @last_row[sheet] = @first_column[sheet] = @last_column[sheet] = nil
|
231
|
+
#--TODO: @cells_read[sheet] = false
|
232
|
+
end
|
233
|
+
|
234
|
+
# is String a date with format DD/MM/YYYY
|
235
|
+
def Google.date?(string)
|
236
|
+
return false if string.class == Float
|
237
|
+
return true if string.class == Date
|
238
|
+
return string.strip =~ /^([0-9]+)\/([0-9]+)\/([0-9]+)$/
|
126
239
|
end
|
127
240
|
|
128
|
-
|
241
|
+
# Returns the content of a spreadsheet-cell.
|
242
|
+
# (1,1) is the upper left corner.
|
243
|
+
# (1,1), (1,'A'), ('A',1), ('a',1) all refers to the
|
244
|
+
# cell at the first line and first row.
|
245
|
+
def cell(row, col, sheet=nil)
|
246
|
+
sheet = @default_sheet unless sheet
|
247
|
+
check_default_sheet #TODO: 2007-12-16
|
248
|
+
read_cells(sheet) unless @cells_read[sheet]
|
129
249
|
row,col = normalize(row,col)
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
250
|
+
|
251
|
+
if celltype(row,col,sheet) == :date
|
252
|
+
# $log.debug("splitte Datumsfeld auf (#{row},#{col}): #{ @cell[sheet]["#{row},#{col}"]}")
|
253
|
+
yyyy,mm,dd = @cell[sheet]["#{row},#{col}"].split('-')
|
254
|
+
# $log.debug(yyyy)
|
255
|
+
# $log.debug(mm)
|
256
|
+
# $log.debug(dd)
|
257
|
+
#TODO:
|
258
|
+
if dd.to_i < 1 or dd.to_i >31 or mm.to_i < 1 or mm.to_i > 12 or yyyy.to_i < 1900 or yyyy.to_i > 3000
|
259
|
+
raise "Invalid date parameter: #{yyyy}, #{mm}, #{dd}"
|
260
|
+
end
|
261
|
+
return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
|
262
|
+
end
|
263
|
+
return @cell[sheet]["#{row},#{col}"]
|
264
|
+
end
|
265
|
+
|
266
|
+
# returns the type of a cell:
|
267
|
+
# * :float
|
268
|
+
# * :string,
|
269
|
+
# * :date
|
270
|
+
# * :percentage
|
271
|
+
def celltype(row, col, sheet=nil)
|
272
|
+
sheet = @default_sheet unless sheet
|
273
|
+
read_cells(sheet) unless @cells_read[sheet]
|
274
|
+
row,col = normalize(row,col)
|
275
|
+
if @formula[sheet]["#{row},#{col}"]
|
276
|
+
return :formula
|
277
|
+
else
|
278
|
+
@cell_type[sheet]["#{row},#{col}"]
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Returns the formula at (row,col).
|
283
|
+
# Returns nil if there is no formula.
|
284
|
+
# The method #formula? checks if there is a formula.
|
285
|
+
def formula(row,col,sheet=nil)
|
286
|
+
sheet = @default_sheet unless sheet
|
287
|
+
read_cells(sheet) unless @cells_read[sheet]
|
288
|
+
row,col = normalize(row,col)
|
289
|
+
if @formula[sheet]["#{row},#{col}"] == nil
|
290
|
+
return nil
|
291
|
+
else
|
292
|
+
return @formula[sheet]["#{row},#{col}"] #TODO: ["oooc:".length..-1]
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# true, if there is a formula
|
297
|
+
def formula?(row,col,sheet=nil)
|
298
|
+
sheet = @default_sheet unless sheet
|
299
|
+
read_cells unless @cells_read[sheet]
|
300
|
+
row,col = normalize(row,col)
|
301
|
+
formula(row,col) != nil
|
302
|
+
end
|
303
|
+
|
304
|
+
# returns each formula in the selected sheet as an array of elements
|
305
|
+
# [row, col, formula]
|
306
|
+
def formulas(sheet=nil)
|
307
|
+
theformulas = Array.new
|
308
|
+
sheet = @default_sheet unless sheet
|
309
|
+
read_cells(sheet) unless @cells_read[sheet]
|
310
|
+
first_row(sheet).upto(last_row(sheet)) {|row|
|
311
|
+
first_column(sheet).upto(last_column(sheet)) {|col|
|
312
|
+
if formula?(row,col,sheet)
|
313
|
+
f = [row, col, formula(row,col,sheet)]
|
314
|
+
theformulas << f
|
315
|
+
end
|
316
|
+
}
|
317
|
+
}
|
318
|
+
theformulas
|
319
|
+
end
|
320
|
+
|
321
|
+
# # returns all values in this row as an array
|
322
|
+
# # row numbers are 1,2,3,... like in the spreadsheet
|
323
|
+
# def row_old(rownumber,sheet=nil)
|
324
|
+
# sheet = @default_sheet unless sheet
|
325
|
+
# result = []
|
326
|
+
# 1.upto(GOOGLE_MAX_ROWS) { |col| # TODO: maximum size of x-coordinate of google spreadsheet
|
327
|
+
# result[col] = cell(rownumber,col,sheet)
|
328
|
+
# }
|
329
|
+
# result = result[1..-1]
|
330
|
+
# while result[-1] == '' #TODO: besser?
|
331
|
+
# result = result[0..-2]
|
332
|
+
# end
|
333
|
+
# result
|
334
|
+
# end
|
335
|
+
|
336
|
+
# returns all values in this row as an array
|
337
|
+
# row numbers are 1,2,3,... like in the spreadsheet
|
338
|
+
def row(rownumber,sheet=nil)
|
339
|
+
sheet = @default_sheet unless sheet
|
340
|
+
read_cells(sheet) unless @cells_read[sheet]
|
341
|
+
result = []
|
342
|
+
tmp_arr = []
|
343
|
+
@cell[sheet].each_pair {|key,value|
|
344
|
+
y,x = key.split(',')
|
345
|
+
x = x.to_i
|
346
|
+
y = y.to_i
|
347
|
+
if y == rownumber
|
348
|
+
tmp_arr[x] = value
|
349
|
+
end
|
350
|
+
}
|
351
|
+
result = tmp_arr[1..-1]
|
352
|
+
while result[-1] == nil
|
353
|
+
result = result[0..-2]
|
354
|
+
end
|
355
|
+
result
|
356
|
+
end
|
357
|
+
|
358
|
+
# true, if the cell is empty
|
359
|
+
def empty?(row, col, sheet=nil)
|
360
|
+
value = cell(row, col, sheet)
|
361
|
+
return true unless value
|
362
|
+
return false if value.class == Date # a date is never empty
|
363
|
+
return false if value.class == Float
|
364
|
+
value.empty?
|
139
365
|
end
|
366
|
+
|
367
|
+
# returns all values in this column as an array
|
368
|
+
# column numbers are 1,2,3,... like in the spreadsheet
|
369
|
+
#--
|
370
|
+
#TODO: refactoring nach GenericSpreadsheet?
|
371
|
+
def column(columnnumber, sheet=nil)
|
372
|
+
if columnnumber.class == String
|
373
|
+
columnnumber = GenericSpreadsheet.letter_to_number(columnnumber)
|
374
|
+
end
|
375
|
+
sheet = @default_sheet unless sheet
|
376
|
+
read_cells(sheet) unless @cells_read[sheet]
|
377
|
+
result = []
|
378
|
+
first_row(sheet).upto(last_row(sheet)) do |row|
|
379
|
+
result << cell(row,columnnumber,sheet)
|
380
|
+
end
|
381
|
+
result
|
382
|
+
end
|
140
383
|
|
141
|
-
|
142
|
-
|
384
|
+
# sets the cell to the content of 'value'
|
385
|
+
# a formula can be set in the form of '=SUM(...)'
|
386
|
+
def set_value(row,col,value)
|
387
|
+
@gs.add_to_cell_roo(row,col,value)
|
388
|
+
end
|
389
|
+
|
390
|
+
# returns the first non-empty row in a sheet
|
391
|
+
def first_row(sheet=nil)
|
392
|
+
sheet = @default_sheet unless sheet
|
393
|
+
unless @first_row[sheet]
|
394
|
+
sheet_no = sheets.index(sheet) + 1
|
395
|
+
@first_row[sheet], @last_row[sheet], @first_column[sheet], @last_column[sheet] = @gs.oben_unten_links_rechts(sheet_no)
|
396
|
+
end
|
397
|
+
return @first_row[sheet]
|
398
|
+
end
|
399
|
+
|
400
|
+
# returns the last non-empty row in a sheet
|
401
|
+
def last_row(sheet=nil)
|
402
|
+
sheet = @default_sheet unless sheet
|
403
|
+
unless @last_row[sheet]
|
404
|
+
sheet_no = sheets.index(sheet) + 1
|
405
|
+
@first_row[sheet], @last_row[sheet], @first_column[sheet], @last_column[sheet] = @gs.oben_unten_links_rechts(sheet_no)
|
406
|
+
end
|
407
|
+
return @last_row[sheet]
|
408
|
+
end
|
409
|
+
|
410
|
+
# returns the first non-empty column in a sheet
|
411
|
+
def first_column(sheet=nil)
|
412
|
+
sheet = @default_sheet unless sheet
|
413
|
+
unless @first_column[sheet]
|
414
|
+
sheet_no = sheets.index(sheet) + 1
|
415
|
+
@first_row[sheet], @last_row[sheet], @first_column[sheet], @last_column[sheet] = @gs.oben_unten_links_rechts(sheet_no)
|
416
|
+
end
|
417
|
+
return @first_column[sheet]
|
418
|
+
end
|
419
|
+
|
420
|
+
# returns the last non-empty column in a sheet
|
421
|
+
def last_column(sheet=nil)
|
422
|
+
sheet = @default_sheet unless sheet
|
423
|
+
unless @last_column[sheet]
|
424
|
+
sheet_no = sheets.index(sheet) + 1
|
425
|
+
@first_row[sheet], @last_row[sheet], @first_column[sheet], @last_column[sheet] = @gs.oben_unten_links_rechts(sheet_no)
|
426
|
+
end
|
427
|
+
return @last_column[sheet]
|
428
|
+
end
|
429
|
+
|
430
|
+
# write the current spreadsheet to stdout or into a file
|
431
|
+
#--
|
432
|
+
#TODO: refactoring --> GenericSpreadsheet
|
433
|
+
def to_csv(filename=nil,sheet=nil)
|
434
|
+
sheet = @default_sheet unless sheet
|
435
|
+
if filename
|
436
|
+
file = File.open(filename,"w") # do |file|
|
437
|
+
write_csv_content(file,sheet)
|
438
|
+
file.close
|
439
|
+
else
|
440
|
+
write_csv_content(STDOUT,sheet)
|
441
|
+
end
|
442
|
+
true
|
143
443
|
end
|
144
444
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
#
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
445
|
+
|
446
|
+
# find a row either by row number or a condition
|
447
|
+
# Caution: this works only within the default sheet -> set default_sheet before you call this method
|
448
|
+
# (experimental. see examples in the test_roo.rb file)
|
449
|
+
#--
|
450
|
+
# -----------------------------------------------------
|
451
|
+
# !!!TODO: should be factored out to GenericSpreadsheet
|
452
|
+
# also in Openofiffe
|
453
|
+
# -----------------------------------------------------
|
454
|
+
#++
|
455
|
+
def find(*args)
|
456
|
+
result_array = false
|
457
|
+
args.each {|arg,val|
|
458
|
+
if arg.class == Hash
|
459
|
+
arg.each { |hkey,hval|
|
460
|
+
if hkey == :array and hval == true
|
461
|
+
result_array = true
|
161
462
|
end
|
162
|
-
|
463
|
+
}
|
464
|
+
end
|
465
|
+
}
|
466
|
+
column_with = {}
|
467
|
+
1.upto(last_column) do |col|
|
468
|
+
column_with[cell(@header_line,col)] = col
|
469
|
+
end
|
470
|
+
result = Array.new
|
471
|
+
#-- id
|
472
|
+
if args[0].class == Fixnum
|
473
|
+
rownum = args[0]
|
474
|
+
tmp = {}
|
475
|
+
1.upto(self.row(rownum).size) {|j|
|
476
|
+
x = ''
|
477
|
+
column_with.each { |key,val|
|
478
|
+
if val == j
|
479
|
+
x = key
|
480
|
+
end
|
481
|
+
}
|
482
|
+
tmp[x] = cell(rownum,j)
|
483
|
+
}
|
484
|
+
result = [ tmp ] # row(rownum)
|
485
|
+
#-- :all
|
486
|
+
elsif args[0] == :all
|
487
|
+
if args[1].class == Hash
|
488
|
+
args[1].each {|key,val|
|
489
|
+
if key == :conditions
|
490
|
+
column_with = {}
|
491
|
+
1.upto(last_column) do |col|
|
492
|
+
column_with[cell(@header_line,col)] = col
|
493
|
+
end
|
494
|
+
conditions = val
|
495
|
+
first_row.upto(last_row) do |i|
|
496
|
+
# are all conditions met?
|
497
|
+
found = 1
|
498
|
+
conditions.each { |key,val|
|
499
|
+
if cell(i,column_with[key]) == val
|
500
|
+
found *= 1
|
501
|
+
else
|
502
|
+
found *= 0
|
503
|
+
end
|
504
|
+
}
|
505
|
+
# p self.row(i) if found > 0
|
506
|
+
if found > 0
|
507
|
+
tmp = {}
|
508
|
+
1.upto(self.row(i).size) {|j|
|
509
|
+
x = ''
|
510
|
+
column_with.each { |key,val|
|
511
|
+
if val == j
|
512
|
+
x = key
|
513
|
+
end
|
514
|
+
}
|
515
|
+
tmp[x] = cell(i,j)
|
516
|
+
}
|
517
|
+
if result_array
|
518
|
+
result << self.row(i)
|
519
|
+
else
|
520
|
+
result << tmp
|
521
|
+
end
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end # :conditions
|
525
|
+
}
|
163
526
|
end
|
164
|
-
|
165
527
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
528
|
+
result
|
529
|
+
end
|
530
|
+
private
|
531
|
+
|
532
|
+
# def read_cells_old(sheet=nil) #TODO:
|
533
|
+
# sheet = @default_sheet unless sheet
|
534
|
+
# sheet_found = true # TODO:
|
535
|
+
# #TODO: raise ArgumentError falls sheet nicht existiert - siehe openoffice
|
536
|
+
# #TODO: boundaries !!!
|
537
|
+
# 1.upto(25) { |y|
|
538
|
+
# 1.upto(20) { |x|
|
539
|
+
# key = "#{y},#{x}"
|
540
|
+
# @cell[sheet] = {} unless @cell[sheet]
|
541
|
+
# value = cell(y,x,sheet)
|
542
|
+
# @cell[sheet][key] = value unless value == "" or value == nil
|
543
|
+
# }
|
544
|
+
# }
|
545
|
+
# if !sheet_found
|
546
|
+
# raise RangeErrror, "invalid sheet name"
|
547
|
+
# end
|
548
|
+
# @cells_read[sheet] = true
|
549
|
+
# end
|
170
550
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
551
|
+
# read all cells in a sheet
|
552
|
+
def read_cells(sheet=nil)
|
553
|
+
sheet = @default_sheet unless sheet
|
554
|
+
# sheet_no = sheets.index(sheet) + 1
|
555
|
+
# @first_row[sheet], @last_row[sheet], @first_column[sheet], @last_column[sheet] = @gs.oben_unten_links_rechts(sheet_no)
|
556
|
+
#@first_row[sheet].upto(@last_row[sheet]) { |y|
|
557
|
+
# @first_column[sheet].upto(@last_column[sheet]) { |x|
|
558
|
+
# key = "#{y},#{x}"
|
559
|
+
# @cell[sheet] = {} unless @cell[sheet]
|
560
|
+
# value = cell(y,x,sheet)
|
561
|
+
# @cell[sheet][key] = value unless value == "" or value == nil
|
562
|
+
# }
|
563
|
+
#}
|
564
|
+
sheet_no = sheets.index(sheet)+1
|
565
|
+
doc = @gs.fulldoc(sheet_no)
|
566
|
+
(doc/"gs:cell").each {|item|
|
567
|
+
row = item['row']
|
568
|
+
col = item['col']
|
569
|
+
value = item['inputvalue']
|
570
|
+
numericvalue = item['numericvalue']
|
571
|
+
# puts numericvalue
|
572
|
+
# puts value
|
573
|
+
# puts value[0,1]
|
574
|
+
if value[0,1] == '='
|
575
|
+
formula = value
|
576
|
+
# $log.debug("formula: <#{formula}>")
|
577
|
+
# puts "Formel gefunden"
|
578
|
+
else
|
579
|
+
formula = nil
|
580
|
+
end
|
581
|
+
# puts formula
|
582
|
+
#--
|
583
|
+
@cell_type[sheet] = {} unless @cell_type[sheet]
|
584
|
+
if formula
|
585
|
+
ty = :formula
|
586
|
+
if numeric?(numericvalue)
|
587
|
+
value = numericvalue.to_f
|
588
|
+
else
|
589
|
+
value = numericvalue
|
590
|
+
end
|
591
|
+
elsif Google.date?(value)
|
592
|
+
ty = :date
|
593
|
+
elsif numeric?(value) # or o.class ???
|
594
|
+
ty = :float
|
595
|
+
value = value.to_f
|
596
|
+
else
|
597
|
+
ty = :string
|
598
|
+
end
|
599
|
+
key = "#{row},#{col}"
|
600
|
+
@cell[sheet] = {} unless @cell[sheet]
|
601
|
+
if ty == :date
|
602
|
+
dd,mm,yyyy = value.split('/')
|
603
|
+
@cell[sheet][key] = sprintf("%04d-%02d-%02d",yyyy.to_i,mm.to_i,dd.to_i)
|
604
|
+
else
|
605
|
+
@cell[sheet][key] = value unless value == "" or value == nil
|
179
606
|
end
|
180
|
-
|
181
|
-
|
607
|
+
@cell_type[sheet][key] = ty # Openoffice.oo_type_2_roo_type(vt)
|
608
|
+
@formula[sheet] = {} unless @formula[sheet]
|
609
|
+
# $log.debug("formula vor belegen @formula: <#{formula}>") if formula
|
610
|
+
@formula[sheet][key] = formula if formula
|
611
|
+
# $log.debug("@formula[#{sheet}][#{key}] = #{formula}") if formula
|
612
|
+
# $log.debug("#{@formula[sheet][key]}") if formula
|
613
|
+
|
614
|
+
|
615
|
+
}
|
616
|
+
@cells_read[sheet] = true
|
617
|
+
end
|
618
|
+
|
619
|
+
# Checks if the default_sheet exists. Otherwise a RangeError exception is
|
620
|
+
# raised
|
621
|
+
def check_default_sheet
|
622
|
+
sheet_found = false
|
623
|
+
raise ArgumentError, "Error: default_sheet not set" if @default_sheet == nil
|
624
|
+
if sheets.index(@default_sheet)
|
625
|
+
sheet_found = true
|
626
|
+
end
|
627
|
+
if ! sheet_found
|
628
|
+
raise RangeError, "sheet '#{@default_sheet}' not found"
|
629
|
+
end
|
182
630
|
end
|
183
631
|
|
184
|
-
def
|
185
|
-
|
186
|
-
1
|
632
|
+
def numeric?(string)
|
633
|
+
string =~ /^[0-9]+[\.]*[0-9]*$/
|
187
634
|
end
|
188
635
|
|
189
|
-
|
190
|
-
|
191
|
-
|
636
|
+
# convert string DD/MM/YYYY into a Date-object
|
637
|
+
#TODO: was ist mit verschiedenen Typen der Datumseingabe bei Google?
|
638
|
+
def Google.to_date(string)
|
639
|
+
if string.strip =~ /^([0-9]+)\/([0-9]+)\/([0-9]+)$/
|
640
|
+
return Date.new($3.to_i,$2.to_i,$1.to_i)
|
641
|
+
else
|
642
|
+
return nil
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
#TODO: refactoring to GenericSpreadsheet?
|
647
|
+
def write_csv_content(file=nil,sheet=nil)
|
648
|
+
file = STDOUT unless file
|
649
|
+
if first_row # sheet is not empty
|
650
|
+
first_row(sheet).upto(last_row(sheet)) do |row|
|
651
|
+
1.upto(last_column(sheet)) do |col|
|
652
|
+
file.print(",") if col > 1
|
653
|
+
onecell = cell(row,col,sheet)
|
654
|
+
onecelltype = celltype(row,col,sheet)
|
655
|
+
file.print one_cell_output(onecelltype,onecell,empty?(row,col,sheet))
|
656
|
+
end
|
657
|
+
file.print("\n")
|
658
|
+
end # sheet not empty
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
#TODO: refactor to Generic....
|
663
|
+
def one_cell_output(onecelltype,onecell,empty)
|
664
|
+
str = ""
|
665
|
+
if empty
|
666
|
+
str += ''
|
667
|
+
else
|
668
|
+
case onecelltype
|
669
|
+
when :string
|
670
|
+
if onecell == ""
|
671
|
+
str << ''
|
672
|
+
else
|
673
|
+
onecell.gsub!(/"/,'""')
|
674
|
+
str << ('"'+onecell+'"')
|
675
|
+
end
|
676
|
+
when :float,:percentage
|
677
|
+
if onecell == onecell.to_i
|
678
|
+
str << onecell.to_i.to_s
|
679
|
+
else
|
680
|
+
str << onecell.to_s
|
681
|
+
end
|
682
|
+
when :formula
|
683
|
+
if onecell.class == String
|
684
|
+
if onecell == ""
|
685
|
+
str << ''
|
686
|
+
else
|
687
|
+
onecell.gsub!(/"/,'""')
|
688
|
+
str << '"'+onecell+'"'
|
689
|
+
end
|
690
|
+
elsif onecell.class == Float
|
691
|
+
if onecell == onecell.to_i
|
692
|
+
str << onecell.to_i.to_s
|
693
|
+
else
|
694
|
+
str << onecell.to_s
|
695
|
+
end
|
696
|
+
else
|
697
|
+
raise "unhandled onecell-class "+onecell.class.to_s
|
698
|
+
end
|
699
|
+
when :date
|
700
|
+
str << '"'+onecell.to_s+'"'
|
701
|
+
else
|
702
|
+
raise "unhandled celltype "+onecelltype.to_s
|
703
|
+
end
|
704
|
+
end
|
705
|
+
#cells << onecell
|
706
|
+
str
|
192
707
|
end
|
193
708
|
|
194
709
|
end # class
|