roo 1.11.2 → 1.12.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/CHANGELOG +26 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +26 -0
- data/README.markdown +82 -62
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/examples/roo_soap_server.rb +1 -1
- data/lib/roo.rb +28 -10
- data/lib/roo/{generic_spreadsheet.rb → base.rb} +127 -159
- data/lib/roo/csv.rb +28 -30
- data/lib/roo/excel.rb +38 -48
- data/lib/roo/excel2003xml.rb +24 -36
- data/lib/roo/excelx.rb +59 -61
- data/lib/roo/google.rb +36 -59
- data/lib/roo/openoffice.rb +41 -65
- data/lib/roo/roo_rails_helper.rb +2 -1
- data/lib/roo/spreadsheet.rb +17 -8
- data/roo.gemspec +20 -8
- data/spec/fixtures/vcr_cassettes/google_drive.yml +165 -0
- data/spec/fixtures/vcr_cassettes/google_drive_access_token.yml +73 -0
- data/spec/lib/roo/base_spec.rb +7 -0
- data/spec/lib/roo/csv_spec.rb +54 -0
- data/spec/lib/roo/excel_spec.rb +17 -0
- data/spec/lib/roo/excelx_spec.rb +13 -0
- data/spec/lib/roo/google_spec.rb +36 -0
- data/spec/lib/roo/libreoffice_spec.rb +19 -0
- data/spec/lib/roo/openoffice_spec.rb +21 -0
- data/spec/lib/roo/spreadsheet_spec.rb +13 -1
- data/spec/spec_helper.rb +7 -0
- data/test/all_ss.rb +1 -1
- data/test/files/1900_base.xlsx +0 -0
- data/test/files/1904_base.xlsx +0 -0
- data/test/rm_sub_test.rb +1 -1
- data/test/test_generic_spreadsheet.rb +68 -66
- data/test/test_helper.rb +3 -84
- data/test/test_roo.rb +85 -708
- data/website/index.html +16 -16
- data/website/index.txt +42 -42
- metadata +44 -7
- data/TODO +0 -2
data/lib/roo/csv.rb
CHANGED
@@ -1,27 +1,24 @@
|
|
1
1
|
require 'csv'
|
2
2
|
require 'time'
|
3
3
|
|
4
|
-
# The
|
4
|
+
# The CSV class can read csv files (must be separated with commas) which then
|
5
5
|
# can be handled like spreadsheets. This means you can access cells like A5
|
6
6
|
# within these files.
|
7
|
-
# The
|
7
|
+
# The CSV class provides only string objects. If you want conversions to other
|
8
8
|
# types you have to do it yourself.
|
9
|
+
#
|
10
|
+
# You can pass options to the underlying CSV parse operation, via the
|
11
|
+
# :csv_options option.
|
12
|
+
#
|
9
13
|
|
10
|
-
class Roo::
|
11
|
-
def initialize(filename,
|
12
|
-
|
13
|
-
@cell = Hash.new
|
14
|
-
@cell_type = Hash.new
|
15
|
-
@cells_read = Hash.new
|
16
|
-
@first_row = Hash.new
|
17
|
-
@last_row = Hash.new
|
18
|
-
@first_column = Hash.new
|
19
|
-
@last_column = Hash.new
|
14
|
+
class Roo::CSV < Roo::Base
|
15
|
+
def initialize(filename, options = {})
|
16
|
+
super
|
20
17
|
end
|
21
18
|
|
22
19
|
attr_reader :filename
|
23
20
|
|
24
|
-
# Returns an array with the names of the sheets. In
|
21
|
+
# Returns an array with the names of the sheets. In CSV class there is only
|
25
22
|
# one dummy sheet, because a csv file cannot have more than one sheet.
|
26
23
|
def sheets
|
27
24
|
['default']
|
@@ -29,22 +26,24 @@ class Roo::Csv < Roo::GenericSpreadsheet
|
|
29
26
|
|
30
27
|
def cell(row, col, sheet=nil)
|
31
28
|
sheet ||= @default_sheet
|
32
|
-
read_cells(sheet)
|
33
|
-
|
34
|
-
@cell[[row,col]]
|
29
|
+
read_cells(sheet)
|
30
|
+
@cell[normalize(row,col)]
|
35
31
|
end
|
36
32
|
|
37
33
|
def celltype(row, col, sheet=nil)
|
38
34
|
sheet ||= @default_sheet
|
39
|
-
read_cells(sheet)
|
40
|
-
|
41
|
-
@cell_type[[row,col]]
|
35
|
+
read_cells(sheet)
|
36
|
+
@cell_type[normalize(row,col)]
|
42
37
|
end
|
43
38
|
|
44
39
|
def cell_postprocessing(row,col,value)
|
45
40
|
value
|
46
41
|
end
|
47
42
|
|
43
|
+
def csv_options
|
44
|
+
@options[:csv_options] || {}
|
45
|
+
end
|
46
|
+
|
48
47
|
private
|
49
48
|
|
50
49
|
TYPE_MAP = {
|
@@ -58,27 +57,26 @@ class Roo::Csv < Roo::GenericSpreadsheet
|
|
58
57
|
TYPE_MAP[value.class]
|
59
58
|
end
|
60
59
|
|
61
|
-
def
|
62
|
-
|
60
|
+
def each_row(options, &block)
|
61
|
+
if uri?(filename)
|
63
62
|
make_tmpdir do |tmpdir|
|
64
|
-
|
65
|
-
|
66
|
-
open_from_uri(filename, tmpdir) :
|
67
|
-
filename
|
68
|
-
) { |f| f.read }
|
63
|
+
filename = download_uri(filename, tmpdir)
|
64
|
+
CSV.foreach(filename, options, &block)
|
69
65
|
end
|
66
|
+
else
|
67
|
+
CSV.foreach(filename, options, &block)
|
68
|
+
end
|
70
69
|
end
|
71
70
|
|
72
71
|
def read_cells(sheet=nil)
|
73
72
|
sheet ||= @default_sheet
|
74
|
-
|
75
|
-
@cell = {} unless @cell
|
73
|
+
return if @cells_read[sheet]
|
76
74
|
@first_row[sheet] = 1
|
77
75
|
@last_row[sheet] = 0
|
78
76
|
@first_column[sheet] = 1
|
79
77
|
@last_column[sheet] = 1
|
80
78
|
rownum = 1
|
81
|
-
|
79
|
+
each_row csv_options do |row|
|
82
80
|
row.each_with_index do |elem,i|
|
83
81
|
@cell[[rownum,i+1]] = cell_postprocessing rownum,i+1, elem
|
84
82
|
@cell_type[[rownum,i+1]] = celltype_class @cell[[rownum,i+1]]
|
@@ -112,4 +110,4 @@ class Roo::Csv < Roo::GenericSpreadsheet
|
|
112
110
|
@last_column[sheet] -= 1
|
113
111
|
end
|
114
112
|
end
|
115
|
-
end
|
113
|
+
end
|
data/lib/roo/excel.rb
CHANGED
@@ -1,23 +1,33 @@
|
|
1
1
|
require 'spreadsheet'
|
2
|
-
#require 'lib/roo/generic_spreadsheet'
|
3
|
-
#require 'parseexcel'
|
4
|
-
CHARGUESS =
|
5
|
-
begin
|
6
|
-
require 'charguess'
|
7
|
-
true
|
8
|
-
rescue LoadError
|
9
|
-
false
|
10
|
-
end
|
11
2
|
|
12
3
|
# Class for handling Excel-Spreadsheets
|
13
|
-
class Roo::Excel < Roo::
|
4
|
+
class Roo::Excel < Roo::Base
|
5
|
+
FORMULAS_MESSAGE = 'the spreadsheet gem does not support forumulas, so roo can not.'
|
6
|
+
CHARGUESS =
|
7
|
+
begin
|
8
|
+
require 'charguess'
|
9
|
+
true
|
10
|
+
rescue LoadError
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :workbook
|
14
15
|
|
15
16
|
# Creates a new Excel spreadsheet object.
|
16
17
|
# Parameter packed: :zip - File is a zip-file
|
17
|
-
def initialize(filename,
|
18
|
+
def initialize(filename, options = {}, deprecated_file_warning = :error)
|
19
|
+
if Hash === options
|
20
|
+
packed = options[:packed]
|
21
|
+
file_warning = options[:file_warning] || :error
|
22
|
+
else
|
23
|
+
warn 'Supplying `packed` or `file_warning` as separate arguments to `Roo::Excel.new` is deprected. Use an options hash instead.'
|
24
|
+
packed = options
|
25
|
+
file_warning = deprecated_file_warning
|
26
|
+
end
|
27
|
+
|
18
28
|
file_type_check(filename,'.xls','an Excel', file_warning, packed)
|
19
29
|
make_tmpdir do |tmpdir|
|
20
|
-
filename =
|
30
|
+
filename = download_uri(filename, tmpdir) if uri?(filename)
|
21
31
|
filename = open_from_stream(filename[7..-1], tmpdir) if filename[0,7] == "stream:"
|
22
32
|
filename = unzip(filename, tmpdir) if packed == :zip
|
23
33
|
|
@@ -27,16 +37,8 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
27
37
|
end
|
28
38
|
@workbook = Spreadsheet.open(filename)
|
29
39
|
end
|
30
|
-
|
31
|
-
@cell = Hash.new
|
32
|
-
@cell_type = Hash.new
|
40
|
+
super(filename, options)
|
33
41
|
@formula = Hash.new
|
34
|
-
@first_row = Hash.new
|
35
|
-
@last_row = Hash.new
|
36
|
-
@first_column = Hash.new
|
37
|
-
@last_column = Hash.new
|
38
|
-
@header_line = 1
|
39
|
-
@cells_read = Hash.new
|
40
42
|
@fonts = Hash.new
|
41
43
|
end
|
42
44
|
|
@@ -49,12 +51,19 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
49
51
|
@workbook.worksheets.collect {|worksheet| normalize_string(worksheet.name)}
|
50
52
|
end
|
51
53
|
|
54
|
+
# this method lets you find the worksheet with the most data
|
55
|
+
def longest_sheet
|
56
|
+
sheet(@workbook.worksheets.inject {|m,o|
|
57
|
+
o.row_count > m.row_count ? o : m
|
58
|
+
}.name)
|
59
|
+
end
|
60
|
+
|
52
61
|
# returns the content of a cell. The upper left corner is (1,1) or ('A',1)
|
53
62
|
def cell(row,col,sheet=nil)
|
54
63
|
sheet ||= @default_sheet
|
55
64
|
validate_sheet!(sheet)
|
56
65
|
|
57
|
-
read_cells(sheet)
|
66
|
+
read_cells(sheet)
|
58
67
|
raise "should be read" unless @cells_read[sheet]
|
59
68
|
row,col = normalize(row,col)
|
60
69
|
if celltype(row,col,sheet) == :date
|
@@ -82,7 +91,7 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
82
91
|
# * :datetime
|
83
92
|
def celltype(row,col,sheet=nil)
|
84
93
|
sheet ||= @default_sheet
|
85
|
-
read_cells(sheet)
|
94
|
+
read_cells(sheet)
|
86
95
|
row,col = normalize(row,col)
|
87
96
|
begin
|
88
97
|
if @formula[sheet] and @formula[sheet][[row,col]]
|
@@ -98,23 +107,19 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
98
107
|
|
99
108
|
# returns NO formula in excel spreadsheets
|
100
109
|
def formula(row,col,sheet=nil)
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
# raises an exception because formulas are not supported for excel files
|
105
|
-
def formula?(row,col,sheet=nil)
|
106
|
-
wait_for_version_080
|
110
|
+
raise NotImplementedError, FORMULAS_MESSAGE
|
107
111
|
end
|
112
|
+
alias_method :formula?, :formula
|
108
113
|
|
109
114
|
# returns NO formulas in excel spreadsheets
|
110
115
|
def formulas(sheet=nil)
|
111
|
-
|
116
|
+
raise NotImplementedError, FORMULAS_MESSAGE
|
112
117
|
end
|
113
118
|
|
114
119
|
# Given a cell, return the cell's font
|
115
120
|
def font(row, col, sheet=nil)
|
116
121
|
sheet ||= @default_sheet
|
117
|
-
read_cells(sheet)
|
122
|
+
read_cells(sheet)
|
118
123
|
row,col = normalize(row,col)
|
119
124
|
@fonts[sheet][[row,col]]
|
120
125
|
end
|
@@ -123,7 +128,7 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
123
128
|
# mainly for debugging purposes
|
124
129
|
def to_s(sheet=nil)
|
125
130
|
sheet ||= @default_sheet
|
126
|
-
read_cells(sheet)
|
131
|
+
read_cells(sheet)
|
127
132
|
@cell[sheet].inspect
|
128
133
|
end
|
129
134
|
|
@@ -239,10 +244,7 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
239
244
|
def read_cells(sheet=nil)
|
240
245
|
sheet ||= @default_sheet
|
241
246
|
validate_sheet!(sheet)
|
242
|
-
|
243
|
-
if @cells_read[sheet]
|
244
|
-
raise "sheet #{sheet} already read"
|
245
|
-
end
|
247
|
+
return if @cells_read[sheet]
|
246
248
|
|
247
249
|
worksheet = @workbook.worksheet(sheet_no(sheet))
|
248
250
|
row_index=1
|
@@ -286,7 +288,6 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
286
288
|
false
|
287
289
|
end
|
288
290
|
end
|
289
|
-
private :date_or_time?
|
290
291
|
|
291
292
|
# Read the date-time cell and convert to,
|
292
293
|
# the date-time values for Roo
|
@@ -326,7 +327,6 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
326
327
|
end
|
327
328
|
return value_type, value
|
328
329
|
end
|
329
|
-
private :read_cell_date_or_time
|
330
330
|
|
331
331
|
# Read the cell and based on the class,
|
332
332
|
# return the values for Roo
|
@@ -345,15 +345,5 @@ class Roo::Excel < Roo::GenericSpreadsheet
|
|
345
345
|
end # case
|
346
346
|
return value_type, value
|
347
347
|
end
|
348
|
-
private :read_cell
|
349
|
-
|
350
|
-
def wait_for_version_080
|
351
|
-
if Spreadsheet::VERSION<='0.8.0'
|
352
|
-
raise 'Formulas are not supported for excel spreadsheets.' +
|
353
|
-
" We have to wait for the 0.8.0 version of the Spreadsheet gem (currently used version is #{Spreadsheet::VERSION})"
|
354
|
-
else
|
355
|
-
raise 'Thomas should implement formulas from Spreadsheet gem'
|
356
|
-
end
|
357
|
-
end
|
358
348
|
|
359
349
|
end
|
data/lib/roo/excel2003xml.rb
CHANGED
@@ -1,35 +1,34 @@
|
|
1
|
-
require 'fileutils'
|
2
1
|
require 'date'
|
3
2
|
require 'base64'
|
4
|
-
require 'cgi'
|
5
3
|
require 'nokogiri'
|
6
4
|
|
7
|
-
class Roo::Excel2003XML < Roo::
|
5
|
+
class Roo::Excel2003XML < Roo::Base
|
8
6
|
|
9
7
|
# initialization and opening of a spreadsheet file
|
10
8
|
# values for packed: :zip
|
11
|
-
def initialize(filename,
|
9
|
+
def initialize(filename, options={}, deprecated_file_warning=:error)
|
10
|
+
if Hash === options
|
11
|
+
packed = options[:packed]
|
12
|
+
file_warning = options[:file_warning] || :error
|
13
|
+
else
|
14
|
+
warn 'Supplying `packed` or `file_warning` as separate arguments to `Roo::Excel2003XML.new` is deprected. Use an options hash instead.'
|
15
|
+
packed = options
|
16
|
+
file_warning = deprecated_file_warning
|
17
|
+
end
|
18
|
+
|
12
19
|
make_tmpdir do |tmpdir|
|
13
|
-
filename =
|
20
|
+
filename = download_uri(filename, tmpdir) if uri?(filename)
|
14
21
|
filename = unzip(filename, tmpdir) if packed == :zip
|
15
22
|
|
16
23
|
file_type_check(filename,'.xml','an Excel 2003 XML', file_warning)
|
17
|
-
@cells_read = Hash.new
|
18
24
|
@filename = filename
|
19
25
|
unless File.file?(@filename)
|
20
26
|
raise IOError, "file #{@filename} does not exist"
|
21
27
|
end
|
22
|
-
@doc =
|
28
|
+
@doc = load_xml(@filename)
|
23
29
|
end
|
24
|
-
|
25
|
-
@cell = Hash.new
|
26
|
-
@cell_type = Hash.new
|
30
|
+
super(filename, options)
|
27
31
|
@formula = Hash.new
|
28
|
-
@first_row = Hash.new
|
29
|
-
@last_row = Hash.new
|
30
|
-
@first_column = Hash.new
|
31
|
-
@last_column = Hash.new
|
32
|
-
@header_line = 1
|
33
32
|
@style = Hash.new
|
34
33
|
@style_defaults = Hash.new { |h,k| h[k] = [] }
|
35
34
|
@style_definitions = Hash.new
|
@@ -42,7 +41,7 @@ class Roo::Excel2003XML < Roo::GenericSpreadsheet
|
|
42
41
|
# cell at the first line and first row.
|
43
42
|
def cell(row, col, sheet=nil)
|
44
43
|
sheet ||= @default_sheet
|
45
|
-
read_cells(sheet)
|
44
|
+
read_cells(sheet)
|
46
45
|
row,col = normalize(row,col)
|
47
46
|
if celltype(row,col,sheet) == :date
|
48
47
|
yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
|
@@ -56,22 +55,11 @@ class Roo::Excel2003XML < Roo::GenericSpreadsheet
|
|
56
55
|
# The method #formula? checks if there is a formula.
|
57
56
|
def formula(row,col,sheet=nil)
|
58
57
|
sheet ||= @default_sheet
|
59
|
-
read_cells(sheet)
|
60
|
-
row,col = normalize(row,col)
|
61
|
-
if @formula[sheet][[row,col]] == nil
|
62
|
-
return nil
|
63
|
-
else
|
64
|
-
return @formula[sheet][[row,col]]["oooc:".length..-1]
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# true, if there is a formula
|
69
|
-
def formula?(row,col,sheet=nil)
|
70
|
-
sheet ||= @default_sheet
|
71
|
-
read_cells(sheet) unless @cells_read[sheet]
|
58
|
+
read_cells(sheet)
|
72
59
|
row,col = normalize(row,col)
|
73
|
-
formula
|
60
|
+
@formula[sheet][[row,col]] && @formula[sheet][[row,col]]["oooc:".length..-1]
|
74
61
|
end
|
62
|
+
alias_method :formula?, :formula
|
75
63
|
|
76
64
|
class Font
|
77
65
|
attr_accessor :bold, :italic, :underline
|
@@ -92,7 +80,7 @@ class Roo::Excel2003XML < Roo::GenericSpreadsheet
|
|
92
80
|
# Given a cell, return the cell's style
|
93
81
|
def font(row, col, sheet=nil)
|
94
82
|
sheet ||= @default_sheet
|
95
|
-
read_cells(sheet)
|
83
|
+
read_cells(sheet)
|
96
84
|
row,col = normalize(row,col)
|
97
85
|
style_name = @style[sheet][[row,col]] || @style_defaults[sheet][col - 1] || 'Default'
|
98
86
|
@style_definitions[style_name]
|
@@ -108,7 +96,7 @@ class Roo::Excel2003XML < Roo::GenericSpreadsheet
|
|
108
96
|
# * :datetime
|
109
97
|
def celltype(row,col,sheet=nil)
|
110
98
|
sheet ||= @default_sheet
|
111
|
-
read_cells(sheet)
|
99
|
+
read_cells(sheet)
|
112
100
|
row,col = normalize(row,col)
|
113
101
|
if @formula[sheet][[row,col]]
|
114
102
|
return :formula
|
@@ -134,7 +122,7 @@ class Roo::Excel2003XML < Roo::GenericSpreadsheet
|
|
134
122
|
# mainly for debugging purposes
|
135
123
|
def to_s(sheet=nil)
|
136
124
|
sheet ||= @default_sheet
|
137
|
-
read_cells(sheet)
|
125
|
+
read_cells(sheet)
|
138
126
|
@cell[sheet].inspect
|
139
127
|
end
|
140
128
|
|
@@ -148,7 +136,7 @@ class Roo::Excel2003XML < Roo::GenericSpreadsheet
|
|
148
136
|
def formulas(sheet=nil)
|
149
137
|
theformulas = Array.new
|
150
138
|
sheet ||= @default_sheet
|
151
|
-
read_cells(sheet)
|
139
|
+
read_cells(sheet)
|
152
140
|
first_row(sheet).upto(last_row(sheet)) {|row|
|
153
141
|
first_column(sheet).upto(last_column(sheet)) {|col|
|
154
142
|
if formula?(row,col,sheet)
|
@@ -204,9 +192,9 @@ class Roo::Excel2003XML < Roo::GenericSpreadsheet
|
|
204
192
|
#++
|
205
193
|
def read_cells(sheet=nil)
|
206
194
|
sheet ||= @default_sheet
|
195
|
+
validate_sheet!(sheet)
|
196
|
+
return if @cells_read[sheet]
|
207
197
|
sheet_found = false
|
208
|
-
raise ArgumentError, "Error: sheet '#{sheet||'nil'}' not valid" if @default_sheet == nil and sheet==nil
|
209
|
-
raise RangeError unless self.sheets.include? sheet
|
210
198
|
@doc.xpath("/ss:Workbook/ss:Worksheet[@ss:Name='#{sheet}']").each do |ws|
|
211
199
|
sheet_found = true
|
212
200
|
row = 1
|
data/lib/roo/excelx.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
require 'fileutils'
|
2
1
|
require 'date'
|
3
2
|
require 'nokogiri'
|
4
3
|
|
5
|
-
class Roo::Excelx < Roo::
|
4
|
+
class Roo::Excelx < Roo::Base
|
6
5
|
module Format
|
7
6
|
EXCEPTIONAL_FORMATS = {
|
8
7
|
'h:mm am/pm' => :date,
|
@@ -66,56 +65,47 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
66
65
|
|
67
66
|
# initialization and opening of a spreadsheet file
|
68
67
|
# values for packed: :zip
|
69
|
-
def initialize(filename,
|
68
|
+
def initialize(filename, options = {}, deprecated_file_warning = :error)
|
69
|
+
if Hash === options
|
70
|
+
packed = options[:packed]
|
71
|
+
file_warning = options[:file_warning] || :error
|
72
|
+
else
|
73
|
+
warn 'Supplying `packed` or `file_warning` as separate arguments to `Roo::Excelx.new` is deprected. Use an options hash instead.'
|
74
|
+
packed = options
|
75
|
+
file_warning = deprecated_file_warning
|
76
|
+
end
|
77
|
+
|
70
78
|
file_type_check(filename,'.xlsx','an Excel-xlsx', file_warning, packed)
|
71
79
|
make_tmpdir do |tmpdir|
|
72
|
-
filename =
|
80
|
+
filename = download_uri(filename, tmpdir) if uri?(filename)
|
73
81
|
filename = unzip(filename, tmpdir) if packed == :zip
|
74
|
-
@cells_read = Hash.new
|
75
82
|
@filename = filename
|
76
83
|
unless File.file?(@filename)
|
77
84
|
raise IOError, "file #{@filename} does not exist"
|
78
85
|
end
|
79
86
|
@comments_files = Array.new
|
80
87
|
extract_content(tmpdir, @filename)
|
81
|
-
@workbook_doc =
|
82
|
-
Nokogiri::XML(file)
|
83
|
-
end
|
88
|
+
@workbook_doc = load_xml(File.join(tmpdir, "roo_workbook.xml"))
|
84
89
|
@shared_table = []
|
85
90
|
if File.exist?(File.join(tmpdir, 'roo_sharedStrings.xml'))
|
86
|
-
@sharedstring_doc =
|
87
|
-
Nokogiri::XML(file)
|
88
|
-
end
|
91
|
+
@sharedstring_doc = load_xml(File.join(tmpdir, 'roo_sharedStrings.xml'))
|
89
92
|
read_shared_strings(@sharedstring_doc)
|
90
93
|
end
|
91
94
|
@styles_table = []
|
92
95
|
@style_definitions = Array.new # TODO: ??? { |h,k| h[k] = {} }
|
93
96
|
if File.exist?(File.join(tmpdir, 'roo_styles.xml'))
|
94
|
-
@styles_doc =
|
95
|
-
Nokogiri::XML(file)
|
96
|
-
end
|
97
|
+
@styles_doc = load_xml(File.join(tmpdir, 'roo_styles.xml'))
|
97
98
|
read_styles(@styles_doc)
|
98
99
|
end
|
99
100
|
@sheet_doc = @sheet_files.map do |item|
|
100
|
-
|
101
|
-
Nokogiri::XML(file)
|
102
|
-
end
|
101
|
+
load_xml(item)
|
103
102
|
end
|
104
103
|
@comments_doc = @comments_files.map do |item|
|
105
|
-
|
106
|
-
Nokogiri::XML(file)
|
107
|
-
end
|
104
|
+
load_xml(item)
|
108
105
|
end
|
109
106
|
end
|
110
|
-
|
111
|
-
@cell = Hash.new
|
112
|
-
@cell_type = Hash.new
|
107
|
+
super(filename, options)
|
113
108
|
@formula = Hash.new
|
114
|
-
@first_row = Hash.new
|
115
|
-
@last_row = Hash.new
|
116
|
-
@first_column = Hash.new
|
117
|
-
@last_column = Hash.new
|
118
|
-
@header_line = 1
|
119
109
|
@excelx_type = Hash.new
|
120
110
|
@excelx_value = Hash.new
|
121
111
|
@s_attribute = Hash.new # TODO: ggf. wieder entfernen nur lokal benoetigt
|
@@ -128,7 +118,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
128
118
|
read_labels
|
129
119
|
if @label.has_key?(m.to_s)
|
130
120
|
sheet ||= @default_sheet
|
131
|
-
read_cells(sheet)
|
121
|
+
read_cells(sheet)
|
132
122
|
row,col = label(m.to_s)
|
133
123
|
cell(row,col)
|
134
124
|
else
|
@@ -143,7 +133,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
143
133
|
# cell at the first line and first row.
|
144
134
|
def cell(row, col, sheet=nil)
|
145
135
|
sheet ||= @default_sheet
|
146
|
-
read_cells(sheet)
|
136
|
+
read_cells(sheet)
|
147
137
|
row,col = normalize(row,col)
|
148
138
|
if celltype(row,col,sheet) == :date
|
149
139
|
yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
|
@@ -162,28 +152,17 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
162
152
|
# The method #formula? checks if there is a formula.
|
163
153
|
def formula(row,col,sheet=nil)
|
164
154
|
sheet ||= @default_sheet
|
165
|
-
read_cells(sheet)
|
155
|
+
read_cells(sheet)
|
166
156
|
row,col = normalize(row,col)
|
167
|
-
|
168
|
-
return nil
|
169
|
-
else
|
170
|
-
return @formula[sheet][[row,col]]
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
# true, if there is a formula
|
175
|
-
def formula?(row,col,sheet=nil)
|
176
|
-
sheet ||= @default_sheet
|
177
|
-
read_cells(sheet) unless @cells_read[sheet]
|
178
|
-
row,col = normalize(row,col)
|
179
|
-
formula(row,col) != nil
|
157
|
+
@formula[sheet][[row,col]] && @formula[sheet][[row,col]]
|
180
158
|
end
|
159
|
+
alias_method :formula?, :formula
|
181
160
|
|
182
161
|
# returns each formula in the selected sheet as an array of elements
|
183
162
|
# [row, col, formula]
|
184
163
|
def formulas(sheet=nil)
|
185
164
|
sheet ||= @default_sheet
|
186
|
-
read_cells(sheet)
|
165
|
+
read_cells(sheet)
|
187
166
|
if @formula[sheet]
|
188
167
|
@formula[sheet].each.collect do |elem|
|
189
168
|
[elem[0][0], elem[0][1], elem[1]]
|
@@ -212,7 +191,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
212
191
|
# Given a cell, return the cell's style
|
213
192
|
def font(row, col, sheet=nil)
|
214
193
|
sheet ||= @default_sheet
|
215
|
-
read_cells(sheet)
|
194
|
+
read_cells(sheet)
|
216
195
|
row,col = normalize(row,col)
|
217
196
|
s_attribute = @s_attribute[sheet][[row,col]]
|
218
197
|
s_attribute ||= 0
|
@@ -230,7 +209,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
230
209
|
# * :datetime
|
231
210
|
def celltype(row,col,sheet=nil)
|
232
211
|
sheet ||= @default_sheet
|
233
|
-
read_cells(sheet)
|
212
|
+
read_cells(sheet)
|
234
213
|
row,col = normalize(row,col)
|
235
214
|
if @formula[sheet][[row,col]]
|
236
215
|
return :formula
|
@@ -245,7 +224,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
245
224
|
# Note: this is only available within the Excelx class
|
246
225
|
def excelx_type(row,col,sheet=nil)
|
247
226
|
sheet ||= @default_sheet
|
248
|
-
read_cells(sheet)
|
227
|
+
read_cells(sheet)
|
249
228
|
row,col = normalize(row,col)
|
250
229
|
return @excelx_type[sheet][[row,col]]
|
251
230
|
end
|
@@ -254,7 +233,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
254
233
|
# Note: this is only available within the Excelx class
|
255
234
|
def excelx_value(row,col,sheet=nil)
|
256
235
|
sheet ||= @default_sheet
|
257
|
-
read_cells(sheet)
|
236
|
+
read_cells(sheet)
|
258
237
|
row,col = normalize(row,col)
|
259
238
|
return @excelx_value[sheet][[row,col]]
|
260
239
|
end
|
@@ -262,7 +241,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
262
241
|
# returns the internal format of an excel cell
|
263
242
|
def excelx_format(row,col,sheet=nil)
|
264
243
|
sheet ||= @default_sheet
|
265
|
-
read_cells(sheet)
|
244
|
+
read_cells(sheet)
|
266
245
|
row,col = normalize(row,col)
|
267
246
|
s = @s_attribute[sheet][[row,col]]
|
268
247
|
attribute2format(s).to_s
|
@@ -279,7 +258,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
279
258
|
# for debugging purposes
|
280
259
|
def to_s(sheet=nil)
|
281
260
|
sheet ||= @default_sheet
|
282
|
-
read_cells(sheet)
|
261
|
+
read_cells(sheet)
|
283
262
|
@cell[sheet].inspect
|
284
263
|
end
|
285
264
|
|
@@ -291,7 +270,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
291
270
|
return nil,nil,nil
|
292
271
|
else
|
293
272
|
return @label[labelname][1].to_i,
|
294
|
-
Roo::
|
273
|
+
Roo::Base.letter_to_number(@label[labelname][2]),
|
295
274
|
@label[labelname][0]
|
296
275
|
end
|
297
276
|
end
|
@@ -300,12 +279,12 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
300
279
|
# [labelname, [row,col,sheetname]]
|
301
280
|
def labels
|
302
281
|
# sheet ||= @default_sheet
|
303
|
-
# read_cells(sheet)
|
282
|
+
# read_cells(sheet)
|
304
283
|
read_labels
|
305
284
|
@label.map do |label|
|
306
285
|
[ label[0], # name
|
307
286
|
[ label[1][1].to_i, # row
|
308
|
-
Roo::
|
287
|
+
Roo::Base.letter_to_number(label[1][2]), # column
|
309
288
|
label[1][0], # sheet
|
310
289
|
] ]
|
311
290
|
end
|
@@ -315,7 +294,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
315
294
|
# nil if there is no comment
|
316
295
|
def comment(row,col,sheet=nil)
|
317
296
|
sheet ||= @default_sheet
|
318
|
-
#read_cells(sheet)
|
297
|
+
#read_cells(sheet)
|
319
298
|
read_comments(sheet) unless @comments_read[sheet]
|
320
299
|
row,col = normalize(row,col)
|
321
300
|
return nil unless @comment[sheet]
|
@@ -325,7 +304,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
325
304
|
# true, if there is a comment
|
326
305
|
def comment?(row,col,sheet=nil)
|
327
306
|
sheet ||= @default_sheet
|
328
|
-
# read_cells(sheet)
|
307
|
+
# read_cells(sheet)
|
329
308
|
read_comments(sheet) unless @comments_read[sheet]
|
330
309
|
row,col = normalize(row,col)
|
331
310
|
comment(row,col) != nil
|
@@ -365,9 +344,9 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
365
344
|
when :string
|
366
345
|
v
|
367
346
|
when :date
|
368
|
-
(
|
347
|
+
(base_date+v.to_i).strftime("%Y-%m-%d")
|
369
348
|
when :datetime
|
370
|
-
(
|
349
|
+
(base_date+v.to_f).strftime("%Y-%m-%d %H:%M:%S")
|
371
350
|
when :percentage
|
372
351
|
v.to_f
|
373
352
|
when :time
|
@@ -387,6 +366,8 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
387
366
|
def read_cells(sheet=nil)
|
388
367
|
sheet ||= @default_sheet
|
389
368
|
validate_sheet!(sheet)
|
369
|
+
return if @cells_read[sheet]
|
370
|
+
|
390
371
|
@sheet_doc[sheets.index(sheet)].xpath("/xmlns:worksheet/xmlns:sheetData/xmlns:row/xmlns:c").each do |c|
|
391
372
|
s_attribute = c['s'].to_i # should be here
|
392
373
|
# c: <c r="A5" s="2">
|
@@ -420,7 +401,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
420
401
|
value_type = :string
|
421
402
|
v = inlinestr_content
|
422
403
|
excelx_type = :string
|
423
|
-
y, x = Roo::
|
404
|
+
y, x = Roo::Base.split_coordinate(c['r'])
|
424
405
|
excelx_value = inlinestr_content #cell.content
|
425
406
|
set_cell_values(sheet,x,y,0,v,value_type,formula,excelx_type,excelx_value,s_attribute)
|
426
407
|
end
|
@@ -461,7 +442,7 @@ class Roo::Excelx < Roo::GenericSpreadsheet
|
|
461
442
|
value_type = :float
|
462
443
|
cell.content
|
463
444
|
end
|
464
|
-
y, x = Roo::
|
445
|
+
y, x = Roo::Base.split_coordinate(c['r'])
|
465
446
|
set_cell_values(sheet,x,y,0,v,value_type,formula,excelx_type,excelx_value,s_attribute)
|
466
447
|
end
|
467
448
|
end
|
@@ -519,7 +500,7 @@ Datei xl/comments1.xml
|
|
519
500
|
return unless @comments_doc[n] #>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
520
501
|
@comments_doc[n].xpath("//xmlns:comments/xmlns:commentList/xmlns:comment").each do |comment|
|
521
502
|
ref = comment.attributes['ref'].to_s
|
522
|
-
row,col = Roo::
|
503
|
+
row,col = Roo::Base.split_coordinate(ref)
|
523
504
|
comment.xpath('./xmlns:text/xmlns:r/xmlns:t').each do |text|
|
524
505
|
@comment[sheet] ||= {}
|
525
506
|
@comment[sheet][[row,col]] = text.text
|
@@ -637,4 +618,21 @@ Datei xl/comments1.xml
|
|
637
618
|
@numFmts[id] || Format::STANDARD_FORMATS[id.to_i]
|
638
619
|
end
|
639
620
|
|
621
|
+
def base_date
|
622
|
+
@base_date ||= read_base_date
|
623
|
+
end
|
624
|
+
|
625
|
+
# Default to 1900 (minus one day due to excel quirk) but use 1904 if
|
626
|
+
# it's set in the Workbook's workbookPr
|
627
|
+
# http://msdn.microsoft.com/en-us/library/ff530155(v=office.12).aspx
|
628
|
+
def read_base_date
|
629
|
+
base_date = Date.new(1899,12,30)
|
630
|
+
@workbook_doc.xpath("//xmlns:workbookPr").map do |workbookPr|
|
631
|
+
if workbookPr["date1904"] && workbookPr["date1904"] =~ /true|1/i
|
632
|
+
base_date = Date.new(1904,01,01)
|
633
|
+
end
|
634
|
+
end
|
635
|
+
base_date
|
636
|
+
end
|
637
|
+
|
640
638
|
end # class
|