xlsxrb 0.1.13 → 0.1.15

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -0
  3. data/README.md +17 -14
  4. data/lib/xlsxrb/colors.rb +118 -0
  5. data/lib/xlsxrb/elements/cell.rb +205 -16
  6. data/lib/xlsxrb/elements/column.rb +6 -4
  7. data/lib/xlsxrb/elements/coordinate_access.rb +32 -0
  8. data/lib/xlsxrb/elements/image.rb +128 -0
  9. data/lib/xlsxrb/elements/row.rb +206 -9
  10. data/lib/xlsxrb/elements/styles.rb +157 -0
  11. data/lib/xlsxrb/elements/types.rb +95 -1
  12. data/lib/xlsxrb/elements/workbook.rb +121 -4
  13. data/lib/xlsxrb/elements/worksheet.rb +519 -29
  14. data/lib/xlsxrb/elements.rb +2 -0
  15. data/lib/xlsxrb/number_formatter.rb +429 -0
  16. data/lib/xlsxrb/ooxml/cfb.rb +1 -1
  17. data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +7 -5
  18. data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +11 -4
  19. data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +7 -1
  20. data/lib/xlsxrb/ooxml/reader.rb +14 -17
  21. data/lib/xlsxrb/ooxml/shared_strings_parser.rb +7 -1
  22. data/lib/xlsxrb/ooxml/styles_parser.rb +39 -9
  23. data/lib/xlsxrb/ooxml/utils.rb +34 -18
  24. data/lib/xlsxrb/ooxml/workbook_parser.rb +74 -16
  25. data/lib/xlsxrb/ooxml/workbook_writer.rb +82 -23
  26. data/lib/xlsxrb/ooxml/worksheet_parser.rb +319 -79
  27. data/lib/xlsxrb/ooxml/worksheet_writer.rb +263 -66
  28. data/lib/xlsxrb/ooxml/writer/features_xml.rb +5 -3
  29. data/lib/xlsxrb/ooxml/writer.rb +14 -0
  30. data/lib/xlsxrb/ooxml/xml_builder.rb +14 -2
  31. data/lib/xlsxrb/ooxml/zip_reader.rb +144 -28
  32. data/lib/xlsxrb/stream_row.rb +243 -16
  33. data/lib/xlsxrb/stream_sheet.rb +647 -16
  34. data/lib/xlsxrb/stream_writer.rb +375 -34
  35. data/lib/xlsxrb/style_builder.rb +308 -22
  36. data/lib/xlsxrb/utils.rb +211 -0
  37. data/lib/xlsxrb/version.rb +1 -1
  38. data/lib/xlsxrb/workbook_builder.rb +72 -11
  39. data/lib/xlsxrb/worksheet_builder.rb +738 -24
  40. data/lib/xlsxrb.rb +1073 -83
  41. data/sig/generated/xlsxrb/colors.rbs +40 -0
  42. data/sig/generated/xlsxrb/elements/cell.rbs +113 -8
  43. data/sig/generated/xlsxrb/elements/column.rbs +3 -2
  44. data/sig/generated/xlsxrb/elements/coordinate_access.rbs +18 -0
  45. data/sig/generated/xlsxrb/elements/image.rbs +82 -0
  46. data/sig/generated/xlsxrb/elements/row.rbs +83 -4
  47. data/sig/generated/xlsxrb/elements/styles.rbs +79 -0
  48. data/sig/generated/xlsxrb/elements/types.rbs +43 -0
  49. data/sig/generated/xlsxrb/elements/workbook.rbs +79 -2
  50. data/sig/generated/xlsxrb/elements/worksheet.rbs +282 -18
  51. data/sig/generated/xlsxrb/number_formatter.rbs +132 -0
  52. data/sig/generated/xlsxrb/ooxml/reader.rbs +6 -0
  53. data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +2 -0
  54. data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +5 -2
  55. data/sig/generated/xlsxrb/ooxml/utils.rbs +17 -8
  56. data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +9 -3
  57. data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +1 -1
  58. data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +28 -6
  59. data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +13 -3
  60. data/sig/generated/xlsxrb/ooxml/writer.rbs +2 -0
  61. data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +3 -1
  62. data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +13 -0
  63. data/sig/generated/xlsxrb/stream_row.rbs +100 -6
  64. data/sig/generated/xlsxrb/stream_sheet.rbs +358 -14
  65. data/sig/generated/xlsxrb/stream_writer.rbs +220 -30
  66. data/sig/generated/xlsxrb/style_builder.rbs +55 -18
  67. data/sig/generated/xlsxrb/utils.rbs +151 -0
  68. data/sig/generated/xlsxrb/workbook_builder.rbs +26 -0
  69. data/sig/generated/xlsxrb/worksheet_builder.rbs +356 -18
  70. data/sig/generated/xlsxrb.rbs +223 -27
  71. metadata +11 -1
@@ -63,7 +63,12 @@ module Xlsxrb
63
63
  raise ArgumentError, "Sheet name '#{name}' contains invalid characters (ECMA-376 OOXML specification)" if name.match?(%r{[\[\]*?/\\]})
64
64
  raise ArgumentError, "Sheet name '#{name}' is already used. Excel requires unique sheet names." if @strict_excel_mode && @sheets.map { |s| s.respond_to?(:name) ? s.name.downcase : s.to_s.downcase }.include?(name.downcase)
65
65
 
66
- sheet_builder = WorksheetBuilder.new(name, strict_excel_mode: @strict_excel_mode)
66
+ state = opts.delete(:state)
67
+ hidden = opts.delete(:hidden)
68
+ state ||= :hidden if hidden
69
+ state ||= :visible
70
+
71
+ sheet_builder = WorksheetBuilder.new(name, strict_excel_mode: @strict_excel_mode, state: state)
67
72
  opts.each { |k, v| sheet_builder.sheet_properties(k, v) }
68
73
  yield sheet_builder if block_given?
69
74
  @sheet_builders << sheet_builder
@@ -112,6 +117,11 @@ module Xlsxrb
112
117
  #: (?rows: String?, ?cols: String?, ?sheet: String?) -> void
113
118
  def print_titles(rows: nil, cols: nil, sheet: nil)
114
119
  sheet_name = sheet || @sheets.last&.name || "Sheet1"
120
+ existing = @defined_names.find { |dn| dn[:name] == "_xlnm.Print_Titles" && dn[:local_sheet_name] == sheet_name }
121
+ if existing && (rows.nil? || cols.nil?)
122
+ cols = Regexp.last_match(1).delete("$") if cols.nil? && existing[:value] =~ /'[^']*'!\$([A-Za-z]+:\$[A-Za-z]+)/
123
+ rows = Regexp.last_match(1).delete("$") if rows.nil? && existing[:value] =~ /'[^']*'!\$([0-9]+:\$[0-9]+)/
124
+ end
115
125
  parts = []
116
126
  parts << "'#{sheet_name}'!$#{cols.sub(":", ":$")}" if cols
117
127
  parts << "'#{sheet_name}'!$#{rows.sub(":", ":$")}" if rows
@@ -120,6 +130,55 @@ module Xlsxrb
120
130
  defined_name("_xlnm.Print_Titles", value, sheet: sheet_name)
121
131
  end
122
132
 
133
+ # Sets repeating title rows for pagination on the target or active sheet.
134
+ #
135
+ # @example Repeat first row
136
+ # wb.repeat_rows(0)
137
+ #
138
+ # @param first [Integer, String] First row index (0-based) or range string (e.g. "1:2").
139
+ # @param last [Integer, String, nil] Optional last row index (0-based).
140
+ # @param sheet [String, nil] Target sheet name.
141
+ # @return [void]
142
+ # @api public
143
+ #: (Integer | String first, ?(Integer | String)? last, ?sheet: String?) -> void
144
+ def repeat_rows(first, last = nil, sheet: nil)
145
+ rows_str = if first.is_a?(String)
146
+ first.include?(":") ? first : "#{first}:#{last || first}"
147
+ else
148
+ last ||= first
149
+ "#{first + 1}:#{last + 1}"
150
+ end
151
+ print_titles(rows: rows_str, sheet: sheet)
152
+ end
153
+
154
+ # Sets repeating title columns for pagination on the target or active sheet.
155
+ #
156
+ # @example Repeat columns A through C
157
+ # wb.repeat_columns("A", "C")
158
+ #
159
+ # @param first [Integer, String] First column index (0-based) or column name/range.
160
+ # @param last [Integer, String, nil] Optional last column index/name.
161
+ # @param sheet [String, nil] Target sheet name.
162
+ # @return [void]
163
+ # @api public
164
+ #: (Integer | String first, ?(Integer | String)? last, ?sheet: String?) -> void
165
+ def repeat_columns(first, last = nil, sheet: nil)
166
+ cols_str = if first.is_a?(String)
167
+ first.include?(":") ? first : "#{first}:#{last || first}"
168
+ else
169
+ first_name = Utils.col_index_to_name(first)
170
+ last_name = if last.is_a?(Integer)
171
+ Utils.col_index_to_name(last)
172
+ elsif last
173
+ last.to_s
174
+ else
175
+ first_name
176
+ end
177
+ "#{first_name}:#{last_name}"
178
+ end
179
+ print_titles(cols: cols_str, sheet: sheet)
180
+ end
181
+
123
182
  # Sets workbook structure and window protection.
124
183
  #
125
184
  # @param opts [Hash] Protection options (e.g. lock_structure: true, password: "secret").
@@ -190,9 +249,16 @@ module Xlsxrb
190
249
  # Process styles from all sheets and collect style definitions
191
250
  processed_sheets, styles_definition = process_styles(@sheets)
192
251
 
252
+ # Auto-register print_area and print_titles defined names from sheet builders if not explicitly defined
253
+ @sheet_builders.each do |sb|
254
+ print_area(sb.print_area, sheet: sb.name) if sb.print_area && @defined_names.none? { |dn| dn[:name] == "_xlnm.Print_Area" && dn[:local_sheet_name] == sb.name }
255
+ print_titles(rows: sb.print_titles[:rows], cols: sb.print_titles[:cols], sheet: sb.name) if sb.print_titles && @defined_names.none? { |dn| dn[:name] == "_xlnm.Print_Titles" && dn[:local_sheet_name] == sb.name }
256
+ end
257
+
193
258
  # Store workbook-level metadata in unmapped_data
194
259
  wb_meta = {}
195
- wb_meta[:defined_names] = resolve_defined_names(@defined_names, processed_sheets) unless @defined_names.empty?
260
+ dns = resolve_defined_names(@defined_names, processed_sheets)
261
+ wb_meta[:defined_names] = dns unless dns.empty?
196
262
  wb_meta[:core_properties] = @core_properties unless @core_properties.empty?
197
263
  wb_meta[:app_properties] = @app_properties unless @app_properties.empty?
198
264
  wb_meta[:custom_properties] = @custom_properties unless @custom_properties.empty?
@@ -202,7 +268,8 @@ module Xlsxrb
202
268
  Elements::Workbook.new(
203
269
  sheets: processed_sheets,
204
270
  styles: styles_definition,
205
- unmapped_data: wb_meta.empty? ? {} : { facade: wb_meta }
271
+ unmapped_data: wb_meta.empty? ? {} : { facade: wb_meta },
272
+ defined_names: dns
206
273
  )
207
274
  end
208
275
 
@@ -275,19 +342,13 @@ module Xlsxrb
275
342
  height: row.height,
276
343
  hidden: row.hidden,
277
344
  custom_height: row.custom_height,
345
+ collapsed: row.collapsed,
278
346
  outline_level: row.outline_level,
279
347
  unmapped_data: row.unmapped_data,
280
348
  errors: row.errors
281
349
  )
282
350
  end
283
- Elements::Worksheet.new(
284
- name: sheet.name,
285
- rows: new_rows,
286
- columns: sheet.columns,
287
- charts: sheet.charts,
288
- unmapped_data: sheet.unmapped_data,
289
- errors: sheet.errors
290
- )
351
+ sheet.with(rows: new_rows)
291
352
  end
292
353
 
293
354
  [updated_sheets, styles_definition]