rubyXL-git-ref-6002046 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +20 -0
  3. data/Gemfile.lock +63 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +197 -0
  6. data/Rakefile +58 -0
  7. data/VERSION +1 -0
  8. data/lib/rubyXL.rb +21 -0
  9. data/lib/rubyXL/cell.rb +325 -0
  10. data/lib/rubyXL/generic_storage.rb +40 -0
  11. data/lib/rubyXL/objects/border.rb +53 -0
  12. data/lib/rubyXL/objects/cell_style.rb +73 -0
  13. data/lib/rubyXL/objects/color.rb +23 -0
  14. data/lib/rubyXL/objects/column_range.rb +88 -0
  15. data/lib/rubyXL/objects/data_validation.rb +31 -0
  16. data/lib/rubyXL/objects/defined_name.rb +27 -0
  17. data/lib/rubyXL/objects/fill.rb +42 -0
  18. data/lib/rubyXL/objects/font.rb +109 -0
  19. data/lib/rubyXL/objects/formula.rb +8 -0
  20. data/lib/rubyXL/objects/ooxml_object.rb +177 -0
  21. data/lib/rubyXL/objects/reference.rb +98 -0
  22. data/lib/rubyXL/objects/sheet_view.rb +62 -0
  23. data/lib/rubyXL/objects/worksheet.rb +11 -0
  24. data/lib/rubyXL/parser.rb +307 -0
  25. data/lib/rubyXL/private_class.rb +95 -0
  26. data/lib/rubyXL/shared_strings.rb +35 -0
  27. data/lib/rubyXL/workbook.rb +342 -0
  28. data/lib/rubyXL/worksheet.rb +1118 -0
  29. data/lib/rubyXL/writer/app_writer.rb +51 -0
  30. data/lib/rubyXL/writer/calc_chain_writer.rb +18 -0
  31. data/lib/rubyXL/writer/content_types_writer.rb +113 -0
  32. data/lib/rubyXL/writer/core_writer.rb +34 -0
  33. data/lib/rubyXL/writer/generic_writer.rb +33 -0
  34. data/lib/rubyXL/writer/root_rels_writer.rb +17 -0
  35. data/lib/rubyXL/writer/shared_strings_writer.rb +21 -0
  36. data/lib/rubyXL/writer/styles_writer.rb +64 -0
  37. data/lib/rubyXL/writer/theme_writer.rb +337 -0
  38. data/lib/rubyXL/writer/workbook_rels_writer.rb +43 -0
  39. data/lib/rubyXL/writer/workbook_writer.rb +73 -0
  40. data/lib/rubyXL/writer/worksheet_writer.rb +164 -0
  41. data/lib/rubyXL/zip.rb +20 -0
  42. data/rdoc/created.rid +36 -0
  43. data/rdoc/fonts.css +167 -0
  44. data/rdoc/fonts/Lato-Light.ttf +0 -0
  45. data/rdoc/fonts/Lato-LightItalic.ttf +0 -0
  46. data/rdoc/fonts/Lato-Regular.ttf +0 -0
  47. data/rdoc/fonts/Lato-RegularItalic.ttf +0 -0
  48. data/rdoc/fonts/SourceCodePro-Bold.ttf +0 -0
  49. data/rdoc/fonts/SourceCodePro-Regular.ttf +0 -0
  50. data/rdoc/images/add.png +0 -0
  51. data/rdoc/images/arrow_up.png +0 -0
  52. data/rdoc/images/brick.png +0 -0
  53. data/rdoc/images/brick_link.png +0 -0
  54. data/rdoc/images/bug.png +0 -0
  55. data/rdoc/images/bullet_black.png +0 -0
  56. data/rdoc/images/bullet_toggle_minus.png +0 -0
  57. data/rdoc/images/bullet_toggle_plus.png +0 -0
  58. data/rdoc/images/date.png +0 -0
  59. data/rdoc/images/delete.png +0 -0
  60. data/rdoc/images/find.png +0 -0
  61. data/rdoc/images/loadingAnimation.gif +0 -0
  62. data/rdoc/images/macFFBgHack.png +0 -0
  63. data/rdoc/images/package.png +0 -0
  64. data/rdoc/images/page_green.png +0 -0
  65. data/rdoc/images/page_white_text.png +0 -0
  66. data/rdoc/images/page_white_width.png +0 -0
  67. data/rdoc/images/plugin.png +0 -0
  68. data/rdoc/images/ruby.png +0 -0
  69. data/rdoc/images/tag_blue.png +0 -0
  70. data/rdoc/images/tag_green.png +0 -0
  71. data/rdoc/images/transparent.png +0 -0
  72. data/rdoc/images/wrench.png +0 -0
  73. data/rdoc/images/wrench_orange.png +0 -0
  74. data/rdoc/images/zoom.png +0 -0
  75. data/rdoc/js/darkfish.js +140 -0
  76. data/rdoc/js/jquery.js +18 -0
  77. data/rdoc/js/navigation.js +142 -0
  78. data/rdoc/js/search.js +109 -0
  79. data/rdoc/js/search_index.js +1 -0
  80. data/rdoc/js/searcher.js +228 -0
  81. data/rdoc/rdoc.css +580 -0
  82. data/rubyXL-git-ref-6002046.gemspec +143 -0
  83. data/spec/lib/cell_spec.rb +407 -0
  84. data/spec/lib/color_spec.rb +14 -0
  85. data/spec/lib/parser_spec.rb +80 -0
  86. data/spec/lib/workbook_spec.rb +73 -0
  87. data/spec/lib/worksheet_spec.rb +1789 -0
  88. metadata +231 -0
@@ -0,0 +1,95 @@
1
+ module RubyXL
2
+ class PrivateClass
3
+ private
4
+
5
+ #validate and modify methods
6
+ def validate_horizontal_alignment(alignment)
7
+ if alignment.to_s == '' || alignment == 'center' || alignment == 'distributed' || alignment == 'justify' || alignment == 'left' || alignment == 'right'
8
+ return true
9
+ end
10
+ raise 'Only center, distributed, justify, left, and right are valid horizontal alignments'
11
+ end
12
+
13
+ def validate_vertical_alignment(alignment)
14
+ if alignment.to_s == '' || alignment == 'center' || alignment == 'distributed' || alignment == 'justify' || alignment == 'top' || alignment == 'bottom'
15
+ return true
16
+ end
17
+ raise 'Only center, distributed, justify, top, and bottom are valid vertical alignments'
18
+ end
19
+
20
+ def validate_text_wrap(wrap)
21
+ raise 'Only true or false are valid wraps' unless wrap.is_a?(FalseClass) || wrap.is_a?(TrueClass)
22
+ end
23
+
24
+ def validate_border(weight)
25
+ if weight.to_s == '' || weight == 'thin' || weight == 'thick' || weight == 'hairline' || weight == 'medium'
26
+ return true
27
+ end
28
+ raise 'Border weights must only be "hairline", "thin", "medium", or "thick"'
29
+ end
30
+
31
+ def validate_nonnegative(row_or_col)
32
+ if row_or_col < 0
33
+ raise 'Row and Column arguments must be nonnegative'
34
+ end
35
+ end
36
+
37
+ # This method checks to see if there is an equivalent xf that exists
38
+ def find_xf(workbook, xf)
39
+ workbook.cell_xfs.each_with_index { |xfs, index| return index if xfs == xf }
40
+ return nil
41
+ end
42
+
43
+ # Determines if xf exists
44
+ # If yes, return id of existing xf
45
+ # If no, appends xf to xf array
46
+ def modify_xf(workbook, xf)
47
+ existing_xf_id = find_xf(workbook, xf)
48
+ if !existing_xf_id.nil?
49
+ xf_id = existing_xf_id
50
+ else
51
+ xf.apply_font = true
52
+ xf_id = workbook.cell_xfs.size - 1
53
+ end
54
+ return xf_id
55
+ end
56
+
57
+ #modifies fill array (copies, appends, adds color and solid attribute)
58
+ #then styles array (copies, appends)
59
+ def modify_fill(workbook, style_index, rgb)
60
+ xf = workbook.cell_xfs[style_index]
61
+ new_fill = RubyXL::Fill.new(:pattern_fill =>
62
+ RubyXL::PatternFill.new(:pattern_type => 'solid', :fg_color => RubyXL::Color.new(:rgb => rgb)))
63
+ new_xf = workbook.register_new_fill(new_fill, xf)
64
+ workbook.register_new_xf(new_xf, style_index)
65
+ end
66
+
67
+ #is_horizontal is true when doing horizontal alignment,
68
+ #false when doing vertical alignment
69
+ def modify_alignment(workbook, style_index, is_horizontal, alignment)
70
+ old_xf = workbook.cell_xfs[style_index]
71
+
72
+ xf = old_xf.dup
73
+ xf.alignment ||= RubyXL::Alignment.new
74
+
75
+ if is_horizontal then xf.alignment.horizontal = alignment
76
+ else xf.alignment.vertical = alignment
77
+ end
78
+ xf.apply_alignment = true
79
+
80
+ workbook.register_new_xf(xf, style_index)
81
+ end
82
+
83
+ def modify_text_wrap(workbook, style_index, wrapText = false)
84
+ old_xf = workbook.cell_xfs[style_index]
85
+
86
+ xf = old_xf.dup
87
+ xf.alignment ||= RubyXL::Alignment.new
88
+ xf.alignment.wrap_text = wrapText
89
+ xf.apply_alignment = true
90
+
91
+ workbook.register_new_xf(xf, style_index)
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,35 @@
1
+ module RubyXL
2
+ class SharedStrings
3
+
4
+ attr_accessor :count_attr, :unique_count_attr
5
+
6
+ def initialize
7
+ # So far, going by the structure that the original creator had in mind. However,
8
+ # since the actual implementation is now extracted into a separate class,
9
+ # we will be able to transparrently change it later if needs be.
10
+ @content_by_index = []
11
+ @index_by_content = {}
12
+ @unique_count_attr = @count_attr = nil # TODO
13
+ end
14
+
15
+ def empty?
16
+ @content_by_index.empty?
17
+ end
18
+
19
+ def add(str, index)
20
+ @content_by_index[index] = str
21
+ @index_by_content[str] = index
22
+ end
23
+
24
+ def get_index(str, add_if_missing = false)
25
+ index = @index_by_content[str]
26
+ index = add(str) if index.nil? && add_if_missing
27
+ index
28
+ end
29
+
30
+ def[](index)
31
+ @content_by_index[index]
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,342 @@
1
+ require 'rubyXL/writer/generic_writer'
2
+ require 'rubyXL/writer/content_types_writer'
3
+ require 'rubyXL/writer/root_rels_writer'
4
+ require 'rubyXL/writer/app_writer'
5
+ require 'rubyXL/writer/core_writer'
6
+ require 'rubyXL/writer/theme_writer'
7
+ require 'rubyXL/writer/workbook_rels_writer'
8
+ require 'rubyXL/writer/workbook_writer'
9
+ require 'rubyXL/writer/styles_writer'
10
+ require 'rubyXL/writer/shared_strings_writer'
11
+ require 'rubyXL/writer/worksheet_writer'
12
+ require 'rubyXL/zip'
13
+ require 'rubyXL/shared_strings'
14
+ require 'date'
15
+
16
+ module RubyXL
17
+ class Workbook
18
+ include Enumerable
19
+ attr_accessor :worksheets, :filepath, :creator, :modifier, :created_at,
20
+ :modified_at, :company, :application, :appversion, :num_fmts, :fonts, :fills,
21
+ :borders, :cell_xfs, :cell_style_xfs, :cell_styles, :calc_chain, :theme,
22
+ :date1904, :media, :external_links, :external_links_rels, :style_corrector,
23
+ :drawings, :drawings_rels, :charts, :chart_rels,
24
+ :worksheet_rels, :printer_settings, :macros, :colors, :shared_strings_XML, :defined_names, :column_lookup_hash
25
+
26
+ attr_reader :shared_strings
27
+
28
+ APPLICATION = 'Microsoft Macintosh Excel'
29
+ APPVERSION = '12.0000'
30
+
31
+ def initialize(worksheets=[], filepath=nil, creator=nil, modifier=nil, created_at=nil,
32
+ company='', application=APPLICATION,
33
+ appversion=APPVERSION, date1904=0)
34
+
35
+ # Order of sheets in the +worksheets+ array corresponds to the order of pages in Excel UI.
36
+ # SheetId's, rId's, etc. are completely unrelated to ordering.
37
+ @worksheets = worksheets || []
38
+
39
+ @worksheets << Worksheet.new(self) if @worksheets.empty?
40
+
41
+ @filepath = filepath
42
+ @creator = creator
43
+ @modifier = modifier
44
+ @company = company
45
+ @application = application
46
+ @appversion = appversion
47
+ @num_fmts = []
48
+ @num_fmts_by_id = nil
49
+ @fonts = []
50
+ @fills = nil
51
+ @borders = []
52
+ @cell_xfs = []
53
+ @cell_style_xfs = []
54
+ @cell_styles = []
55
+ @shared_strings = RubyXL::SharedStrings.new
56
+ @calc_chain = nil #unnecessary?
57
+ @date1904 = date1904 > 0
58
+ @media = RubyXL::GenericStorage.new(File.join('xl', 'media')).binary
59
+ @external_links = RubyXL::GenericStorage.new(File.join('xl', 'externalLinks'))
60
+ @external_links_rels= RubyXL::GenericStorage.new(File.join('xl', 'externalLinks', '_rels'))
61
+ @style_corrector = nil
62
+ @drawings = RubyXL::GenericStorage.new(File.join('xl', 'drawings'))
63
+ @drawings_rels = RubyXL::GenericStorage.new(File.join('xl', 'drawings', '_rels'))
64
+ @charts = RubyXL::GenericStorage.new(File.join('xl', 'charts'))
65
+ @chart_rels = RubyXL::GenericStorage.new(File.join('xl', 'charts', '_rels'))
66
+ @worksheet_rels = RubyXL::GenericStorage.new(File.join('xl', 'worksheets', '_rels'))
67
+ @theme = RubyXL::GenericStorage.new(File.join('xl', 'theme'))
68
+ @printer_settings = RubyXL::GenericStorage.new(File.join('xl', 'printerSettings')).binary
69
+ @macros = RubyXL::GenericStorage.new('xl').binary
70
+ @colors = {}
71
+ @shared_strings_XML = nil
72
+ @defined_names = []
73
+ @column_lookup_hash = {}
74
+
75
+ begin
76
+ @created_at = DateTime.parse(created_at).strftime('%Y-%m-%dT%TZ')
77
+ rescue
78
+ t = Time.now
79
+ @created_at = t.strftime('%Y-%m-%dT%TZ')
80
+ end
81
+ @modified_at = @created_at
82
+
83
+ fill_styles()
84
+ fill_shared_strings()
85
+ end
86
+
87
+ # Finds worksheet by its name or numerical index
88
+ def [](ind)
89
+ case ind
90
+ when Integer then worksheets[ind]
91
+ when String then worksheets.find { |ws| ws.sheet_name == ind }
92
+ end
93
+ end
94
+
95
+ # Create new simple worksheet and add it to the workbook worksheets
96
+ #
97
+ # @param [String] The name for the new worksheet
98
+ def add_worksheet(name = nil)
99
+ new_worksheet = Worksheet.new(self, name)
100
+ worksheets << new_worksheet
101
+ new_worksheet
102
+ end
103
+
104
+ def each
105
+ worksheets.each{|i| yield i}
106
+ end
107
+
108
+ def num_fmts_by_id
109
+ return @num_fmts_by_id unless @num_fmts_by_id.nil?
110
+
111
+ @num_fmts_by_id = {}
112
+
113
+ num_fmts.each { |fmt| @num_fmts_by_id[fmt.num_fmt_id] = fmt }
114
+
115
+ @num_fmts_by_id
116
+ end
117
+
118
+ #filepath of xlsx file (including file itself)
119
+ def write(filepath = @filepath)
120
+ validate_before_write
121
+
122
+ extension = File.extname(filepath)
123
+ unless %w{.xlsx .xlsm}.include?(extension)
124
+ raise "Only xlsx and xlsm files are supported. Unsupported extension: #{extension}"
125
+ end
126
+
127
+ dirpath = File.dirname(filepath)
128
+ temppath = File.join(dirpath, Dir::Tmpname.make_tmpname([ File.basename(filepath), '.tmp' ], nil))
129
+ FileUtils.mkdir_p(temppath)
130
+ zippath = File.join(temppath, 'file.zip')
131
+
132
+ Zip::File.open(zippath, Zip::File::CREATE) { |zipfile|
133
+ [ Writer::ContentTypesWriter, Writer::RootRelsWriter, Writer::AppWriter, Writer::CoreWriter,
134
+ Writer::ThemeWriter, Writer::WorkbookRelsWriter, Writer::WorkbookWriter, Writer::StylesWriter
135
+ ].each { |writer_class| writer_class.new(self).add_to_zip(zipfile) }
136
+
137
+ Writer::SharedStringsWriter.new(self).add_to_zip(zipfile) unless @shared_strings.empty?
138
+
139
+ [ @media, @external_links, @external_links_rels,
140
+ @drawings, @drawings_rels, @charts, @chart_rels,
141
+ @printer_settings, @worksheet_rels, @macros ].each { |s| s.add_to_zip(zipfile) }
142
+
143
+ @worksheets.each_index { |i| Writer::WorksheetWriter.new(self, i).add_to_zip(zipfile) }
144
+ }
145
+
146
+ FileUtils.mv(zippath, filepath)
147
+ FileUtils.rm_rf(temppath) if File.exist?(filepath)
148
+
149
+ return filepath
150
+ end
151
+
152
+ def base_date
153
+ if @date1904 then
154
+ Date.new(1904, 1, 1)
155
+ else
156
+ # Subtracting one day to accomodate for erroneous 1900 leap year compatibility only for 1900 based dates
157
+ Date.new(1899, 12, 31) - 1
158
+ end
159
+ end
160
+ private :base_date
161
+
162
+ def date_to_num(date)
163
+ date && (date.ajd - base_date().ajd).to_i
164
+ end
165
+
166
+ def num_to_date(num)
167
+ num && (base_date + num)
168
+ end
169
+
170
+ def date_num_fmt?(num_fmt)
171
+ @num_fmt_date_hash ||= {}
172
+ if @num_fmt_date_hash[num_fmt].nil?
173
+ @num_fmt_date_hash[num_fmt] = is_date_format?(num_fmt)
174
+ end
175
+ return @num_fmt_date_hash[num_fmt]
176
+ end
177
+
178
+ def is_date_format?(num_fmt)
179
+ num_fmt = num_fmt.downcase
180
+ skip_chars = ['$', '-', '+', '/', '(', ')', ':', ' ']
181
+ num_chars = ['0', '#', '?']
182
+ non_date_formats = ['0.00e+00', '##0.0e+0', 'general', '@']
183
+ date_chars = ['y','m','d','h','s']
184
+
185
+ state = 0
186
+ s = ''
187
+
188
+ num_fmt.split(//).each do |c|
189
+ case state
190
+ when 0 then
191
+ if c == '"'
192
+ state = 1
193
+ elsif ['\\', '_', '*'].include?(c)
194
+ state = 2
195
+ elsif skip_chars.include?(c)
196
+ next
197
+ else
198
+ s << c
199
+ end
200
+ when 1 then
201
+ state = 0 if c == '"'
202
+ when 2 then
203
+ state = 0
204
+ end
205
+ end
206
+
207
+ s.gsub!(/\[[^\]]*\]/, '')
208
+
209
+ return false if non_date_formats.include?(s)
210
+
211
+ separator = ';'
212
+ got_sep = 0
213
+ date_count = 0
214
+ num_count = 0
215
+
216
+ s.split(//).each do |c|
217
+ if date_chars.include?(c)
218
+ date_count += 1
219
+ elsif num_chars.include?(c)
220
+ num_count += 1
221
+ elsif c == separator
222
+ got_sep = 1
223
+ end
224
+ end
225
+
226
+ if date_count > 0 && num_count == 0
227
+ return true
228
+ elsif num_count > 0 && date_count == 0
229
+ return false
230
+ elsif date_count
231
+ # ambiguous result
232
+ elsif got_sep == 0
233
+ # constant result
234
+ end
235
+
236
+ return date_count > num_count
237
+ end
238
+
239
+ def get_fill_color(xf)
240
+ fill = @fills[xf.fill_id]
241
+ pattern = fill && fill.pattern_fill
242
+ color = pattern && pattern.fg_color
243
+ color && color.rgb || 'ffffff'
244
+ end
245
+
246
+ def register_new_fill(new_fill, old_xf)
247
+ new_xf = old_xf.dup
248
+
249
+ unless fills[old_xf.fill_id].count == 1 && old_xf.fill_id > 2 # If the old fill is not used anymore, just replace it
250
+ new_xf.fill_id = fills.find_index { |x| x == new_fill } # Use existing fill, if it exists
251
+ new_xf.fill_id ||= fills.size # If this fill has never existed before, add it to collection.
252
+ end
253
+
254
+ fills[old_xf.fill_id].count -= 1
255
+ new_fill.count += 1
256
+ fills[new_xf.fill_id] = new_fill
257
+
258
+ new_xf.apply_fill = true
259
+ new_xf
260
+ end
261
+
262
+ def register_new_font(new_font, old_xf)
263
+ new_xf = old_xf.dup
264
+
265
+ unless fonts[old_xf.font_id].count == 1 && old_xf.font_id > 1 # If the old font is not used anymore, just replace it
266
+ new_xf.font_id = fonts.find_index { |x| x == new_font } # Use existing font, if it exists
267
+ new_xf.font_id ||= fonts.size # If this font has never existed before, add it to collection.
268
+ end
269
+
270
+ fonts[old_xf.font_id].count -= 1
271
+ new_font.count += 1
272
+ fonts[new_xf.font_id] = new_font
273
+
274
+ new_xf.apply_font = true
275
+ new_xf
276
+ end
277
+
278
+ def register_new_border(new_border, old_xf)
279
+ new_xf = old_xf.dup
280
+
281
+ unless borders[old_xf.border_id].count == 1 && old_xf.border_id > 0 # If the old border not used anymore, just replace it
282
+ new_xf.border_id = borders.find_index { |x| x == new_border } # Use existing border, if it exists
283
+ new_xf.border_id ||= borders.size # If this border has never existed before, add it to collection.
284
+ end
285
+
286
+ borders[old_xf.border_id].count -= 1
287
+ new_border.count += 1
288
+ borders[new_xf.border_id] = new_border
289
+
290
+ new_xf.apply_border = true
291
+ new_xf
292
+ end
293
+
294
+ def register_new_xf(new_xf, old_style_index)
295
+ new_xf_id = cell_xfs.find_index { |xf| xf == new_xf } # Use existing XF, if it exists
296
+ new_xf_id ||= cell_xfs.size # If this XF has never existed before, add it to collection.
297
+
298
+ cell_xfs[old_style_index].count -= 1
299
+ new_xf.count += 1
300
+ cell_xfs[new_xf_id] = new_xf
301
+
302
+ new_xf_id
303
+ end
304
+
305
+ private
306
+
307
+ # Do not change. Excel requires that some of these styles be default,
308
+ # and will simply assume that the 0 and 1 indexed fonts are the default values.
309
+ def fill_styles()
310
+
311
+ @fonts = [ RubyXL::Font.new(:name => RubyXL::StringValue.new(:val => 'Verdana'), :sz => RubyXL::FloatValue.new(:val => 10) ),
312
+ RubyXL::Font.new(:name => RubyXL::StringValue.new(:val => 'Verdana'), :sz => RubyXL::FloatValue.new(:val => 8) ) ]
313
+
314
+ @fills = [ RubyXL::Fill.new(:pattern_fill => RubyXL::PatternFill.new(:pattern_type => 'none')),
315
+ RubyXL::Fill.new(:pattern_fill => RubyXL::PatternFill.new(:pattern_type => 'gray125')) ]
316
+
317
+ @borders = [ RubyXL::Border.new ]
318
+
319
+ @cell_style_xfs = [ RubyXL::XF.new(:num_fmt_id => 0, :font_id => 0, :fill_id => 0, :border_id => 0) ]
320
+ @cell_xfs = [ RubyXL::XF.new(:num_fmt_id => 0, :font_id => 0, :fill_id => 0, :border_id => 0, :xfId => 0) ]
321
+ @cell_styles = [ RubyXL::CellStyle.new({ :builtin_id => 0, :name => 'Normal', :xf_id => 0 }) ]
322
+ end
323
+
324
+
325
+ #fills shared strings hash, contains each unique string
326
+ def fill_shared_strings()
327
+ @worksheets.compact.each { |sheet|
328
+ sheet.sheet_data.each { |row|
329
+ row.each { |cell|
330
+ if cell && cell.value && cell.datatype == RubyXL::Cell::SHARED_STRING then
331
+ get_index(cell.value.to_s, :add_if_missing)
332
+ end
333
+ }
334
+ }
335
+ }
336
+ end
337
+
338
+ def validate_before_write
339
+ ## TODO CHECK IF STYLE IS OK if not raise
340
+ end
341
+ end
342
+ end