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