rubyXL 1.0.4

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.
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,1245 @@
1
+ module RubyXL
2
+ class Worksheet < PrivateClass
3
+
4
+ attr_accessor :sheet_name, :sheet_data, :cols, :merged_cells, :pane,
5
+ :validations, :sheet_view, :legacy_drawing, :extLst, :workbook, :row_styles
6
+
7
+ def initialize(workbook, sheet_name='Sheet1',sheet_data=[[nil]],cols=[], merged_cells=[])
8
+ @workbook = workbook
9
+
10
+ @sheet_name = sheet_name
11
+ @sheet_data = sheet_data
12
+ @cols = cols
13
+ @merged_cells = merged_cells
14
+ @row_styles={}
15
+ @sheet_view = {
16
+ :attributes => {
17
+ :workbookViewId => 0, :zoomScale => 100, :tabSelected => 1, :view=>'normalLayout', :zoomScaleNormal => 100
18
+ }
19
+ }
20
+ @extLst = nil
21
+ @legacy_drawing=nil
22
+ end
23
+
24
+ # allows for easier access to sheet_data
25
+ def [](row=0)
26
+ return @sheet_data[row]
27
+ end
28
+
29
+ def get_table(headers=[])
30
+ validate_workbook
31
+
32
+ if !headers.is_a?(Array)
33
+ headers = [headers]
34
+ end
35
+
36
+ row_num = find_first_row_with_content(headers)
37
+
38
+ if row_num.nil?
39
+ return nil
40
+ end
41
+
42
+ table_hash = {}
43
+ table_hash[:table] = []
44
+
45
+ headers.each do |header|
46
+ row_strings = @sheet_data[row_num].map { |cell| cell.nil? ? '' : cell.value.to_s }
47
+ header_column = row_strings.index(header)
48
+ table_hash[header.to_sym] = []
49
+
50
+ original_row = row_num + 1
51
+ current_row = original_row
52
+
53
+ cell = @sheet_data[current_row][header_column]
54
+
55
+ # makes array of hashes in table_hash[:table]
56
+ # as well as hash of arrays in table_hash[header.to_sym]
57
+ while !cell.nil? && !cell.value.nil?
58
+ table_hash[header.to_sym] << cell.value
59
+
60
+ table_index = current_row - original_row
61
+
62
+ if table_hash[:table][table_index].nil?
63
+ table_hash[:table][table_index] = {}
64
+ end
65
+
66
+ table_hash[:table][table_index][header.to_sym] = cell.value
67
+
68
+ current_row += 1
69
+ if @sheet_data[current_row].nil?
70
+ cell = nil
71
+ else
72
+ cell = @sheet_data[current_row][header_column]
73
+ end
74
+ end
75
+ end
76
+
77
+ return table_hash
78
+ end
79
+
80
+ #changes color of fill in (zer0 indexed) row
81
+ def change_row_fill(row=0,rgb='ffffff')
82
+ validate_workbook
83
+ validate_nonnegative(row)
84
+ increase_rows(row)
85
+ Color.validate_color(rgb)
86
+ if @row_styles[(Integer(row)+1).to_s].nil?
87
+ @row_styles[(Integer(row)+1).to_s] = {}
88
+ @row_styles[(Integer(row)+1).to_s][:style] = '0'
89
+ end
90
+
91
+ @row_styles[(Integer(row)+1).to_s][:style] = modify_fill(@workbook,Integer(@row_styles[(Integer(row)+1).to_s][:style]),rgb)
92
+
93
+ @sheet_data[Integer(row)].each do |c|
94
+ unless c.nil?
95
+ c.change_fill(rgb)
96
+ end
97
+ end
98
+ end
99
+
100
+ def change_row_font_name(row=0,font_name='Verdana')
101
+ change_row_font(row,Worksheet::NAME,font_name)
102
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:name][:attributes][:val] = font_name.to_s
103
+ end
104
+
105
+ def change_row_font_size(row=0,font_size=10)
106
+ change_row_font(row,Worksheet::SIZE,font_size)
107
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:sz][:attributes][:val] = font_size
108
+ end
109
+
110
+ def change_row_font_color(row=0,font_color='000000')
111
+ Color.validate_color(font_color)
112
+
113
+ change_row_font(row,Worksheet::COLOR,font_color)
114
+
115
+ font = @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font]
116
+ if font[:color].nil? || font[:color][:attributes].nil?
117
+ font[:color] = { :attributes => { :rgb => nil } }
118
+ end
119
+ font[:color][:attributes][:rgb] = font_color.to_s
120
+ end
121
+
122
+ def change_row_italics(row=0,italicized=false)
123
+ change_row_font(row,Worksheet::ITALICS,italicized)
124
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:i] = italicized ? {} : nil
125
+ end
126
+
127
+ def change_row_bold(row=0,bolded=false)
128
+ change_row_font(row,Worksheet::BOLD,bolded)
129
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:b] = bolded ? {} : nil
130
+ end
131
+
132
+ def change_row_underline(row=0,underlined=false)
133
+ change_row_font(row,Worksheet::UNDERLINE,underlined)
134
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:u] = underlined ? {} : nil
135
+ end
136
+
137
+ def change_row_strikethrough(row=0,struckthrough=false)
138
+ change_row_font(row,Worksheet::STRIKETHROUGH,struckthrough)
139
+ @workbook.fonts[font_id(@row_styles[(row+1).to_s][:style])][:font][:strike] = struckthrough ? {} : nil
140
+ end
141
+
142
+ def change_row_height(row=0,height=10)
143
+ validate_workbook
144
+ validate_nonnegative(row)
145
+
146
+ increase_rows(row)
147
+
148
+ if height.to_i.to_s == height.to_s
149
+ height = Integer(height)
150
+ elsif height.to_f.to_s == height.to_s
151
+ height = Float(height)
152
+ else
153
+ raise 'You must enter a number for the height'
154
+ end
155
+
156
+ if @row_styles[(row+1).to_s].nil?
157
+ @row_styles[(row+1).to_s] = {}
158
+ @row_styles[(row+1).to_s][:style] = '0'
159
+ end
160
+ @row_styles[(row+1).to_s][:height] = height
161
+ @row_styles[(row+1).to_s][:customHeight] = '1'
162
+ end
163
+
164
+ def change_row_horizontal_alignment(row=0,alignment='center')
165
+ validate_workbook
166
+ validate_nonnegative(row)
167
+ validate_horizontal_alignment(alignment)
168
+ change_row_alignment(row,alignment,true)
169
+ end
170
+
171
+ def change_row_vertical_alignment(row=0,alignment='center')
172
+ validate_workbook
173
+ validate_nonnegative(row)
174
+ validate_vertical_alignment(alignment)
175
+ change_row_alignment(row,alignment,false)
176
+ end
177
+
178
+ def change_row_border_top(row=0,weight='thin')
179
+ change_row_border(row, :top, weight)
180
+ end
181
+
182
+ def change_row_border_left(row=0,weight='thin')
183
+ change_row_border(row, :left, weight)
184
+ end
185
+
186
+ def change_row_border_right(row=0,weight='thin')
187
+ change_row_border(row, :right, weight)
188
+ end
189
+
190
+ def change_row_border_bottom(row=0,weight='thin')
191
+ change_row_border(row, :bottom, weight)
192
+ end
193
+
194
+ def change_row_border_diagonal(row=0,weight='thin')
195
+ change_row_border(row, :diagonal, weight)
196
+ end
197
+
198
+ def change_column_font_name(col=0,font_name='Verdana')
199
+ s = change_column_font(col,Worksheet::NAME,font_name)
200
+ @workbook.fonts[font_id(s)][:font][:name][:attributes][:val] = font_name.to_s
201
+ end
202
+
203
+ def change_column_font_size(col=0,font_size=10)
204
+ s = change_column_font(col,Worksheet::SIZE,font_size)
205
+ @workbook.fonts[font_id(s)][:font][:sz][:attributes][:val] = font_size
206
+ end
207
+
208
+ def change_column_font_color(col=0,font_color='000000')
209
+ Color.validate_color(font_color)
210
+ s = change_column_font(col,Worksheet::COLOR,font_color)
211
+
212
+ font = @workbook.fonts[font_id(s)][:font]
213
+ if font[:color].nil? || font[:color][:attributes].nil?
214
+ font[:color] = { :attributes => { :rgb => nil } }
215
+ end
216
+
217
+ font[:color][:attributes][:rgb] = font_color.to_s
218
+ end
219
+
220
+ def change_column_italics(col=0,italicized=false)
221
+ s = change_column_font(col,Worksheet::ITALICS,italicized)
222
+ @workbook.fonts[font_id(s)][:font][:i] = italicized ? {} : nil
223
+ end
224
+
225
+ def change_column_bold(col=0,bolded=false)
226
+ s = change_column_font(col,Worksheet::BOLD,bolded)
227
+ @workbook.fonts[font_id(s)][:font][:b] = bolded ? {} : nil
228
+ end
229
+
230
+ def change_column_underline(col=0,underlined=false)
231
+ s = change_column_font(col,Worksheet::UNDERLINE,underlined)
232
+ @workbook.fonts[font_id(s)][:font][:u] = underlined ? {} : nil
233
+ end
234
+
235
+ def change_column_strikethrough(col=0,struckthrough=false)
236
+ s = change_column_font(col,Worksheet::STRIKETHROUGH,struckthrough)
237
+ @workbook.fonts[font_id(s)][:font][:strike] = struckthrough ? {} : nil
238
+ end
239
+
240
+ def change_column_width(col=0,width=13)
241
+ validate_workbook
242
+ validate_nonnegative(col)
243
+ increase_columns(col)
244
+
245
+ i = get_cols_index(col)
246
+
247
+ if width.to_i.to_s == width.to_s
248
+ width = Integer(width)
249
+ elsif width.to_f.to_s == width.to_s
250
+ width = Float(width)
251
+ else
252
+ raise 'You must enter a number for the width'
253
+ end
254
+
255
+ change_cols(i,col)
256
+ @cols.last[:attributes][:width] = width
257
+ @cols.last[:attributes][:customWidth] = '1'
258
+ end
259
+
260
+ def change_column_fill(col=0, color_index='ffffff')
261
+ validate_workbook
262
+ validate_nonnegative(col)
263
+ Color.validate_color(color_index)
264
+ increase_columns(col)
265
+
266
+ i = get_cols_index(col)
267
+
268
+ if cols[i].nil?
269
+ style_index = 0
270
+ else
271
+ #just copies any style if there is none which already exists for this col
272
+ #while it changes style/min/max, width *might* be preserved
273
+ style_index = Integer(@cols[i][:attributes][:style])
274
+ end
275
+
276
+ modify_fill(@workbook,style_index,color_index)
277
+
278
+ change_cols(i,col)
279
+
280
+ @sheet_data.each_with_index do |row,i|
281
+ c = row[Integer(col)]
282
+ unless c.nil?
283
+ c.change_fill(color_index)
284
+ end
285
+ end
286
+
287
+ end
288
+
289
+ def change_column_horizontal_alignment(col=0,alignment='center')
290
+ validate_workbook
291
+ validate_nonnegative(col)
292
+ validate_horizontal_alignment(alignment)
293
+ change_column_alignment(col,alignment,true)
294
+ end
295
+
296
+ def change_column_vertical_alignment(col=0,alignment='center')
297
+ validate_workbook
298
+ validate_nonnegative(col)
299
+ validate_vertical_alignment(alignment)
300
+ change_column_alignment(col,alignment,false)
301
+ end
302
+
303
+ def change_column_border_top(col=0,weight='thin')
304
+ change_column_border(col,:top,weight)
305
+ end
306
+
307
+ def change_column_border_left(col=0,weight='thin')
308
+ change_column_border(col,:left,weight)
309
+ end
310
+
311
+ def change_column_border_right(col=0,weight='thin')
312
+ change_column_border(col,:right,weight)
313
+ end
314
+
315
+ def change_column_border_bottom(col=0,weight='thin')
316
+ change_column_border(col,:bottom,weight)
317
+ end
318
+
319
+ def change_column_border_diagonal(col=0,weight='thin')
320
+ change_column_border(col,:diagonal,weight)
321
+ end
322
+
323
+ # merges cells within a rectangular range
324
+ def merge_cells(row1=0,col1=0,row2=0,col2=0)
325
+ validate_workbook
326
+ @merged_cells << {
327
+ :attributes => {
328
+ :ref => ''
329
+ }
330
+ }
331
+ cell1 = Cell.convert_to_cell(row1,col1)
332
+ cell2 = Cell.convert_to_cell(row2,col2)
333
+ @merged_cells.last[:attributes][:ref] = cell1+':'+cell2
334
+ end
335
+
336
+ def add_cell(row=0, column=0, data='', formula=nil,overwrite=true)
337
+ validate_workbook
338
+ validate_nonnegative(row)
339
+ validate_nonnegative(column)
340
+
341
+ unless @sheet_data.size > row && @sheet_data[row].size > column
342
+ increase_columns(column)
343
+ increase_rows(row)
344
+ end
345
+
346
+ datatype = 'str'
347
+ unless formula.nil?
348
+ datatype = ''
349
+ end
350
+ if overwrite || @sheet_data[row][column].nil?
351
+ @sheet_data[row][column] = Cell.new(self,row,column,data,formula,datatype)
352
+
353
+ if (data.is_a?Integer) || (data.is_a?Float)
354
+ @sheet_data[row][column].datatype = ''
355
+ end
356
+ col = @cols[get_cols_index(column)]
357
+
358
+ if @row_styles[(row+1).to_s] != nil
359
+ @sheet_data[row][column].style_index = @row_styles[(row+1).to_s][:style]
360
+ elsif col != nil
361
+ @sheet_data[row][column].style_index = col[:attributes][:style]
362
+ end
363
+ end
364
+
365
+ add_cell_style(row,column)
366
+
367
+ return @sheet_data[row][column]
368
+ end
369
+
370
+ def add_cell_obj(cell, overwrite=true)
371
+ validate_workbook
372
+
373
+ if cell.nil?
374
+ return cell
375
+ end
376
+
377
+ row = cell.row
378
+ column = cell.column
379
+
380
+ validate_nonnegative(row)
381
+ validate_nonnegative(column)
382
+
383
+ unless @sheet_data.size > row && @sheet_data[row].size > column
384
+ increase_columns(column)
385
+ increase_rows(row)
386
+ end
387
+ if overwrite || @sheet_data[row][column].nil?
388
+ @sheet_data[row][column] = cell
389
+ end
390
+
391
+ add_cell_style(row,column)
392
+
393
+ return @sheet_data[row][column]
394
+ end
395
+
396
+ #inserts row at row_index, pushes down, copies style from below (row previously at that index)
397
+ #USE OF THIS METHOD will break formulas which reference cells which are being "pushed down"
398
+ def insert_row(row_index)
399
+ validate_workbook
400
+ validate_nonnegative(row_index)
401
+
402
+ increase_rows(row_index)
403
+
404
+ @sheet_data.insert(row_index,Array.new(@sheet_data[row_index].size))
405
+
406
+ row_num = row_index+1
407
+
408
+ #copy cell styles from row above, (or below if first row)
409
+ @sheet_data[row_index].each_index do |i|
410
+ if row_index > 0
411
+ old_cell = @sheet_data[row_index-1][i]
412
+ else
413
+ old_cell = @sheet_data[row_index+1][i]
414
+ end
415
+
416
+ unless old_cell.nil?
417
+ #only add cell if style exists, not copying content
418
+
419
+ if @row_styles[(row_num+1).to_s].nil?
420
+ @row_styles[(row_num+1).to_s] = {:style=>0}
421
+ end
422
+ if old_cell.style_index != 0 && old_cell.style_index.to_s != @row_styles[(row_num+1).to_s][:style].to_s
423
+ c = Cell.new(self,row_index,i)
424
+ c.style_index = old_cell.style_index
425
+ @sheet_data[row_index][i] = c
426
+ end
427
+ end
428
+ end
429
+
430
+ #copy row styles from row above, (or below if first row)
431
+ (@row_styles.size+1).downto(row_num+1) do |i|
432
+ @row_styles[i.to_s] = @row_styles[(i-1).to_s]
433
+ end
434
+ if row_index > 0
435
+ @row_styles[row_num.to_s] = @row_styles[(row_num-1).to_s]
436
+ else
437
+ @row_styles[row_num.to_s] = nil#@row_styles[(row_num+1).to_s]
438
+ end
439
+
440
+ #update row value for all rows below
441
+ (row_index+1).upto(@sheet_data.size-1) do |i|
442
+ row = @sheet_data[i]
443
+ row.each do |c|
444
+ unless c.nil?
445
+ c.row += 1
446
+ end
447
+ end
448
+ end
449
+
450
+ return @sheet_data[row_index]
451
+ end
452
+
453
+ # inserts column at col_index, pushes everything right, takes styles from column to left
454
+ # USE OF THIS METHOD will break formulas which reference cells which are being "pushed down"
455
+ def insert_column(col_index)
456
+ validate_workbook
457
+ validate_nonnegative(col_index)
458
+ increase_columns(col_index)
459
+
460
+ old_index = col_index > 0 ? col_index-1 : col_index+1
461
+ old_col = @cols[get_cols_index(old_index)]
462
+ if old_index == 1
463
+ old_col = nil
464
+ end
465
+
466
+ #go through each cell in column
467
+ @sheet_data.each_with_index do |r,i|
468
+ #insert "column" in each row
469
+ r.insert(col_index, nil)
470
+
471
+ #copy styles over to each cell
472
+ old_cell = r[old_index]
473
+ unless old_cell.nil?
474
+ #only add cell if style exists, not copying content
475
+ if old_cell.style_index != 0
476
+ if !old_col.nil? && old_cell.style_index.to_s != old_col[:attributes][:style].to_s
477
+ c = Cell.new(self,i,col_index)
478
+ c.style_index = old_cell.style_index
479
+ @sheet_data[i][col_index] = c
480
+ end
481
+ end
482
+ end
483
+ end
484
+
485
+ #copy over column-level styles
486
+ new_col = change_cols(get_cols_index(old_index),old_index)
487
+ @cols[-1] = deep_copy(old_col)#-1 = last
488
+
489
+ new_col = @cols.last
490
+ if @cols.last.nil?
491
+ @cols.pop
492
+ end
493
+
494
+ #shift col styles 'right'
495
+ @cols.each do |col|
496
+ if Integer(col[:attributes][:min]) > col_index
497
+ col[:attributes][:min] = (1 + Integer(col[:attributes][:min])).to_s
498
+ end
499
+ if Integer(col[:attributes][:max]) > col_index
500
+ col[:attributes][:max] = (1 + Integer(col[:attributes][:max])).to_s
501
+ end
502
+ end
503
+ unless new_col.nil?
504
+ new_col[:attributes][:min] = (1 + Integer(new_col[:attributes][:min])).to_s
505
+ new_col[:attributes][:max] = (1 + Integer(new_col[:attributes][:max])).to_s
506
+ end
507
+
508
+ #update column numbers
509
+ @sheet_data.each do |row|
510
+ (col_index+1).upto(row.size) do |j|
511
+ unless row[j].nil?
512
+ row[j].column += 1
513
+ end
514
+ end
515
+ end
516
+ end
517
+
518
+ def get_row_fill(row=0)
519
+ validate_workbook
520
+ validate_nonnegative(row)
521
+
522
+ if @sheet_data.size <= row
523
+ return nil
524
+ end
525
+
526
+ if @row_styles[(row+1).to_s].nil?
527
+ return "ffffff" #default, white
528
+ end
529
+
530
+ xf = xf_attr_row(row)
531
+
532
+ return @workbook.get_fill_color(xf)
533
+ end
534
+
535
+ def get_row_font_name(row=0)
536
+ validate_workbook
537
+ validate_nonnegative(row)
538
+
539
+ if @sheet_data.size <= row
540
+ return nil
541
+ end
542
+
543
+ if @row_styles[(row+1).to_s].nil?
544
+ return 'Verdana'
545
+ end
546
+
547
+ xf = xf_attr_row(row)
548
+
549
+ return @workbook.fonts[xf[:fontId].to_s][:font][:name][:attributes][:val]
550
+ end
551
+
552
+ def get_row_font_size(row=0)
553
+ validate_workbook
554
+ validate_nonnegative(row)
555
+
556
+ if @sheet_data.size <= row
557
+ return nil
558
+ end
559
+
560
+ if @row_styles[(row+1).to_s].nil?
561
+ return '10'
562
+ end
563
+
564
+ xf = xf_attr_row(row)
565
+
566
+ return @workbook.fonts[xf[:fontId].to_s][:font][:sz][:attributes][:val]
567
+ end
568
+
569
+ def get_row_font_color(row=0)
570
+ validate_workbook
571
+ validate_nonnegative(row)
572
+
573
+ if @sheet_data.size <= row
574
+ return nil
575
+ end
576
+
577
+ if @row_styles[(row+1).to_s].nil?
578
+ return '000000'
579
+ end
580
+
581
+ xf = xf_attr_row(row)
582
+
583
+ color = @workbook.fonts[xf[:fontId].to_s][:font][:color]
584
+
585
+ if color.nil? || color[:attributes].nil? || color[:attributes][:rgb].nil?
586
+ return '000000'
587
+ end
588
+
589
+ return color[:attributes][:rgb]
590
+ end
591
+
592
+ def is_row_italicized(row=0)
593
+ return get_row_bool(row,:i)
594
+ end
595
+
596
+ def is_row_bolded(row=0)
597
+ return get_row_bool(row,:b)
598
+ end
599
+
600
+ def is_row_underlined(row=0)
601
+ return get_row_bool(row,:u)
602
+ end
603
+
604
+ def is_row_struckthrough(row=0)
605
+ return get_row_bool(row,:strike)
606
+ end
607
+
608
+
609
+ def get_row_height(row=0)
610
+ validate_workbook
611
+ validate_nonnegative(row)
612
+
613
+ if @sheet_data.size <= row
614
+ return nil
615
+ end
616
+
617
+ if @row_styles[(row+1).to_s].nil?
618
+ return 13
619
+ else
620
+ @row_styles[(row+1).to_s][:height]
621
+ end
622
+ end
623
+
624
+ def get_row_horizontal_alignment(row=0)
625
+ return get_row_alignment(row,true)
626
+ end
627
+
628
+ def get_row_vertical_alignment(row=0)
629
+ return get_row_alignment(row,false)
630
+ end
631
+
632
+ def get_row_border_top(row=0)
633
+ return get_row_border(row,:top)
634
+ end
635
+
636
+ def get_row_border_left(row=0)
637
+ return get_row_border(row,:left)
638
+ end
639
+
640
+ def get_row_border_right(row=0)
641
+ return get_row_border(row,:right)
642
+ end
643
+
644
+ def get_row_border_bottom(row=0)
645
+ return get_row_border(row,:bottom)
646
+ end
647
+
648
+ def get_row_border_diagonal(row=0)
649
+ return get_row_border(row,:diagonal)
650
+ end
651
+
652
+ def get_column_font_name(col=0)
653
+ validate_workbook
654
+ validate_nonnegative(col)
655
+
656
+ if @sheet_data[0].size <= col
657
+ return nil
658
+ end
659
+
660
+ style_index = get_cols_style_index(col)
661
+
662
+ return @workbook.fonts[font_id( style_index ).to_s][:font][:name][:attributes][:val]
663
+ end
664
+
665
+ def get_column_font_size(col=0)
666
+ validate_workbook
667
+ validate_nonnegative(col)
668
+
669
+ if @sheet_data[0].size <= col
670
+ return nil
671
+ end
672
+
673
+ style_index = get_cols_style_index(col)
674
+
675
+ return @workbook.fonts[font_id( style_index ).to_s][:font][:sz][:attributes][:val]
676
+ end
677
+
678
+ def get_column_font_color(col=0)
679
+ validate_workbook
680
+ validate_nonnegative(col)
681
+
682
+ if @sheet_data[0].size <= col
683
+ return nil
684
+ end
685
+
686
+ style_index = get_cols_style_index(col)
687
+
688
+ font = @workbook.fonts[font_id( style_index ).to_s][:font]
689
+
690
+ if font[:color].nil? || font[:color][:attributes].nil? || font[:color][:attributes][:rgb].nil?
691
+ return '000000'
692
+ end
693
+
694
+ return font[:color][:attributes][:rgb]
695
+
696
+ end
697
+
698
+ def is_column_italicized(col=0)
699
+ get_column_bool(col,:i)
700
+ end
701
+
702
+ def is_column_bolded(col=0)
703
+ get_column_bool(col,:b)
704
+ end
705
+
706
+ def is_column_underlined(col=0)
707
+ get_column_bool(col,:u)
708
+ end
709
+
710
+ def is_column_struckthrough(col=0)
711
+ get_column_bool(col,:strike)
712
+ end
713
+
714
+ def get_column_width(col=0)
715
+ validate_workbook
716
+ validate_nonnegative(col)
717
+
718
+ if @sheet_data[0].size <= col
719
+ return nil
720
+ end
721
+
722
+ cols_index = get_cols_index(col)
723
+
724
+ if @cols[cols_index].nil? || @cols[cols_index][:attributes].nil? || @cols[cols_index][:attributes][:width].to_s == ''
725
+ return 10
726
+ end
727
+
728
+ return @cols[cols_index][:attributes][:width]
729
+ end
730
+
731
+ def get_column_fill(col=0)
732
+ validate_workbook
733
+ validate_nonnegative(col)
734
+
735
+ if @sheet_data[0].size <= col
736
+ return nil
737
+ end
738
+
739
+ style_index = get_cols_style_index(col)
740
+
741
+ if style_index == 0
742
+ return "ffffff" #default, white
743
+ end
744
+
745
+ return @workbook.get_fill_color(@workbook.cell_xfs[:xf][style_index][:attributes])
746
+ end
747
+
748
+ def get_column_horizontal_alignment(col=0)
749
+ get_column_alignment(col, :horizontal)
750
+ end
751
+
752
+ def get_column_vertical_alignment(col=0)
753
+ get_column_alignment(col, :vertical)
754
+ end
755
+
756
+ def get_column_border_top(col=0)
757
+ return get_column_border(col,:top)
758
+ end
759
+
760
+ def get_column_border_left(col=0)
761
+ return get_column_border(col,:left)
762
+ end
763
+
764
+ def get_column_border_right(col=0)
765
+ return get_column_border(col,:right)
766
+ end
767
+
768
+ def get_column_border_bottom(col=0)
769
+ return get_column_border(col,:bottom)
770
+ end
771
+
772
+ def get_column_border_diagonal(col=0)
773
+ return get_column_border(col,:diagonal)
774
+ end
775
+
776
+
777
+ private
778
+
779
+ Worksheet::NAME = 0
780
+ Worksheet::SIZE = 1
781
+ Worksheet::COLOR = 2
782
+ Worksheet::ITALICS = 3
783
+ Worksheet::BOLD = 4
784
+ Worksheet::UNDERLINE = 5
785
+ Worksheet::STRIKETHROUGH = 6
786
+
787
+ #row_styles is assumed to not be nil at specified row
788
+ def xf_attr_row(row)
789
+ row_style = @row_styles[(row+1).to_s][:style]
790
+ return @workbook.get_style_attributes(@workbook.get_style(row_style))
791
+ end
792
+
793
+ def xf_attr_col(column)
794
+ col_style = @cols[get_cols_index(column)][:style]
795
+ return @workbook.get_style_attributes(@workbook.get_style(Integer(col_style)))
796
+ end
797
+
798
+ def get_row_bool(row,property)
799
+ validate_workbook
800
+ validate_nonnegative(row)
801
+
802
+ if @sheet_data.size <= row
803
+ return nil
804
+ end
805
+
806
+ if @row_styles[(row+1).to_s].nil?
807
+ return false
808
+ end
809
+
810
+ xf = xf_attr_row(row)
811
+
812
+ return !@workbook.fonts[xf[:fontId].to_s][:font][property].nil?
813
+ end
814
+
815
+ def get_row_alignment(row,is_horizontal)
816
+ validate_workbook
817
+ validate_nonnegative(row)
818
+
819
+ if @sheet_data.size <= row || @row_styles[(row+1).to_s].nil?
820
+ return nil
821
+ end
822
+
823
+ xf_obj = @workbook.get_style(@row_styles[(row+1).to_s][:style])
824
+
825
+ if xf_obj[:alignment].nil? || xf_obj[:alignment][:attributes].nil?
826
+ return nil
827
+ end
828
+
829
+ if is_horizontal
830
+ return xf_obj[:alignment][:attributes][:horizontal].to_s
831
+ else
832
+ return xf_obj[:alignment][:attributes][:vertical].to_s
833
+ end
834
+ end
835
+
836
+ def get_row_border(row,border_direction)
837
+ validate_workbook
838
+ validate_nonnegative(row)
839
+
840
+ if @sheet_data.size <= row || @row_styles[(row+1).to_s].nil?
841
+ return nil
842
+ end
843
+
844
+ if @workbook.borders[xf_attr_row(row)[:borderId]].nil? && !@workbook.borders[xf_attr_row(row)[:borderId].to_s].nil?
845
+ @workbook.borders[xf_attr_row(row)[:borderId]] = deep_copy(@workbook.borders[xf_attr_row(row)[:borderId].to_s])
846
+ @workbook.borders.delete(xf_attr_row(row)[:borderId].to_s)
847
+ end
848
+
849
+ if @workbook.borders[xf_attr_row(row)[:borderId]][:border][border_direction][:attributes].nil?
850
+ return nil
851
+ end
852
+
853
+ return @workbook.borders[xf_attr_row(row)[:borderId]][:border][border_direction][:attributes][:style]
854
+ end
855
+
856
+ def get_column_bool(col,property)
857
+ validate_workbook
858
+ validate_nonnegative(col)
859
+
860
+ if @sheet_data[0].size <= col
861
+ return nil
862
+ end
863
+
864
+ style_index = get_cols_style_index(col)
865
+
866
+ return !@workbook.fonts[font_id( style_index ).to_s][:font][property].nil?
867
+ end
868
+
869
+ def get_column_alignment(col, type)
870
+ validate_workbook
871
+ validate_nonnegative(col)
872
+
873
+ if @sheet_data[0].size <= col
874
+ return nil
875
+ end
876
+
877
+ style_index = get_cols_style_index(col)
878
+
879
+ xf_obj = @workbook.get_style(style_index)
880
+ if xf_obj[:alignment].nil?
881
+ return nil
882
+ end
883
+
884
+ return xf_obj[:alignment][:attributes][type]
885
+ end
886
+
887
+ def get_column_border(col, border_direction)
888
+ validate_workbook
889
+ validate_nonnegative(col)
890
+ style_index = get_cols_style_index(col)
891
+ xf = @workbook.get_style_attributes(@workbook.get_style(style_index))
892
+
893
+ if @sheet_data[0].size <= col
894
+ return nil
895
+ end
896
+
897
+ if @workbook.borders[xf[:borderId]].nil? && !@workbook.borders[xf[:borderId].to_s].nil?
898
+ @workbook.borders[xf[:borderId]] = deep_copy(@workbook.borders[xf[:borderId].to_s])
899
+ @workbook.borders.delete(xf[:borderId].to_s)
900
+ end
901
+
902
+ if @workbook.borders[xf[:borderId]][:border][border_direction][:attributes].nil?
903
+ return nil
904
+ end
905
+
906
+ return @workbook.borders[xf[:borderId]][:border][border_direction][:attributes][:style]
907
+ end
908
+
909
+ def deep_copy(hash)
910
+ Marshal.load(Marshal.dump(hash))
911
+ end
912
+
913
+ #validates Workbook, ensures that this worksheet is in @workbook
914
+ def validate_workbook()
915
+ unless @workbook.nil? || @workbook.worksheets.nil?
916
+ @workbook.worksheets.each do |sheet|
917
+ if sheet == self
918
+ return
919
+ end
920
+ end
921
+ end
922
+ raise "This worksheet #{self} is not in workbook #{@workbook}"
923
+ end
924
+
925
+ # because cols is not ordered by col num, this actually gets
926
+ # the index in the array based on which column is actually being asked for by the user
927
+ def get_cols_index(col)
928
+ i = @cols.size - 1
929
+
930
+ @cols.reverse_each do |column|
931
+ if col >= (Integer(column[:attributes][:min])-1)
932
+ if col <= (Integer(column[:attributes][:max])-1)
933
+ break
934
+ end
935
+ end
936
+ i -= 1
937
+ end
938
+ if i < 0
939
+ i = @cols.size #effectively nil
940
+ end
941
+ i
942
+ end
943
+
944
+ def get_cols_style_index(col)
945
+ cols_index = get_cols_index(col)
946
+ if cols_index == @cols.size
947
+ return 0
948
+ end
949
+ return Integer(@cols[cols_index][:attributes][:style])
950
+ end
951
+
952
+ #change cols array
953
+ def change_cols(i,col_index)
954
+ if @cols[i].nil?
955
+ @cols << {:attributes=>{:style=>nil,:min=>nil,:max=>nil,:width=>nil,:customWidth=>nil}}
956
+ else
957
+ @cols << deep_copy(@cols[i])
958
+ end
959
+ @cols.last[:attributes][:style] = (@workbook.cell_xfs[:xf].size-1).to_s
960
+ @cols.last[:attributes][:min] = (Integer(col_index)+1).to_s
961
+ @cols.last[:attributes][:max] = (Integer(col_index)+1).to_s
962
+ @cols.last[:attributes][:width] = '10'
963
+ @cols.last[:attributes][:customWidth] = '0'
964
+ end
965
+
966
+ # row - zer0 indexed int
967
+ # change_type - NAME or SIZE or COLOR etc
968
+ # main method to change font, called from each separate font mutator method
969
+ def change_row_font(row,change_type,arg)
970
+ validate_workbook
971
+ validate_nonnegative(row)
972
+
973
+ increase_rows(row)
974
+
975
+ if @row_styles[(row+1).to_s].nil?
976
+ @row_styles[(row+1).to_s] = {}
977
+ end
978
+
979
+ @row_styles[(row+1).to_s][:style] =
980
+ modify_font(@workbook,Integer(@row_styles[(row+1).to_s][:style]))
981
+
982
+ if @sheet_data[row].nil?
983
+ @sheet_data[row] = []
984
+ end
985
+ @sheet_data[Integer(row)].each do |c|
986
+ unless c.nil?
987
+ font_switch(c,change_type,arg)
988
+ end
989
+ end
990
+ end
991
+
992
+ #main method to change font, called from each separate font mutator method
993
+ def change_column_font(col, change_type, arg)
994
+ validate_workbook
995
+ validate_nonnegative(col)
996
+
997
+ increase_columns(col)
998
+
999
+ i = get_cols_index(col)
1000
+
1001
+ #just copies any style if there is none which already exists for this col
1002
+ #while it changes style/min/max, width *might* be preserved
1003
+ if @cols[i].nil?
1004
+ style_index = 0
1005
+ else
1006
+ style_index = Integer(@cols[i][:attributes][:style])
1007
+ end
1008
+
1009
+ style_index = modify_font(@workbook,style_index)
1010
+
1011
+ change_cols(i,col)
1012
+
1013
+ @sheet_data.each_with_index do |row,i|
1014
+ c = row[col]
1015
+ unless c.nil?
1016
+ font_switch(c,change_type,arg)
1017
+ end
1018
+ end
1019
+ style_index
1020
+ end
1021
+
1022
+ #performs correct modification based on what type of change_type is specified
1023
+ def font_switch(c,change_type,arg)
1024
+ case change_type
1025
+ when Worksheet::NAME
1026
+ unless arg.is_a?String
1027
+ raise 'Not a String'
1028
+ end
1029
+ c.change_font_name(arg)
1030
+ when Worksheet::SIZE
1031
+ unless arg.is_a?(Integer) || arg.is_a?(Float)
1032
+ raise 'Not a Number'
1033
+ end
1034
+ c.change_font_size(arg)
1035
+ when Worksheet::COLOR
1036
+ Color.validate_color(arg)
1037
+ c.change_font_color(arg)
1038
+ when Worksheet::ITALICS
1039
+ unless arg == !!arg
1040
+ raise 'Not a boolean'
1041
+ end
1042
+ c.change_font_italics(arg)
1043
+ when Worksheet::BOLD
1044
+ unless arg == !!arg
1045
+ raise 'Not a boolean'
1046
+ end
1047
+ c.change_font_bold(arg)
1048
+ when Worksheet::UNDERLINE
1049
+ unless arg == !!arg
1050
+ raise 'Not a boolean'
1051
+ end
1052
+ c.change_font_underline(arg)
1053
+ when Worksheet::STRIKETHROUGH
1054
+ unless arg == !!arg
1055
+ raise 'Not a boolean'
1056
+ end
1057
+ c.change_font_strikethrough(arg)
1058
+ else
1059
+ raise 'Invalid change_type'
1060
+ end
1061
+ end
1062
+
1063
+ #increases number of rows until the array at index row is not nil
1064
+ def increase_rows(row)
1065
+ @sheet_data.size.upto(row) do
1066
+ @sheet_data << Array.new(@sheet_data[0].size)
1067
+ end
1068
+ end
1069
+
1070
+ #increases number of columns until the array at index column is not nil
1071
+ def increase_columns(column)
1072
+ @sheet_data.each do |r|
1073
+ r.size.upto(column) do
1074
+ r << nil
1075
+ end
1076
+ end
1077
+ end
1078
+
1079
+ def font_id(style_index)
1080
+ @workbook.get_style_attributes(@workbook.get_style(style_index))[:fontId]
1081
+ end
1082
+
1083
+ def change_row_alignment(row,alignment,is_horizontal)
1084
+ validate_workbook
1085
+ validate_nonnegative(row)
1086
+
1087
+ increase_rows(row)
1088
+
1089
+ if @row_styles[(row+1).to_s].nil?
1090
+ @row_styles[(row+1).to_s] = {}
1091
+ @row_styles[(row+1).to_s][:style] = '0'
1092
+ end
1093
+
1094
+ @row_styles[(row+1).to_s][:style] =
1095
+ modify_alignment(@workbook,@row_styles[(row+1).to_s][:style],is_horizontal,alignment)
1096
+
1097
+ @sheet_data[row].each do |c|
1098
+ unless c.nil?
1099
+ if is_horizontal
1100
+ c.change_horizontal_alignment(alignment)
1101
+ else
1102
+ c.change_vertical_alignment(alignment)
1103
+ end
1104
+ end
1105
+ end
1106
+ end
1107
+
1108
+ def change_column_alignment(col,alignment,is_horizontal)
1109
+ validate_workbook
1110
+ validate_nonnegative(col)
1111
+
1112
+ increase_columns(col)
1113
+
1114
+ i = get_cols_index(col)
1115
+
1116
+ if @cols[i].nil?
1117
+ style_index = 0
1118
+ else
1119
+ style_index = Integer(@cols[i][:attributes][:style])
1120
+ end
1121
+
1122
+ style_index = modify_alignment(@workbook,style_index,is_horizontal,alignment)
1123
+
1124
+ change_cols(i,col)
1125
+
1126
+ @cols[i][:attributes][:style] = style_index
1127
+
1128
+ @sheet_data.each_with_index do |row,i|
1129
+ c = row[Integer(col)]
1130
+ unless c.nil?
1131
+ if is_horizontal
1132
+ c.change_horizontal_alignment(alignment)
1133
+ else
1134
+ c.change_vertical_alignment(alignment)
1135
+ end
1136
+ end
1137
+ end
1138
+ end
1139
+
1140
+ def change_row_border(row, direction, weight)
1141
+ validate_workbook
1142
+ validate_nonnegative(row)
1143
+ validate_border(weight)
1144
+ increase_rows(row)
1145
+
1146
+ if @row_styles[(row+1).to_s].nil?
1147
+ @row_styles[(row+1).to_s]= {}
1148
+ @row_styles[(row+1).to_s][:style] = '0'
1149
+ end
1150
+ @row_styles[(row+1).to_s][:style] = modify_border(@workbook,@row_styles[(row+1).to_s][:style])
1151
+
1152
+ if @workbook.borders[xf_attr_row(row)[:borderId]][:border][direction][:attributes].nil?
1153
+ @workbook.borders[xf_attr_row(row)[:borderId]][:border][direction][:attributes] = { :style => nil }
1154
+ end
1155
+ @workbook.borders[xf_attr_row(row)[:borderId]][:border][direction][:attributes][:style] = weight.to_s
1156
+
1157
+ @sheet_data[row].each do |c|
1158
+ unless c.nil?
1159
+ case direction
1160
+ when :top
1161
+ c.change_border_top(weight)
1162
+ when :left
1163
+ c.change_border_left(weight)
1164
+ when :right
1165
+ c.change_border_right(weight)
1166
+ when :bottom
1167
+ c.change_border_bottom(weight)
1168
+ when :diagonal
1169
+ c.change_border_diagonal(weight)
1170
+ else
1171
+ raise 'invalid direction'
1172
+ end
1173
+ end
1174
+ end
1175
+ end
1176
+
1177
+ def change_column_border(col,direction,weight)
1178
+ validate_workbook
1179
+ validate_nonnegative(col)
1180
+ validate_border(weight)
1181
+
1182
+ increase_columns(col)
1183
+
1184
+ i = get_cols_index(col)
1185
+ if @cols[i].nil?
1186
+ style_index = 0
1187
+ else
1188
+ style_index = Integer(@cols[i][:attributes][:style])
1189
+ end
1190
+
1191
+ style_index = modify_border(@workbook,style_index)
1192
+
1193
+ change_cols(i,col)
1194
+
1195
+ xf = @workbook.get_style_attributes(@workbook.get_style(style_index))
1196
+
1197
+ if @workbook.borders[xf[:borderId]][:border][direction][:attributes].nil?
1198
+ @workbook.borders[xf[:borderId]][:border][direction][:attributes] = { :style => nil }
1199
+ end
1200
+ @workbook.borders[xf[:borderId]][:border][direction][:attributes][:style] = weight.to_s
1201
+
1202
+ @sheet_data.each_with_index do |row,i|
1203
+ c = row[Integer(col)]
1204
+ unless c.nil?
1205
+ case direction
1206
+ when :top
1207
+ c.change_border_top(weight)
1208
+ when :left
1209
+ c.change_border_left(weight)
1210
+ when :right
1211
+ c.change_border_right(weight)
1212
+ when :bottom
1213
+ c.change_border_bottom(weight)
1214
+ when :diagonal
1215
+ c.change_border_diagonal(weight)
1216
+ else
1217
+ raise 'invalid direction'
1218
+ end
1219
+ end
1220
+ end
1221
+ end
1222
+
1223
+ def add_cell_style(row,column)
1224
+ xf = @workbook.get_style_attributes(@workbook.get_style(@sheet_data[row][column].style_index))
1225
+ @workbook.fonts[xf[:fontId].to_s][:count] += 1
1226
+ @workbook.fills[xf[:fillId].to_s][:count] += 1
1227
+ @workbook.borders[xf[:borderId].to_s][:count] += 1
1228
+ end
1229
+
1230
+ # finds first row which contains at least all strings in cells_content
1231
+ def find_first_row_with_content(cells_content)
1232
+ validate_workbook
1233
+ index = nil
1234
+
1235
+ @sheet_data.each_with_index do |row, index|
1236
+ original_cells_content = row.map { |cell| cell.nil? ? '' : cell.value.to_s }
1237
+ if (cells_content & original_cells_content).size == cells_content.size
1238
+ return index
1239
+ end
1240
+ end
1241
+ return nil
1242
+ end
1243
+
1244
+ end #end class
1245
+ end