rubyXL 1.1.12 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/rubyXL/parser.rb +102 -82
- data/lib/rubyXL/workbook.rb +7 -4
- data/lib/rubyXL/worksheet.rb +7 -3
- data/rubyXL.gemspec +2 -2
- data/spec/lib/cell_spec.rb +11 -2
- metadata +15 -5
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/lib/rubyXL/parser.rb
CHANGED
@@ -155,116 +155,136 @@ module RubyXL
|
|
155
155
|
wb.worksheets[i] = Parser.create_matrix(wb, i, files)
|
156
156
|
j = i+1
|
157
157
|
|
158
|
+
namespaces = files[j].root.namespaces()
|
158
159
|
unless @data_only
|
159
|
-
|
160
|
-
|
161
|
-
wb.worksheets[i].sheet_view = hash[:sheetViews][:sheetView]
|
160
|
+
sheet_views_node= files[j].xpath('/xmlns:worksheet/xmlns:sheetViews[xmlns:sheetView]',namespaces).first
|
161
|
+
wb.worksheets[i].sheet_view = Hash.xml_node_to_hash(sheet_views_node)[:sheetView]
|
162
162
|
|
163
163
|
##col styles##
|
164
|
-
|
165
|
-
unless
|
166
|
-
wb.worksheets[i].cols=
|
164
|
+
cols_node_set = files[j].xpath('/xmlns:worksheet/xmlns:cols/xmlns:col',namespaces)
|
165
|
+
unless cols_node_set.empty?
|
166
|
+
wb.worksheets[i].cols= cols_node_set.map(&:attributes)
|
167
167
|
end
|
168
168
|
##end col styles##
|
169
169
|
|
170
170
|
##merge_cells##
|
171
|
-
|
172
|
-
unless
|
173
|
-
wb.worksheets[i].merged_cells =
|
171
|
+
merge_cells_node = files[j].xpath('/xmlns:worksheet/xmlns:mergeCells[xmlns:mergeCell]',namespaces)
|
172
|
+
unless merge_cells_node.empty?
|
173
|
+
wb.worksheets[i].merged_cells = Hash.xml_node_to_hash(merge_cells_node.first)[:mergeCell]
|
174
174
|
end
|
175
175
|
##end merge_cells##
|
176
176
|
|
177
177
|
##sheet_view pane##
|
178
|
-
pane_data =
|
178
|
+
pane_data = wb.worksheets[i].sheet_view[:pane]
|
179
179
|
wb.worksheets[i].pane = pane_data
|
180
180
|
##end sheet_view pane##
|
181
181
|
|
182
182
|
##data_validation##
|
183
|
-
|
184
|
-
unless
|
185
|
-
|
183
|
+
data_validations_node = files[j].xpath('/xmlns:worksheet/xmlns:dataValidations[xmlns:dataValidation]',namespaces)
|
184
|
+
unless data_validations_node.empty?
|
185
|
+
wb.worksheets[i].validations = Hash.xml_node_to_hash(data_validations_node.first)[:dataValidation]
|
186
|
+
else
|
187
|
+
wb.worksheets[i].validations=nil
|
186
188
|
end
|
187
|
-
wb.worksheets[i].validations = data_validation
|
188
189
|
##end data_validation##
|
189
190
|
|
190
191
|
#extLst
|
191
|
-
|
192
|
+
ext_list_node=files[j].xpath('/xmlns:worksheet/xmlns:extLst',namespaces)
|
193
|
+
unless ext_list_node.empty?
|
194
|
+
wb.worksheets[i].extLst = Hash.xml_node_to_hash(ext_list_node.first)
|
195
|
+
else
|
196
|
+
wb.worksheets[i].extLst=nil
|
197
|
+
end
|
192
198
|
#extLst
|
193
199
|
|
194
200
|
##legacy drawing##
|
195
|
-
|
196
|
-
|
201
|
+
legacy_drawing_node = files[j].xpath('/xmlns:worksheet/xmlns:legacyDrawing',namespaces)
|
202
|
+
unless legacy_drawing_node.empty?
|
203
|
+
wb.worksheets[i].legacy_drawing = Hash.xml_node_to_hash(legacy_drawing_node.first)
|
204
|
+
else
|
205
|
+
wb.worksheets[i].legacy_drawing = nil
|
206
|
+
end
|
197
207
|
##end legacy drawing
|
198
208
|
end
|
199
209
|
|
200
|
-
|
210
|
+
|
211
|
+
row_data = files[j].xpath('/xmlns:worksheet/xmlns:sheetData/xmlns:row[xmlns:c[xmlns:v]]',namespaces)
|
212
|
+
row_data.each do |row|
|
213
|
+
unless @data_only
|
214
|
+
##row styles##
|
215
|
+
row_style = '0'
|
216
|
+
row_attributes = row.attributes
|
217
|
+
unless row_attributes['s'].nil?
|
218
|
+
row_style = row_attributes['s'].value
|
219
|
+
end
|
201
220
|
|
202
|
-
|
203
|
-
row_data.each do |row|
|
221
|
+
wb.worksheets[i].row_styles[row_attributes['r'].content] = { :style => row_style }
|
204
222
|
|
205
|
-
unless
|
206
|
-
|
207
|
-
|
208
|
-
row_style = '0'
|
209
|
-
unless row.attribute('s').nil?
|
210
|
-
row_style = row.attribute('s').value.to_s
|
211
|
-
end
|
212
|
-
|
213
|
-
wb.worksheets[i].row_styles[row.attribute('r').to_s] = { :style => row_style.to_s }
|
214
|
-
|
215
|
-
unless row.attribute('ht').to_s == ""
|
216
|
-
wb.worksheets[i].change_row_height(Integer(row.attribute('r').to_s)-1,
|
217
|
-
Float(row.attribute('ht').to_s))
|
218
|
-
end
|
219
|
-
end
|
220
|
-
##end row styles##
|
223
|
+
unless row_attributes['ht'].content == ""
|
224
|
+
wb.worksheets[i].change_row_height(Integer(row_attributes['r'].content)-1,
|
225
|
+
Float(row_attributes['ht'].content))
|
221
226
|
end
|
227
|
+
##end row styles##
|
228
|
+
end
|
222
229
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
data_type = value.attribute('t').to_s
|
229
|
-
|
230
|
-
if (value.css('v').to_s == "") || (value.css('v').children.to_s == "") #no data
|
231
|
-
cell_data = nil
|
232
|
-
elsif data_type == 's' #shared string
|
233
|
-
str_index = Integer(value.css('v').children.to_s)
|
234
|
-
cell_data = shared_strings[str_index].to_s
|
235
|
-
elsif data_type=='str' #raw string
|
236
|
-
cell_data = value.css('v').children.to_s
|
237
|
-
elsif data_type=='e' #error
|
238
|
-
cell_data = value.css('v').children.to_s
|
239
|
-
else# (value.css('v').to_s != "") && (value.css('v').children.to_s != "") #is number
|
240
|
-
data_type = ''
|
241
|
-
if(value.css('v').children.to_s =~ /\./) #is float
|
242
|
-
cell_data = Float(value.css('v').children.to_s)
|
243
|
-
else
|
244
|
-
cell_data = Integer(value.css('v').children.to_s)
|
245
|
-
end
|
246
|
-
end
|
247
|
-
cell_formula = nil
|
248
|
-
fmla_css = value.css('f')
|
249
|
-
if(fmla_css.to_s != "")
|
250
|
-
cell_formula = fmla_css.children.to_s
|
251
|
-
cell_formula_attr = {}
|
252
|
-
cell_formula_attr['t'] = fmla_css.attribute('t').to_s if fmla_css.attribute('t')
|
253
|
-
cell_formula_attr['ref'] = fmla_css.attribute('ref').to_s if fmla_css.attribute('ref')
|
254
|
-
cell_formula_attr['si'] = fmla_css.attribute('si').to_s if fmla_css.attribute('si')
|
255
|
-
end
|
230
|
+
c_row = row.search('./xmlns:c[xmlns:v]')
|
231
|
+
c_row.each do |value|
|
232
|
+
value_attributes= value.attributes
|
233
|
+
cell_index = Parser.convert_to_index(value_attributes['r'].content)
|
234
|
+
style_index = nil
|
256
235
|
|
257
|
-
|
258
|
-
|
236
|
+
data_type = value_attributes['t'].content if value_attributes['t']
|
237
|
+
element_hash ={}
|
238
|
+
value.children.each do |node|
|
239
|
+
element_hash["#{node.name()}_element"]=node
|
240
|
+
end
|
241
|
+
# v is the value element that is part of the cell
|
242
|
+
if element_hash["v_element"]
|
243
|
+
v_element_content = element_hash["v_element"].content
|
244
|
+
else
|
245
|
+
v_element_content=""
|
246
|
+
end
|
247
|
+
if v_element_content =="" #no data
|
248
|
+
cell_data = nil
|
249
|
+
elsif data_type == 's' #shared string
|
250
|
+
str_index = Integer(v_element_content)
|
251
|
+
cell_data = shared_strings[str_index].to_s
|
252
|
+
elsif data_type=='str' #raw string
|
253
|
+
cell_data = v_element_content
|
254
|
+
elsif data_type=='e' #error
|
255
|
+
cell_data = v_element_content
|
256
|
+
else# (value.css('v').to_s != "") && (value.css('v').children.to_s != "") #is number
|
257
|
+
data_type = ''
|
258
|
+
if(v_element_content =~ /\./) #is float
|
259
|
+
cell_data = Float(v_element_content)
|
259
260
|
else
|
260
|
-
|
261
|
+
cell_data = Integer(v_element_content)
|
261
262
|
end
|
263
|
+
end
|
264
|
+
cell_formula = nil
|
265
|
+
fmla_css = element_hash["f_element"]
|
266
|
+
if fmla_css && fmla_css.content
|
267
|
+
fmla_css_content= fmla_css.content
|
268
|
+
if(fmla_css_content != "")
|
269
|
+
cell_formula = fmla_css_content
|
270
|
+
cell_formula_attr = {}
|
271
|
+
fmla_css_attributes = fmla_css.attributes
|
272
|
+
cell_formula_attr['t'] = fmla_css_attributes['t'].content if fmla_css_attributes['t']
|
273
|
+
cell_formula_attr['ref'] = fmla_css_attributes['ref'].content if fmla_css_attributes['ref']
|
274
|
+
cell_formula_attr['si'] = fmla_css_attributes['si'].content if fmla_css_attributes['si']
|
275
|
+
end
|
276
|
+
end
|
262
277
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
278
|
+
unless @data_only
|
279
|
+
style_index = value['s'].to_i #nil goes to 0 (default)
|
280
|
+
else
|
281
|
+
style_index = 0
|
267
282
|
end
|
283
|
+
|
284
|
+
wb.worksheets[i].sheet_data[cell_index[0]][cell_index[1]] =
|
285
|
+
Cell.new(wb.worksheets[i],cell_index[0],cell_index[1],cell_data,cell_formula,
|
286
|
+
data_type,style_index,cell_formula_attr)
|
287
|
+
cell = wb.worksheets[i].sheet_data[cell_index[0]][cell_index[1]]
|
268
288
|
end
|
269
289
|
end
|
270
290
|
end
|
@@ -288,13 +308,13 @@ module RubyXL
|
|
288
308
|
|
289
309
|
files = Hash.new
|
290
310
|
|
291
|
-
files['app'] = Nokogiri::XML.parse(File.
|
292
|
-
files['core'] = Nokogiri::XML.parse(File.
|
311
|
+
files['app'] = Nokogiri::XML.parse(File.open(File.join(dir_path,'docProps','app.xml'),'r'))
|
312
|
+
files['core'] = Nokogiri::XML.parse(File.open(File.join(dir_path,'docProps','core.xml'),'r'))
|
293
313
|
|
294
|
-
files['workbook'] = Nokogiri::XML.parse(File.
|
314
|
+
files['workbook'] = Nokogiri::XML.parse(File.open(File.join(dir_path,'xl','workbook.xml'),'r'))
|
295
315
|
|
296
316
|
if(File.exist?(File.join(dir_path,'xl','sharedStrings.xml')))
|
297
|
-
files['sharedString'] = Nokogiri::XML.parse(File.
|
317
|
+
files['sharedString'] = Nokogiri::XML.parse(File.open(File.join(dir_path,'xl','sharedStrings.xml'),'r'))
|
298
318
|
end
|
299
319
|
|
300
320
|
unless @data_only
|
@@ -352,7 +372,7 @@ module RubyXL
|
|
352
372
|
files['vbaProject'] = File.open(File.join(dir_path,"xl","vbaProject.bin"),'rb').read
|
353
373
|
end
|
354
374
|
|
355
|
-
files['styles'] = Nokogiri::XML.parse(File.
|
375
|
+
files['styles'] = Nokogiri::XML.parse(File.open(File.join(dir_path,'xl','styles.xml'),'r'))
|
356
376
|
end
|
357
377
|
|
358
378
|
@num_sheets = files['workbook'].css('sheets').children.size
|
@@ -362,7 +382,7 @@ module RubyXL
|
|
362
382
|
i=1
|
363
383
|
1.upto(@num_sheets) do
|
364
384
|
filename = 'sheet'+i.to_s
|
365
|
-
files[i] = Nokogiri::XML.parse(File.
|
385
|
+
files[i] = Nokogiri::XML.parse(File.open(File.join(dir_path,'xl','worksheets',filename+'.xml'),'r'))
|
366
386
|
i=i+1
|
367
387
|
end
|
368
388
|
|
data/lib/rubyXL/workbook.rb
CHANGED
@@ -47,7 +47,7 @@ module RubyXL
|
|
47
47
|
@calc_chain = nil #unnecessary?
|
48
48
|
@num_strings = 0 #num strings total
|
49
49
|
@size = 0 #num strings in shared_strings array
|
50
|
-
@date1904 = date1904
|
50
|
+
@date1904 = date1904 > 0
|
51
51
|
@external_links = nil
|
52
52
|
@style_corrector = nil
|
53
53
|
@drawings = nil
|
@@ -78,6 +78,9 @@ module RubyXL
|
|
78
78
|
#filepath of xlsx file (including file itself)
|
79
79
|
def write(filepath=@filepath)
|
80
80
|
validate_before_write
|
81
|
+
if !(filepath =~ /(.+)\.xls(x|m)/)
|
82
|
+
raise "Only xlsx and xlsm files are supported. Unsupported type for file: #{filepath}"
|
83
|
+
end
|
81
84
|
dirpath = ''
|
82
85
|
extension = 'xls'
|
83
86
|
if(filepath =~ /((.|\s)*)\.xls(x|m)$/)
|
@@ -197,7 +200,7 @@ module RubyXL
|
|
197
200
|
compare_date = DateTime.parse('December 31, 1899')
|
198
201
|
end
|
199
202
|
# add one day to compare date for erroneous 1900 leap year compatibility
|
200
|
-
date.ajd -
|
203
|
+
date.ajd + 1 - compare_date.ajd
|
201
204
|
end
|
202
205
|
|
203
206
|
def num_to_date(num)
|
@@ -207,8 +210,8 @@ module RubyXL
|
|
207
210
|
else
|
208
211
|
compare_date = DateTime.parse('December 31, 1899')
|
209
212
|
end
|
210
|
-
#
|
211
|
-
compare_date
|
213
|
+
# subtract one day to compare date for erroneous 1900 leap year compatibility
|
214
|
+
compare_date - 1 + num
|
212
215
|
end
|
213
216
|
|
214
217
|
#gets style object from style array given index
|
data/lib/rubyXL/worksheet.rb
CHANGED
@@ -60,8 +60,11 @@ class Worksheet < PrivateClass
|
|
60
60
|
|
61
61
|
# makes array of hashes in table_hash[:table]
|
62
62
|
# as well as hash of arrays in table_hash[header]
|
63
|
-
|
64
|
-
|
63
|
+
table_index = current_row - original_row
|
64
|
+
cell_test= (!cell.nil? && !cell.value.nil?)
|
65
|
+
while cell_test || !table_hash[:table][table_index].empty?
|
66
|
+
|
67
|
+
table_hash[header] << (cell_test ? cell.value : nil)
|
65
68
|
|
66
69
|
table_index = current_row - original_row
|
67
70
|
|
@@ -69,7 +72,7 @@ class Worksheet < PrivateClass
|
|
69
72
|
table_hash[:table][table_index] = {}
|
70
73
|
end
|
71
74
|
|
72
|
-
table_hash[:table][table_index][header] = cell.value
|
75
|
+
table_hash[:table][table_index][header] = cell.value if cell_test
|
73
76
|
|
74
77
|
current_row += 1
|
75
78
|
if @sheet_data[current_row].nil?
|
@@ -77,6 +80,7 @@ class Worksheet < PrivateClass
|
|
77
80
|
else
|
78
81
|
cell = @sheet_data[current_row][index]
|
79
82
|
end
|
83
|
+
cell_test= (!cell.nil? && !cell.value.nil?)
|
80
84
|
end
|
81
85
|
end
|
82
86
|
|
data/rubyXL.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rubyXL}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Vivek Bhagwat"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2012-01-06}
|
13
13
|
s.description = %q{rubyXL is a gem which allows the parsing, creation, and manipulation of Microsoft Excel (.xlsx/.xlsm) Documents}
|
14
14
|
s.email = %q{bhagwat.vivek@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/spec/lib/cell_spec.rb
CHANGED
@@ -196,9 +196,18 @@ describe RubyXL::Cell do
|
|
196
196
|
it 'should return the value of a date' do
|
197
197
|
date = Date.parse('January 1, 2011')
|
198
198
|
@cell.change_contents(date)
|
199
|
-
@cell.should_receive(:is_date?).
|
199
|
+
@cell.should_receive(:is_date?).any_number_of_times.and_return(true)
|
200
200
|
@cell.value.should == date
|
201
201
|
end
|
202
|
+
|
203
|
+
it 'should convert date numbers correctly' do
|
204
|
+
date = 41019
|
205
|
+
@cell.change_contents(date)
|
206
|
+
@cell.should_receive(:is_date?).any_number_of_times.and_return(true)
|
207
|
+
puts @cell.value
|
208
|
+
puts Date.parse('April 20, 2012')
|
209
|
+
@cell.value.should == Date.parse('April 20, 2012')
|
210
|
+
end
|
202
211
|
end
|
203
212
|
|
204
213
|
describe '.change_contents' do
|
@@ -211,7 +220,7 @@ describe RubyXL::Cell do
|
|
211
220
|
it 'should cause cell value to match a date that is passed in' do
|
212
221
|
date = Date.parse('January 1, 2011')
|
213
222
|
@cell.change_contents(date)
|
214
|
-
@cell.should_receive(:is_date?).
|
223
|
+
@cell.should_receive(:is_date?).any_number_of_times.and_return(true)
|
215
224
|
@cell.value.should == date
|
216
225
|
@cell.formula.should == nil
|
217
226
|
end
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyXL
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
segments_generated: true
|
11
|
+
version: 1.2.0
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- Vivek Bhagwat
|
@@ -15,7 +16,7 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date:
|
19
|
+
date: 2012-01-06 00:00:00 -05:00
|
19
20
|
default_executable:
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
@@ -28,6 +29,7 @@ dependencies:
|
|
28
29
|
hash: 3
|
29
30
|
segments:
|
30
31
|
- 0
|
32
|
+
segments_generated: true
|
31
33
|
version: "0"
|
32
34
|
name: shoulda
|
33
35
|
requirement: *id001
|
@@ -44,6 +46,7 @@ dependencies:
|
|
44
46
|
- 1
|
45
47
|
- 0
|
46
48
|
- 0
|
49
|
+
segments_generated: true
|
47
50
|
version: 1.0.0
|
48
51
|
name: bundler
|
49
52
|
requirement: *id002
|
@@ -60,6 +63,7 @@ dependencies:
|
|
60
63
|
- 1
|
61
64
|
- 6
|
62
65
|
- 0
|
66
|
+
segments_generated: true
|
63
67
|
version: 1.6.0
|
64
68
|
name: jeweler
|
65
69
|
requirement: *id003
|
@@ -74,6 +78,7 @@ dependencies:
|
|
74
78
|
hash: 3
|
75
79
|
segments:
|
76
80
|
- 0
|
81
|
+
segments_generated: true
|
77
82
|
version: "0"
|
78
83
|
name: rcov
|
79
84
|
requirement: *id004
|
@@ -90,6 +95,7 @@ dependencies:
|
|
90
95
|
- 1
|
91
96
|
- 4
|
92
97
|
- 4
|
98
|
+
segments_generated: true
|
93
99
|
version: 1.4.4
|
94
100
|
name: nokogiri
|
95
101
|
requirement: *id005
|
@@ -106,6 +112,7 @@ dependencies:
|
|
106
112
|
- 0
|
107
113
|
- 9
|
108
114
|
- 4
|
115
|
+
segments_generated: true
|
109
116
|
version: 0.9.4
|
110
117
|
name: rubyzip
|
111
118
|
requirement: *id006
|
@@ -122,6 +129,7 @@ dependencies:
|
|
122
129
|
- 1
|
123
130
|
- 3
|
124
131
|
- 4
|
132
|
+
segments_generated: true
|
125
133
|
version: 1.3.4
|
126
134
|
name: rspec
|
127
135
|
requirement: *id007
|
@@ -187,6 +195,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
195
|
hash: 3
|
188
196
|
segments:
|
189
197
|
- 0
|
198
|
+
segments_generated: true
|
190
199
|
version: "0"
|
191
200
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
201
|
none: false
|
@@ -196,6 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
205
|
hash: 3
|
197
206
|
segments:
|
198
207
|
- 0
|
208
|
+
segments_generated: true
|
199
209
|
version: "0"
|
200
210
|
requirements: []
|
201
211
|
|