rubyXL 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/Gemfile +16 -0
  2. data/Gemfile.lock +34 -0
  3. data/LICENSE.txt +20 -0
  4. data/README +0 -0
  5. data/README.rdoc +19 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/lib/.DS_Store +0 -0
  9. data/lib/Hash.rb +60 -0
  10. data/lib/cell.rb +360 -0
  11. data/lib/color.rb +14 -0
  12. data/lib/parser.rb +413 -0
  13. data/lib/private_class.rb +182 -0
  14. data/lib/rubyXL.rb +9 -0
  15. data/lib/test.html +1 -0
  16. data/lib/tests/test.rb +110 -0
  17. data/lib/tests/test10.rb +16 -0
  18. data/lib/tests/test2.rb +118 -0
  19. data/lib/tests/test3.rb +76 -0
  20. data/lib/tests/test4.rb +92 -0
  21. data/lib/tests/test5.rb +90 -0
  22. data/lib/tests/test6.rb +50 -0
  23. data/lib/tests/test7.rb +48 -0
  24. data/lib/tests/test8.rb +12 -0
  25. data/lib/tests/test9.rb +60 -0
  26. data/lib/workbook.rb +336 -0
  27. data/lib/worksheet.rb +1245 -0
  28. data/lib/writer/app_writer.rb +62 -0
  29. data/lib/writer/calc_chain_writer.rb +33 -0
  30. data/lib/writer/content_types_writer.rb +77 -0
  31. data/lib/writer/core_writer.rb +51 -0
  32. data/lib/writer/root_rels_writer.rb +25 -0
  33. data/lib/writer/shared_strings_writer.rb +44 -0
  34. data/lib/writer/styles_writer.rb +376 -0
  35. data/lib/writer/theme_writer.rb +346 -0
  36. data/lib/writer/workbook_rels_writer.rb +59 -0
  37. data/lib/writer/workbook_writer.rb +77 -0
  38. data/lib/writer/worksheet_writer.rb +208 -0
  39. data/lib/zip.rb +20 -0
  40. data/pkg/rubyXL-1.0.4.gem +0 -0
  41. data/rubyXL.gemspec +106 -0
  42. data/spec/lib/cell_spec.rb +359 -0
  43. data/spec/lib/color_spec.rb +14 -0
  44. data/spec/lib/hash_spec.rb +28 -0
  45. data/spec/lib/parser_spec.rb +49 -0
  46. data/spec/lib/workbook_spec.rb +51 -0
  47. data/spec/lib/worksheet_spec.rb +1650 -0
  48. metadata +222 -0
@@ -0,0 +1,50 @@
1
+ require '../rubyXL'
2
+ require 'rubygems'
3
+ # require File.expand_path(File.join(File.dirname(__FILE__),'workbook'))
4
+ # require File.expand_path(File.join(File.dirname(__FILE__),'parser'))
5
+ # require File.expand_path(File.join(File.dirname(__FILE__),'color'))
6
+ # require File.expand_path(File.join(File.dirname(__FILE__),'cell'))
7
+
8
+ module RubyXL
9
+ wb = Workbook.new([],nil)
10
+ wb.worksheets = [Worksheet.new(wb,'Sheet1')]
11
+ cell = wb.worksheets[0].add_cell(0,0,'1.00.0')
12
+ # cell.change_font_italics(false)
13
+ # p cell.is_italicized(wb)
14
+ # cell.change_font_bold(false)
15
+ # p cell.is_bolded(wb)
16
+ # cell.change_font_underline(false)
17
+ # p cell.is_underlined(wb)
18
+ # p cell.font_name(wb)
19
+ # p cell.font_size(wb)
20
+ # p cell.font_color(wb)
21
+ # p cell.fill_color(wb)
22
+
23
+ wb.worksheets[0].add_cell(2,5,'$1,000.00')
24
+ wb.worksheets[0].add_cell(3,3,'6/14/11')
25
+ wb.worksheets[0].add_cell(4,0,1)
26
+ wb.worksheets[0].add_cell(4,1,2)
27
+ wb.worksheets[0].add_cell(4,2,3)
28
+ wb.worksheets[0].add_cell(4,3,4)
29
+ wb.worksheets[0].add_cell(4,4,0,'AVERAGE(A5:D5)')
30
+
31
+ cell.change_font_color('ff0000')
32
+
33
+ wb.write('/Users/vbhagwat/Desktop/test2/Output/nums.xlsx')
34
+
35
+
36
+ wb2 = Parser.parse('/Users/vbhagwat/Desktop/5-1_5-20.xlsx')
37
+ # wb2.worksheets[0].merge_cells(0,1,0,2)
38
+ # wb2.worksheets[0].merge_cells(0,0,0,1)
39
+ #.change_font_size(30)
40
+ wb2.write('/Users/vbhagwat/Desktop/test2/Output/nums2.xlsx')
41
+
42
+ wb3 = Parser.parse('/Users/vbhagwat/Documents/excelTestFiles/paneWorkbook2/paneWorkbook2.xlsx')
43
+
44
+
45
+
46
+ # p Color.find(8)
47
+ # c = Color::ColorProperties
48
+ # p c.has_value?({:hex=>'#000000', :name=>"black"})
49
+ # p Color.find('black')
50
+ end
@@ -0,0 +1,48 @@
1
+ require '../rubyXL'
2
+ require 'rubygems'
3
+ require 'rubyXL'
4
+ # require File.expand_path(File.join(File.dirname(__FILE__),'workbook'))
5
+
6
+ module RubyXL
7
+ wb = Workbook.new([],nil)
8
+ wb.worksheets = [Worksheet.new(wb,'Sheet1')]
9
+
10
+ cell = wb.worksheets[0].add_cell(0,0,'A1')
11
+ cell2 = wb.worksheets[0].add_cell(0,1,'B1')
12
+ cell3 = wb.worksheets[0].add_cell(0,5,'F1')
13
+
14
+ wb.worksheets[0].sheet_data[0].each do |c|
15
+ unless c.nil?
16
+ c.change_font_bold(true)
17
+ c.change_font_underline(true)
18
+ end
19
+ end
20
+
21
+ cell.change_horizontal_alignment('center')
22
+ wb.worksheets[0].change_row_horizontal_alignment(0,'justify')
23
+ wb.worksheets[0].change_row_vertical_alignment(0,'center')
24
+
25
+ wb.worksheets[0].change_row_fill(0,'FF0000')
26
+ cell2.change_fill('0000FF')
27
+
28
+ cell4 = wb.worksheets[0].add_cell(0,3,'D1')
29
+ puts '
30
+
31
+
32
+
33
+ '
34
+ p wb.fills
35
+ puts '
36
+
37
+
38
+
39
+
40
+ '
41
+ cell4.change_fill('A43502')
42
+
43
+ cell5 = wb.worksheets[0].add_cell(1,0,'A2')
44
+ wb.worksheets[0].change_row_fill(1,'00FF00')
45
+ cell5.change_fill('FF0000')
46
+
47
+ wb.write('/Users/vbhagwat/Desktop/test2/Output/test7.xlsx')
48
+ end
@@ -0,0 +1,12 @@
1
+ require '../rubyXL'
2
+ require 'rubygems'
3
+ # require File.expand_path(File.join(File.dirname(__FILE__),'workbook'))
4
+ # require File.expand_path(File.join(File.dirname(__FILE__),'parser'))
5
+
6
+ module RubyXL
7
+
8
+ wb = Parser.parse('/Users/vbhagwat/Desktop/macros.xlsm', false)
9
+ wb.write('/Users/vbhagwat/Desktop/test2/Output/macros.xlsm')
10
+ puts "completed writing /Users/vbhagwat/Desktop/test2/Output/macros.xlsm"
11
+
12
+ end
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+ require File.expand_path(File.join(File.dirname(__FILE__),'Hash'))
4
+
5
+ module RubyXL
6
+ testWb = Nokogiri::XML.parse(File.read('/Users/vbhagwat/Desktop/testWorkbook.xml'))
7
+ testStyles = Nokogiri::XML.parse(File.read('/Users/vbhagwat/Desktop/testStyles.xml'))
8
+
9
+ puts "testWb.css('workbook definedNames')[0]"
10
+ p testWb.css('workbook definedNames')[0]
11
+ puts '/css'
12
+
13
+
14
+
15
+
16
+ Hash.xml_node_to_hash(test_wb.css('workbook definedNames')[0])
17
+
18
+ puts '
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+ '
39
+ h= Hash.xml_node_to_hash(test_styles.css('styleSheet cellXfs')[0])
40
+
41
+ puts '
42
+
43
+
44
+
45
+
46
+
47
+ '
48
+ p h
49
+ #
50
+ # :cellXfs=>{
51
+ # :xf=>[{
52
+ # :attributes=>{
53
+ # :xfId=>0, :fontId=>0, :numFmtId=>0, :borderId=>0, :fillId=>0}},
54
+ # {:attributes=>{
55
+ # :applyFill=>0, :applyFont=>0, :applyAlignment=>1, :xfId=>0, :fontId=>0,
56
+ # :numFmtId=>0, :applyNumberFormat=>0, :borderId=>0, :applyBorder=>0, :fillId=>0},
57
+ # :alignment=>{:attributes=>{:horizontal=>"center"}}}],
58
+ #
59
+ # :attributes=>{:count=>2}}
60
+ end
@@ -0,0 +1,336 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','content_types_writer'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','root_rels_writer'))
3
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','app_writer'))
4
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','core_writer'))
5
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','theme_writer'))
6
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','workbook_rels_writer'))
7
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','workbook_writer'))
8
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','styles_writer'))
9
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','shared_strings_writer'))
10
+ require File.expand_path(File.join(File.dirname(__FILE__),'writer','worksheet_writer'))
11
+ require 'zip'
12
+
13
+ module RubyXL
14
+ class Workbook
15
+ attr_accessor :worksheets, :filepath, :creator, :modifier, :created_at,
16
+ :modified_at, :company, :application, :appversion, :num_fmts, :fonts, :fills,
17
+ :borders, :cell_xfs, :cell_style_xfs, :cell_styles, :shared_strings, :calc_chain,
18
+ :num_strings, :size, :date1904, :external_links, :style_corrector, :drawings,
19
+ :worksheet_rels, :printer_settings, :macros, :colors, :shared_strings_XML
20
+
21
+ APPLICATION = 'Microsoft Macintosh Excel'
22
+ APPVERSION = '12.0000'
23
+ SHEET_NAME = 'Sheet1'
24
+ def initialize(worksheets=[], filepath=nil, creator=nil, modifier=nil, created_at=nil,
25
+ company='', application=APPLICATION,
26
+ appversion=APPVERSION, date_1904=0)
27
+ if worksheets.nil? || worksheets.empty?
28
+ @worksheets = [Worksheet.new(self,SHEET_NAME)]
29
+ else
30
+ @worksheets = worksheets
31
+ end
32
+ @filepath = filepath
33
+ @creator = creator
34
+ @modifier = modifier
35
+ @company = company
36
+ @application = application
37
+ @appversion = appversion
38
+ @num_fmts = nil
39
+ @fonts = nil
40
+ @fills = nil
41
+ @borders = nil
42
+ @cell_xfs = nil
43
+ @cell_style_xfs = nil
44
+ @cell_styles = nil
45
+ @shared_strings = nil
46
+ @calc_chain = nil #unnecessary?
47
+ @num_strings = 0 #num strings total
48
+ @size = 0 #num strings in shared_strings array
49
+ @date_1904 = date_1904
50
+ @external_links = nil
51
+ @style_corrector = nil
52
+ @drawings = nil
53
+ @worksheet_rels = nil
54
+ @printer_settings = nil
55
+ @macros = nil
56
+ @colors = nil
57
+ @shared_strings_XML = nil
58
+
59
+ begin
60
+ @created_at = DateTime.parse(created_at).strftime('%Y-%m-%dT%TZ')
61
+ rescue
62
+ t = Time.now
63
+ @created_at = t.strftime('%Y-%m-%dT%TZ')
64
+ end
65
+ @modified_at = @created_at
66
+
67
+ fill_styles()
68
+ fill_shared_strings()
69
+ end
70
+
71
+ # allows easier access to worksheets
72
+ def [](worksheet)
73
+ return worksheets[worksheet]
74
+ end
75
+
76
+ #filepath of xlsx file (including file itself)
77
+ def write(filepath=@filepath)
78
+ validate_before_write
79
+ dirpath = ''
80
+ extension = 'xls'
81
+ if(filepath =~ /((.|\s)*)\.xls(x|m)$/)
82
+ dirpath = $1.to_s()
83
+ extension += $3.to_s
84
+ end
85
+ filename = ''
86
+ if(filepath =~ /\/((.|\s)*)\/((.|\s)*)\.xls(x|m)$/)
87
+ filename = $3.to_s()
88
+ end
89
+
90
+ #creates zip file, writes each type of file to zip folder
91
+ #zips package and renames it to xlsx.
92
+ zippath = File.join(dirpath, filename + '.zip')
93
+ File.unlink(zippath) if File.exists?(zippath)
94
+ FileUtils.mkdir_p(File.join(dirpath,zippath))
95
+ Zip::ZipFile.open(zippath, Zip::ZipFile::CREATE) do |zipfile|
96
+ writer = Writer::ContentTypesWriter.new(dirpath,self)
97
+ zipfile.get_output_stream('[Content_Types].xml') {|f| f.puts(writer.write())}
98
+
99
+ writer = Writer::RootRelsWriter.new(dirpath,self)
100
+ zipfile.get_output_stream(File.join('_rels','.rels')) {|f| f.puts(writer.write())}
101
+
102
+ writer = Writer::AppWriter.new(dirpath,self)
103
+ zipfile.get_output_stream(File.join('docProps','app.xml')) {|f| f.puts(writer.write())}
104
+
105
+ writer = Writer::CoreWriter.new(dirpath,self)
106
+ zipfile.get_output_stream(File.join('docProps','core.xml')) {|f| f.puts(writer.write())}
107
+
108
+ writer = Writer::ThemeWriter.new(dirpath,self)
109
+ zipfile.get_output_stream(File.join('xl','theme','theme1.xml')) {|f| f.puts(writer.write())}
110
+
111
+ writer = Writer::WorkbookRelsWriter.new(dirpath,self)
112
+ zipfile.get_output_stream(File.join('xl','_rels','workbook.xml.rels')) {|f| f.puts(writer.write())}
113
+
114
+ writer = Writer::WorkbookWriter.new(dirpath,self)
115
+ zipfile.get_output_stream(File.join('xl','workbook.xml')) {|f| f.puts(writer.write())}
116
+
117
+ writer = Writer::StylesWriter.new(dirpath,self)
118
+ zipfile.get_output_stream(File.join('xl','styles.xml')) {|f| f.puts(writer.write())}
119
+
120
+ unless @shared_strings.nil?
121
+ writer = Writer::SharedStringsWriter.new(dirpath,self)
122
+ zipfile.get_output_stream(File.join('xl','sharedStrings.xml')) {|f| f.puts(writer.write())}
123
+ end
124
+
125
+ #preserves external links (exactly, no modification allowed)
126
+ unless @external_links.nil?
127
+ #-1 because of rels
128
+ 1.upto(@external_links.size-1) do |i|
129
+ zipfile.get_output_stream(
130
+ File.join('xl','externalLinks',"externalLink#{i}.xml")) {|f|
131
+ f.puts(@external_links[i])
132
+ }
133
+ end
134
+ @external_links['rels'].each_index do |i|
135
+ unless @external_links['rels'][i].nil?
136
+ zipfile.get_output_stream(
137
+ File.join('xl','externalLinks','_rels',"externalLink#{i}.xml.rels")) {|f|
138
+ f.puts(@external_links['rels'][i])
139
+ }
140
+ end
141
+ end
142
+ end
143
+
144
+ #preserves drawings (exactly, no modification allowed)
145
+ unless @drawings.nil?
146
+ 1.upto(@drawings.size) do |i|
147
+ zipfile.get_output_stream(
148
+ File.join('xl','drawings',"vmlDrawing#{i}.vml")) {|f|
149
+ f.puts(@drawings[i])
150
+ }
151
+ end
152
+ end
153
+
154
+ unless @printer_settings.nil?
155
+ 1.upto(@printer_settings.size) do |i|
156
+ zipfile.get_output_stream(
157
+ File.join('xl','printerSettings',"printerSettings#{i}.bin")) {|f|
158
+ f.puts(@printer_settings[i])
159
+ }
160
+ end
161
+ end
162
+
163
+ unless @worksheet_rels.nil?
164
+ 1.upto(@worksheet_rels.size) do |i|
165
+ zipfile.get_output_stream(
166
+ File.join('xl','worksheets','_rels',"sheet#{i}.xml.rels")) {|f|
167
+ f.puts(@worksheet_rels[i])
168
+ }
169
+ end
170
+ end
171
+
172
+ unless @macros.nil?
173
+ zipfile.get_output_stream(File.join('xl','vbaProject.bin')) {|f| f.puts(@macros)}
174
+ end
175
+
176
+ @worksheets.each_with_index do |sheet,i|
177
+ writer = Writer::WorksheetWriter.new(dirpath,self,i)
178
+ zipfile.get_output_stream(File.join('xl','worksheets',"sheet#{i+1}.xml")) {|f| f.puts(writer.write())}
179
+ end
180
+ end
181
+
182
+ FileUtils.cp(zippath,File.join(dirpath,filename+".#{extension}"))
183
+ FileUtils.cp(File.join(dirpath,filename+".#{extension}"),filepath)
184
+ if File.exist?(filepath)
185
+ FileUtils.rm_rf(dirpath)
186
+ end
187
+ end
188
+
189
+ #gets style object from style array given index
190
+ def get_style(style_index)
191
+ if !@cell_xfs[:xf].is_a?Array
192
+ @cell_xfs[:xf] = [@cell_xfs[:xf]]
193
+ end
194
+
195
+ xf_obj = @cell_xfs[:xf]
196
+ if xf_obj.is_a?Array
197
+ xf_obj = xf_obj[Integer(style_index)]
198
+ end
199
+ xf_obj
200
+ end
201
+
202
+ #gets attributes of above style object
203
+ #necessary because can take the form of hash or array,
204
+ #based on odd behavior of Nokogiri
205
+ def get_style_attributes(xf_obj)
206
+ if xf_obj.is_a?Array
207
+ xf = xf_obj[1]
208
+ else
209
+ xf = xf_obj[:attributes]
210
+ end
211
+ end
212
+
213
+ def get_fill_color(xf_attributes)
214
+ if @fills[xf_attributes[:fillId]].nil? || @fills[xf_attributes[:fillId]][:fill].nil? || @fills[xf_attributes[:fillId]][:fill][:patternFill].nil? || @fills[xf_attributes[:fillId]][:fill][:patternFill][:fgColor].nil?
215
+ 'ffffff' #white
216
+ else
217
+ @fills[xf_attributes[:fillId]][:fill][:patternFill][:fgColor][:attributes][:rgb]
218
+ end
219
+ end
220
+
221
+
222
+ private
223
+
224
+ # Do not change. Excel requires that some of these styles be default,
225
+ # and will simply assume that the 0 and 1 indexed fonts are the default values.
226
+ def fill_styles()
227
+ @fonts = {
228
+ '0' => {
229
+ :font => {
230
+ :sz => { :attributes => { :val => 10 } },
231
+ :name => { :attributes => { :val => "Verdana" } }
232
+ },
233
+ :count=>1
234
+ },
235
+ '1' => {
236
+ :font => {
237
+ :sz => { :attributes => { :val => 8 } },
238
+ :name => { :attributes => { :val => "Verdana" } }
239
+ },
240
+ :count=>0
241
+ }
242
+ }
243
+
244
+ @fills = {
245
+ '0' => {
246
+ :fill => {
247
+ :patternFill => { :attributes => { :patternType => "none" } }
248
+ },
249
+ :count=>1} ,
250
+ '1' => {
251
+ :fill => {
252
+ :patternFill => { :attributes => { :patternType => "gray125" } }
253
+ },
254
+ :count=>0
255
+ }
256
+ }
257
+
258
+ @borders = {
259
+ '0' => {
260
+ :border => {
261
+ :left => { },
262
+ :right => { },
263
+ :top => { },
264
+ :bottom => { },
265
+ :diagonal => { }
266
+ },
267
+ :count => 1 #count = how many styles reference it
268
+ }
269
+ }
270
+
271
+ @cell_style_xfs = {
272
+ :attributes => {
273
+ :count => 1
274
+ },
275
+ :xf => {
276
+ :attributes => { :numFmtId => 0, :fontId => 0, :fillId => 0, :borderId => 0 }
277
+ }
278
+ }
279
+ @cell_xfs = {
280
+ :attributes => {
281
+ :count => 1
282
+ },
283
+ :xf => {
284
+ :attributes => { :numFmtId => 0, :fontId => 0, :fillId => 0, :borderId => 0, :xfId => 0 }
285
+ }
286
+ }
287
+ @cell_styles = {
288
+ :cellStyle => {
289
+ :attributes => { :builtinId=>0, :name=>"Normal", :xfId=>0 }
290
+ },
291
+ :attributes => { :count => 1 }
292
+ }
293
+ end
294
+
295
+
296
+ #fills shared strings hash, contains each unique string
297
+ def fill_shared_strings()
298
+ if @shared_strings.nil?
299
+ string_hash = {}
300
+ string_index = 0
301
+ @num_strings = 0
302
+ #fill hash for shared strings
303
+ @worksheets.each do |sheet|
304
+ unless sheet.nil?
305
+ sheet.sheet_data.each do |row|
306
+ row.each do |cell|
307
+ unless cell.nil? || cell.value.nil?
308
+ #if string not already seen, add it to hash
309
+ if cell.datatype == 's'
310
+ if string_hash[cell.value.to_s].nil?
311
+ string_hash[string_index]=cell.value.to_s
312
+ string_hash[cell.value.to_s]=string_index
313
+ string_index += 1
314
+ end
315
+ @num_strings += 1
316
+ end
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ if string_hash[0].nil?
324
+ @shared_strings = nil
325
+ else
326
+ @shared_strings = string_hash
327
+ @size = string_index
328
+ end
329
+ end
330
+ end
331
+
332
+ def validate_before_write
333
+ ## TODO CHECK IF STYLE IS OK if not raise
334
+ end
335
+ end
336
+ end