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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +104 -0
- data/README.md +17 -14
- data/lib/xlsxrb/colors.rb +118 -0
- data/lib/xlsxrb/elements/cell.rb +205 -16
- data/lib/xlsxrb/elements/column.rb +6 -4
- data/lib/xlsxrb/elements/coordinate_access.rb +32 -0
- data/lib/xlsxrb/elements/image.rb +128 -0
- data/lib/xlsxrb/elements/row.rb +206 -9
- data/lib/xlsxrb/elements/styles.rb +157 -0
- data/lib/xlsxrb/elements/types.rb +95 -1
- data/lib/xlsxrb/elements/workbook.rb +121 -4
- data/lib/xlsxrb/elements/worksheet.rb +519 -29
- data/lib/xlsxrb/elements.rb +2 -0
- data/lib/xlsxrb/number_formatter.rb +429 -0
- data/lib/xlsxrb/ooxml/cfb.rb +1 -1
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +7 -5
- data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +11 -4
- data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +7 -1
- data/lib/xlsxrb/ooxml/reader.rb +14 -17
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +7 -1
- data/lib/xlsxrb/ooxml/styles_parser.rb +39 -9
- data/lib/xlsxrb/ooxml/utils.rb +34 -18
- data/lib/xlsxrb/ooxml/workbook_parser.rb +74 -16
- data/lib/xlsxrb/ooxml/workbook_writer.rb +82 -23
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +319 -79
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +263 -66
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +5 -3
- data/lib/xlsxrb/ooxml/writer.rb +14 -0
- data/lib/xlsxrb/ooxml/xml_builder.rb +14 -2
- data/lib/xlsxrb/ooxml/zip_reader.rb +144 -28
- data/lib/xlsxrb/stream_row.rb +243 -16
- data/lib/xlsxrb/stream_sheet.rb +647 -16
- data/lib/xlsxrb/stream_writer.rb +375 -34
- data/lib/xlsxrb/style_builder.rb +308 -22
- data/lib/xlsxrb/utils.rb +211 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +72 -11
- data/lib/xlsxrb/worksheet_builder.rb +738 -24
- data/lib/xlsxrb.rb +1073 -83
- data/sig/generated/xlsxrb/colors.rbs +40 -0
- data/sig/generated/xlsxrb/elements/cell.rbs +113 -8
- data/sig/generated/xlsxrb/elements/column.rbs +3 -2
- data/sig/generated/xlsxrb/elements/coordinate_access.rbs +18 -0
- data/sig/generated/xlsxrb/elements/image.rbs +82 -0
- data/sig/generated/xlsxrb/elements/row.rbs +83 -4
- data/sig/generated/xlsxrb/elements/styles.rbs +79 -0
- data/sig/generated/xlsxrb/elements/types.rbs +43 -0
- data/sig/generated/xlsxrb/elements/workbook.rbs +79 -2
- data/sig/generated/xlsxrb/elements/worksheet.rbs +282 -18
- data/sig/generated/xlsxrb/number_formatter.rbs +132 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +6 -0
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +5 -2
- data/sig/generated/xlsxrb/ooxml/utils.rbs +17 -8
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +9 -3
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +1 -1
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +28 -6
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +13 -3
- data/sig/generated/xlsxrb/ooxml/writer.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +13 -0
- data/sig/generated/xlsxrb/stream_row.rbs +100 -6
- data/sig/generated/xlsxrb/stream_sheet.rbs +358 -14
- data/sig/generated/xlsxrb/stream_writer.rbs +220 -30
- data/sig/generated/xlsxrb/style_builder.rbs +55 -18
- data/sig/generated/xlsxrb/utils.rbs +151 -0
- data/sig/generated/xlsxrb/workbook_builder.rbs +26 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +356 -18
- data/sig/generated/xlsxrb.rbs +223 -27
- metadata +11 -1
data/lib/xlsxrb/stream_writer.rb
CHANGED
|
@@ -6,6 +6,7 @@ require "tempfile"
|
|
|
6
6
|
require_relative "style_builder"
|
|
7
7
|
require_relative "chart_builder"
|
|
8
8
|
require_relative "dsl_helpers"
|
|
9
|
+
require_relative "worksheet_builder"
|
|
9
10
|
require_relative "ooxml/writer"
|
|
10
11
|
require_relative "ooxml/worksheet_writer"
|
|
11
12
|
require_relative "ooxml/workbook_writer"
|
|
@@ -70,9 +71,12 @@ module Xlsxrb
|
|
|
70
71
|
@current_images = []
|
|
71
72
|
@current_shapes = []
|
|
72
73
|
@current_sheet_properties = {}
|
|
74
|
+
@current_sheet_format = {}
|
|
73
75
|
@current_sheet_view = {}
|
|
74
76
|
@current_row_breaks = []
|
|
75
77
|
@current_col_breaks = []
|
|
78
|
+
@current_protected_ranges = []
|
|
79
|
+
@current_cell_watches = []
|
|
76
80
|
@current_cells = {}
|
|
77
81
|
@styles = {} # { style_name => StyleBuilder }
|
|
78
82
|
@style_writer = Ooxml::Writer.new
|
|
@@ -220,15 +224,30 @@ module Xlsxrb
|
|
|
220
224
|
# @param hidden [Boolean] Whether the row is hidden.
|
|
221
225
|
# @param custom_height [Boolean] Whether to flag as custom height.
|
|
222
226
|
# @param outline_level [Integer, nil] Grouping/outline level (0 - 7).
|
|
227
|
+
# @param collapsed [Boolean] Whether the row is collapsed.
|
|
223
228
|
# @return [void]
|
|
224
229
|
# @api public
|
|
225
|
-
#: (Array[untyped] | Hash[untyped, untyped] values, ?styles: untyped, ?height: Float | Integer | nil, ?hidden: bool, ?custom_height: bool, ?outline_level: Integer | nil) -> void
|
|
226
|
-
def row(values, styles: nil, height: nil, hidden: false, custom_height: false, outline_level: nil)
|
|
230
|
+
#: (Array[untyped] | Hash[untyped, untyped] values, ?styles: untyped, ?height: Float | Integer | nil, ?hidden: bool, ?custom_height: bool, ?collapsed: bool, ?outline_level: Integer | nil) -> void
|
|
231
|
+
def row(values, styles: nil, height: nil, hidden: false, custom_height: false, collapsed: false, outline_level: nil)
|
|
227
232
|
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
228
233
|
|
|
229
|
-
@writer.row(values, styles: styles, height: height, hidden: hidden, custom_height: custom_height, outline_level: outline_level)
|
|
234
|
+
@writer.row(values, styles: styles, height: height, hidden: hidden, custom_height: custom_height, collapsed: collapsed, outline_level: outline_level)
|
|
235
|
+
end
|
|
236
|
+
alias add_row row
|
|
237
|
+
|
|
238
|
+
# Appends a row to the worksheet and returns self for chaining.
|
|
239
|
+
#
|
|
240
|
+
# @example
|
|
241
|
+
# sheet << ["A", 1] << ["B", 2]
|
|
242
|
+
#
|
|
243
|
+
# @param values [Array, Hash] Row cell values.
|
|
244
|
+
# @return [self]
|
|
245
|
+
# @api public
|
|
246
|
+
#: (Array[untyped] | Hash[untyped, untyped] values) -> self
|
|
247
|
+
def <<(values)
|
|
248
|
+
row(values)
|
|
249
|
+
self
|
|
230
250
|
end
|
|
231
|
-
alias << row
|
|
232
251
|
|
|
233
252
|
# Configures column width and properties.
|
|
234
253
|
#
|
|
@@ -287,7 +306,7 @@ module Xlsxrb
|
|
|
287
306
|
# @param location [String, nil] Destination location / URL (keyword alternative).
|
|
288
307
|
# @return [void]
|
|
289
308
|
# @api public
|
|
290
|
-
#: (String cell, ?String? url, ?display: String?, ?tooltip: String?, ?location: String?) -> void
|
|
309
|
+
#: (String | Integer cell, ?(String | Elements::Hyperlink)? url, ?display: String?, ?tooltip: String?, ?location: String?) -> void
|
|
291
310
|
def hyperlink(...)
|
|
292
311
|
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
293
312
|
|
|
@@ -344,15 +363,24 @@ module Xlsxrb
|
|
|
344
363
|
|
|
345
364
|
# Adds data validation rules to a range.
|
|
346
365
|
#
|
|
366
|
+
# Adds data validation to a cell or range.
|
|
367
|
+
#
|
|
347
368
|
# @example Dropdown list validation
|
|
348
369
|
# s.validate_data("B2:B100", type: "list", formula1: '"High,Medium,Low"')
|
|
349
370
|
#
|
|
350
|
-
# @
|
|
351
|
-
#
|
|
371
|
+
# @example Block syntax
|
|
372
|
+
# s.validate_data("B2:B100") do |dv|
|
|
373
|
+
# dv.type :list
|
|
374
|
+
# dv.formula1 '"High,Medium,Low"'
|
|
375
|
+
# end
|
|
376
|
+
#
|
|
377
|
+
# @param range [String, nil] The cell range (e.g. "B2:B10").
|
|
378
|
+
# @param type [String, Symbol, nil] Validation type ("list", "whole", "decimal", "date", "time", "textLength", "custom").
|
|
352
379
|
# @param opts [Hash] Validation options.
|
|
380
|
+
# @yield [data_validation_builder] Optional configuration block.
|
|
353
381
|
# @return [void]
|
|
354
382
|
# @api public
|
|
355
|
-
#: (String range, ?type: String | Symbol
|
|
383
|
+
#: (?String? range, ?type: (String | Symbol)?, **untyped opts) ?{ (DataValidationBuilder) -> void } -> void
|
|
356
384
|
def validate_data(...)
|
|
357
385
|
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
358
386
|
|
|
@@ -378,18 +406,25 @@ module Xlsxrb
|
|
|
378
406
|
|
|
379
407
|
# Adds a formatted Excel Table to the sheet.
|
|
380
408
|
#
|
|
381
|
-
# @example
|
|
409
|
+
# @example Standard keyword arguments
|
|
382
410
|
# s.table("A1:C10", columns: ["ID", "Name", "Total"], name: "SalesTable", style: "TableStyleMedium9")
|
|
383
411
|
#
|
|
384
|
-
# @
|
|
385
|
-
#
|
|
412
|
+
# @example Block syntax
|
|
413
|
+
# s.table("A1:C10") do |t|
|
|
414
|
+
# t.columns ["ID", "Name", "Total"]
|
|
415
|
+
# t.style "TableStyleMedium9"
|
|
416
|
+
# end
|
|
417
|
+
#
|
|
418
|
+
# @param ref [String, nil] The cell range for the table (e.g. "A1:D10").
|
|
419
|
+
# @param columns [Array<String>, Array<Hash>, nil] Column names or definitions.
|
|
386
420
|
# @param name [String, nil] Table name.
|
|
387
421
|
# @param display_name [String, nil] Display name.
|
|
388
422
|
# @param style [String, nil] Table style name.
|
|
389
423
|
# @param opts [Hash] Additional options.
|
|
424
|
+
# @yield [table_builder] Optional configuration block.
|
|
390
425
|
# @return [void]
|
|
391
426
|
# @api public
|
|
392
|
-
#: (String ref, columns: untyped, ?name: String?, ?display_name: String?, ?style: String?, **untyped opts) -> void
|
|
427
|
+
#: (?String? ref, ?columns: untyped, ?name: String?, ?display_name: String?, ?style: String?, **untyped opts) ?{ (TableBuilder) -> void } -> void
|
|
393
428
|
def table(...)
|
|
394
429
|
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
395
430
|
|
|
@@ -460,6 +495,30 @@ module Xlsxrb
|
|
|
460
495
|
@writer.sparkline_group(...)
|
|
461
496
|
end
|
|
462
497
|
|
|
498
|
+
# Adds a single sparkline to the sheet.
|
|
499
|
+
#
|
|
500
|
+
# @example Add a line sparkline
|
|
501
|
+
# s.add_sparkline(location: "F1", range: "A1:E1")
|
|
502
|
+
#
|
|
503
|
+
# @example Add a column sparkline with high/low markers
|
|
504
|
+
# s.add_sparkline(location: "F2", range: "A2:E2", type: :column, high: true, low: true)
|
|
505
|
+
#
|
|
506
|
+
# @example Add a win/loss sparkline
|
|
507
|
+
# s.add_sparkline(location: "F3", range: "A3:E3", type: :win_loss)
|
|
508
|
+
#
|
|
509
|
+
# @param location [String, nil] Target cell for the sparkline (e.g. "F1").
|
|
510
|
+
# @param range [String, nil] Data range for the sparkline (e.g. "A1:E1").
|
|
511
|
+
# @param type [Symbol, String, nil] Sparkline type (:line, :column, :win_loss / :stacked).
|
|
512
|
+
# @param opts [Hash] Additional sparkline options.
|
|
513
|
+
# @return [void]
|
|
514
|
+
# @api public
|
|
515
|
+
#: (?location: String?, ?range: String?, ?type: (String | Symbol)?, **untyped opts) -> void
|
|
516
|
+
def add_sparkline(...)
|
|
517
|
+
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
518
|
+
|
|
519
|
+
@writer.add_sparkline(...)
|
|
520
|
+
end
|
|
521
|
+
|
|
463
522
|
# Sets workbook-level properties.
|
|
464
523
|
#
|
|
465
524
|
# @param opts [Hash] Workbook property options.
|
|
@@ -554,6 +613,32 @@ module Xlsxrb
|
|
|
554
613
|
|
|
555
614
|
@writer.print_titles(...)
|
|
556
615
|
end
|
|
616
|
+
|
|
617
|
+
# Sets repeating title rows to appear at the top of each printed page.
|
|
618
|
+
#
|
|
619
|
+
# @param first [Integer, String] First row index (0-based) or range string (e.g. "1:2").
|
|
620
|
+
# @param last [Integer, String, nil] Optional last row index (0-based).
|
|
621
|
+
# @return [void]
|
|
622
|
+
# @api public
|
|
623
|
+
#: (Integer | String first, ?(Integer | String)? last) -> void
|
|
624
|
+
def repeat_rows(first, last = nil)
|
|
625
|
+
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
626
|
+
|
|
627
|
+
@writer.repeat_rows(first, last, sheet: @sheet_name)
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
# Sets repeating title columns to appear at the left of each printed page.
|
|
631
|
+
#
|
|
632
|
+
# @param first [Integer, String] First column index (0-based) or column name/range.
|
|
633
|
+
# @param last [Integer, String, nil] Optional last column index/name.
|
|
634
|
+
# @return [void]
|
|
635
|
+
# @api public
|
|
636
|
+
#: (Integer | String first, ?(Integer | String)? last) -> void
|
|
637
|
+
def repeat_columns(first, last = nil)
|
|
638
|
+
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
639
|
+
|
|
640
|
+
@writer.repeat_columns(first, last, sheet: @sheet_name)
|
|
641
|
+
end
|
|
557
642
|
# simplecov:enable
|
|
558
643
|
|
|
559
644
|
# Splits sheet view into panes.
|
|
@@ -765,6 +850,20 @@ module Xlsxrb
|
|
|
765
850
|
@writer.sheet_view(...)
|
|
766
851
|
end
|
|
767
852
|
|
|
853
|
+
# Configures sheet format properties (e.g. default_row_height, default_col_width).
|
|
854
|
+
#
|
|
855
|
+
# @param name [Symbol, String, Hash, nil] Property name or hash of properties.
|
|
856
|
+
# @param value [Object, nil] Property value when name is provided.
|
|
857
|
+
# @param opts [Hash] Keyword arguments for sheet format properties.
|
|
858
|
+
# @return [Hash[Symbol, untyped]]
|
|
859
|
+
# @api public
|
|
860
|
+
#: (?Symbol | String | Hash[Symbol, untyped] | nil name, ?untyped value, **untyped opts) -> Hash[Symbol, untyped]
|
|
861
|
+
def sheet_format(...)
|
|
862
|
+
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
863
|
+
|
|
864
|
+
@writer.sheet_format(...)
|
|
865
|
+
end
|
|
866
|
+
|
|
768
867
|
# simplecov:disable
|
|
769
868
|
# Edge case / untested delegation block
|
|
770
869
|
# Adds a horizontal page break after the given row index.
|
|
@@ -794,6 +893,35 @@ module Xlsxrb
|
|
|
794
893
|
@writer.page_break_col(...)
|
|
795
894
|
end
|
|
796
895
|
# simplecov:enable
|
|
896
|
+
|
|
897
|
+
# Adds a protected range to the sheet.
|
|
898
|
+
#
|
|
899
|
+
# @param name [String] Name of the protected range.
|
|
900
|
+
# @param sqref [String] Cell range (e.g. "A1:B10").
|
|
901
|
+
# @param password [String, nil] Optional password or hash.
|
|
902
|
+
# @param opts [Hash] Additional options.
|
|
903
|
+
# @return [void]
|
|
904
|
+
# @api public
|
|
905
|
+
#: (String name, String sqref, ?password: String?, **untyped opts) -> void
|
|
906
|
+
def protected_range(...)
|
|
907
|
+
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
908
|
+
|
|
909
|
+
@writer.protected_range(...)
|
|
910
|
+
end
|
|
911
|
+
alias add_protected_range protected_range
|
|
912
|
+
|
|
913
|
+
# Adds a cell watch to the sheet.
|
|
914
|
+
#
|
|
915
|
+
# @param ref [String] Cell reference (e.g. "A1").
|
|
916
|
+
# @return [void]
|
|
917
|
+
# @api public
|
|
918
|
+
#: (String ref) -> void
|
|
919
|
+
def cell_watch(...)
|
|
920
|
+
raise Error, "Sheet '#{@sheet_name}' is no longer active. In streaming mode, you cannot write to a previous sheet." if @writer.current_sheet != @sheet_name
|
|
921
|
+
|
|
922
|
+
@writer.cell_watch(...)
|
|
923
|
+
end
|
|
924
|
+
alias add_cell_watch cell_watch
|
|
797
925
|
end
|
|
798
926
|
|
|
799
927
|
# Adds a new sheet to the workbook and starts streaming rows into it.
|
|
@@ -829,7 +957,8 @@ module Xlsxrb
|
|
|
829
957
|
@sheet_entry_started = false
|
|
830
958
|
@current_row_buffer = String.new(capacity: 65_536)
|
|
831
959
|
@current_sheet_io = StringIO.new(@current_row_buffer)
|
|
832
|
-
|
|
960
|
+
date1904 = @workbook_properties&.[](:date1904) ? true : false
|
|
961
|
+
@current_row_writer = Ooxml::WorksheetWriter.new(@current_sheet_io, date1904: date1904)
|
|
833
962
|
@current_row_writer.instance_variable_set(:@started, true)
|
|
834
963
|
|
|
835
964
|
@current_columns = []
|
|
@@ -856,9 +985,12 @@ module Xlsxrb
|
|
|
856
985
|
@current_images = []
|
|
857
986
|
@current_shapes = []
|
|
858
987
|
@current_sheet_properties = {}
|
|
988
|
+
@current_sheet_format = {}
|
|
859
989
|
@current_sheet_view = {}
|
|
860
990
|
@current_row_breaks = []
|
|
861
991
|
@current_col_breaks = []
|
|
992
|
+
@current_protected_ranges = []
|
|
993
|
+
@current_cell_watches = []
|
|
862
994
|
@current_cells = {}
|
|
863
995
|
|
|
864
996
|
return unless block_given?
|
|
@@ -883,14 +1015,26 @@ module Xlsxrb
|
|
|
883
1015
|
row_buf.clear
|
|
884
1016
|
end
|
|
885
1017
|
|
|
886
|
-
@
|
|
1018
|
+
if @current_columns && !@current_columns.empty? && @style_name_to_id
|
|
1019
|
+
@current_columns.each do |col|
|
|
1020
|
+
s = col[:style] || col[:style_index]
|
|
1021
|
+
if s.is_a?(Symbol) || s.is_a?(String)
|
|
1022
|
+
resolved = @style_name_to_id[s] || @style_name_to_id[s.to_s]
|
|
1023
|
+
col[:style] = resolved if resolved
|
|
1024
|
+
end
|
|
1025
|
+
end
|
|
1026
|
+
end
|
|
1027
|
+
|
|
1028
|
+
date1904 = @workbook_properties&.[](:date1904) ? true : false
|
|
1029
|
+
@current_row_writer = Ooxml::WorksheetWriter.new(zip_io, date1904: date1904)
|
|
887
1030
|
@current_row_writer.start(
|
|
888
1031
|
columns: @current_columns,
|
|
889
1032
|
sheet_properties: @current_sheet_properties.empty? ? nil : @current_sheet_properties,
|
|
890
1033
|
freeze_pane: @current_freeze_pane,
|
|
891
1034
|
split_pane: @current_split_pane,
|
|
892
1035
|
selection: @current_selection,
|
|
893
|
-
sheet_view: @current_sheet_view.empty? ? nil : @current_sheet_view
|
|
1036
|
+
sheet_view: @current_sheet_view.empty? ? nil : @current_sheet_view,
|
|
1037
|
+
sheet_format: @current_sheet_format.empty? ? nil : @current_sheet_format
|
|
894
1038
|
)
|
|
895
1039
|
@zip.write_data(@current_row_buffer) unless @current_row_buffer.empty?
|
|
896
1040
|
@current_row_buffer.clear
|
|
@@ -906,8 +1050,8 @@ module Xlsxrb
|
|
|
906
1050
|
# @param outline_level [Integer, nil] Grouping/outline level (0 - 7).
|
|
907
1051
|
# @return [void]
|
|
908
1052
|
# @api public
|
|
909
|
-
#: (Array[untyped] | Hash[untyped, untyped] values, ?styles: untyped, ?height: Float | Integer | nil, ?hidden: bool, ?custom_height: bool, ?outline_level: Integer | nil) -> void
|
|
910
|
-
def row(values, styles: nil, height: nil, hidden: false, custom_height: false, outline_level: nil)
|
|
1053
|
+
#: (Array[untyped] | Hash[untyped, untyped] values, ?styles: untyped, ?height: Float | Integer | nil, ?hidden: bool, ?custom_height: bool, ?collapsed: bool, ?outline_level: Integer | nil) -> void
|
|
1054
|
+
def row(values, styles: nil, height: nil, hidden: false, custom_height: false, collapsed: false, outline_level: nil)
|
|
911
1055
|
sheet if @current_sheet.nil?
|
|
912
1056
|
|
|
913
1057
|
row_index = @current_row_index
|
|
@@ -931,36 +1075,60 @@ module Xlsxrb
|
|
|
931
1075
|
raise ArgumentError, "Row contains #{values.length} columns, exceeding Excel limit of 16_384 columns" if @strict_excel_mode && values.length > 16_384
|
|
932
1076
|
|
|
933
1077
|
attrs = nil
|
|
934
|
-
if height || hidden || outline_level
|
|
1078
|
+
if height || hidden || outline_level || collapsed
|
|
935
1079
|
attrs = {}
|
|
936
1080
|
attrs[:height] = height if height
|
|
937
1081
|
attrs[:hidden] = true if hidden
|
|
938
1082
|
attrs[:custom_height] = custom_height || !height.nil?
|
|
1083
|
+
attrs[:collapsed] = true if collapsed
|
|
939
1084
|
attrs[:outline_level] = outline_level if outline_level
|
|
940
1085
|
end
|
|
941
1086
|
|
|
942
1087
|
@current_row_writer.write_row_values(row_index, values, styles: styles, style_map: @style_name_to_id, sst: @sst, sst_index: @sst_index, attrs: attrs)
|
|
943
1088
|
start_sheet_entry if !@sheet_entry_started && @current_row_buffer.bytesize >= 65_536
|
|
944
1089
|
end
|
|
945
|
-
alias
|
|
1090
|
+
alias add_row row
|
|
1091
|
+
|
|
1092
|
+
# Appends a row to the worksheet and returns self for chaining.
|
|
1093
|
+
#
|
|
1094
|
+
# @example
|
|
1095
|
+
# writer << ["A", 1] << ["B", 2]
|
|
1096
|
+
#
|
|
1097
|
+
# @param values [Array, Hash] Row cell values.
|
|
1098
|
+
# @return [self]
|
|
1099
|
+
# @api public
|
|
1100
|
+
#: (Array[untyped] | Hash[untyped, untyped] values) -> self
|
|
1101
|
+
def <<(values)
|
|
1102
|
+
row(values)
|
|
1103
|
+
self
|
|
1104
|
+
end
|
|
946
1105
|
|
|
947
1106
|
# Sets column formatting and properties for one or multiple columns.
|
|
948
1107
|
#
|
|
949
1108
|
# @param index [Integer, String, Range, Array] Column index (0-based) or letter ("A".."D").
|
|
950
1109
|
# @param width [Float, Integer, nil] Column width in character units (0 - 255).
|
|
951
1110
|
# @param hidden [Boolean] Whether the column is hidden.
|
|
952
|
-
# @param
|
|
953
|
-
# @param outline_level [Integer, nil] Grouping/outline level.
|
|
1111
|
+
# @param style [Integer, Symbol, String, nil] Column style format or index.
|
|
954
1112
|
# @return [void]
|
|
955
1113
|
# @api public
|
|
956
|
-
#: (Integer | String | Range[Integer | String] | Array[Integer | String] index, ?width: Float | Integer | nil, ?hidden: bool, ?custom_width: bool, ?outline_level: Integer | nil) -> void
|
|
957
|
-
def column(index, width: nil, hidden: false, custom_width: false, outline_level: nil)
|
|
1114
|
+
#: (Integer | String | Range[Integer | String] | Array[Integer | String] index, ?width: Float | Integer | nil, ?hidden: bool, ?custom_width: bool, ?outline_level: Integer | nil, ?style: (Integer | Symbol | String)?) -> void
|
|
1115
|
+
def column(index, width: nil, hidden: false, custom_width: false, outline_level: nil, style: nil)
|
|
958
1116
|
raise ArgumentError, "Column width #{width} must be between 0 and 255 characters (Excel limitation)" if @strict_excel_mode && width && (width.negative? || width > 255)
|
|
959
1117
|
|
|
960
1118
|
sheet if @current_sheet.nil?
|
|
961
1119
|
|
|
1120
|
+
style_id = if @style_name_to_id && style
|
|
1121
|
+
@style_name_to_id[style] || @style_name_to_id[style.to_s] || style
|
|
1122
|
+
else
|
|
1123
|
+
style
|
|
1124
|
+
end
|
|
962
1125
|
DslHelpers.normalize_column_indices(index).each do |idx|
|
|
963
|
-
|
|
1126
|
+
entry = { index: idx, width: width, hidden: hidden, custom_width: custom_width || !width.nil?, outline_level: outline_level }
|
|
1127
|
+
if style_id
|
|
1128
|
+
entry[:style] = style_id
|
|
1129
|
+
@current_row_writer&.set_column_style(idx, style_id)
|
|
1130
|
+
end
|
|
1131
|
+
@current_columns << entry
|
|
964
1132
|
end
|
|
965
1133
|
end
|
|
966
1134
|
|
|
@@ -993,9 +1161,18 @@ module Xlsxrb
|
|
|
993
1161
|
# @param location [String, nil] Internal location.
|
|
994
1162
|
# @return [void]
|
|
995
1163
|
# @api public
|
|
996
|
-
#: (String | Integer cell, ?String? url, ?display: String?, ?tooltip: String?, ?location: String?) -> void
|
|
1164
|
+
#: (String | Integer cell, ?(String | Elements::Hyperlink)? url, ?display: String?, ?tooltip: String?, ?location: String?) -> void
|
|
997
1165
|
def hyperlink(cell, url = nil, display: nil, tooltip: nil, location: nil)
|
|
998
1166
|
sheet if @current_sheet.nil?
|
|
1167
|
+
if url.is_a?(Elements::Hyperlink)
|
|
1168
|
+
link = { cell: cell }
|
|
1169
|
+
link[:url] = url.url if url.url
|
|
1170
|
+
link[:display] = url.display || display if url.display || display
|
|
1171
|
+
link[:tooltip] = url.tooltip || tooltip if url.tooltip || tooltip
|
|
1172
|
+
link[:location] = url.location || location if url.location || location
|
|
1173
|
+
@current_hyperlinks << link
|
|
1174
|
+
return
|
|
1175
|
+
end
|
|
999
1176
|
link = { cell: cell }
|
|
1000
1177
|
link[:url] = url if url
|
|
1001
1178
|
link[:display] = display if display
|
|
@@ -1042,13 +1219,22 @@ module Xlsxrb
|
|
|
1042
1219
|
|
|
1043
1220
|
# Adds a data validation rule.
|
|
1044
1221
|
#
|
|
1045
|
-
# @param sqref [String] Cell range.
|
|
1222
|
+
# @param sqref [String, nil] Cell range.
|
|
1046
1223
|
# @param opts [Hash] Validation options.
|
|
1224
|
+
# @yield [data_validation_builder] Optional configuration block.
|
|
1047
1225
|
# @return [void]
|
|
1048
1226
|
# @api public
|
|
1049
|
-
#: (
|
|
1050
|
-
def validate_data(sqref, **opts)
|
|
1227
|
+
#: (?String? sqref, **untyped opts) ?{ (DataValidationBuilder) -> void } -> void
|
|
1228
|
+
def validate_data(sqref = nil, **opts)
|
|
1051
1229
|
sheet if @current_sheet.nil?
|
|
1230
|
+
if block_given?
|
|
1231
|
+
builder = DataValidationBuilder.new(sqref, **opts)
|
|
1232
|
+
yield builder
|
|
1233
|
+
opts = builder.to_h
|
|
1234
|
+
sqref = opts.delete(:sqref) || sqref
|
|
1235
|
+
end
|
|
1236
|
+
raise ArgumentError, "data validation sqref must be provided" unless sqref
|
|
1237
|
+
|
|
1052
1238
|
@current_data_validations << opts.merge(sqref: sqref)
|
|
1053
1239
|
end
|
|
1054
1240
|
|
|
@@ -1066,18 +1252,33 @@ module Xlsxrb
|
|
|
1066
1252
|
|
|
1067
1253
|
# Adds an Excel Table (ListObject).
|
|
1068
1254
|
#
|
|
1069
|
-
# @param ref [String] Table range.
|
|
1070
|
-
# @param columns [Array<String
|
|
1255
|
+
# @param ref [String, nil] Table range.
|
|
1256
|
+
# @param columns [Array<String>, nil] Column names.
|
|
1071
1257
|
# @param name [String, nil] Table name.
|
|
1072
1258
|
# @param display_name [String, nil] Display name.
|
|
1073
1259
|
# @param style [String, nil] Table style.
|
|
1074
1260
|
# @param opts [Hash] Additional options.
|
|
1261
|
+
# @yield [table_builder] Optional configuration block.
|
|
1075
1262
|
# @return [void]
|
|
1076
1263
|
# @api public
|
|
1077
|
-
#: (
|
|
1078
|
-
def table(ref, columns
|
|
1264
|
+
#: (?String? ref, ?columns: untyped, ?name: untyped, ?display_name: untyped, ?style: untyped, **untyped opts) ?{ (TableBuilder) -> void } -> void
|
|
1265
|
+
def table(ref = nil, columns: nil, name: nil, display_name: nil, style: nil, **opts)
|
|
1079
1266
|
sheet if @current_sheet.nil?
|
|
1080
|
-
|
|
1267
|
+
opts = opts.dup
|
|
1268
|
+
if block_given?
|
|
1269
|
+
builder = TableBuilder.new(ref, columns: columns, name: name, display_name: display_name, style: style, **opts)
|
|
1270
|
+
yield builder
|
|
1271
|
+
opts = builder.to_h
|
|
1272
|
+
ref = opts.delete(:ref) || ref
|
|
1273
|
+
columns = opts.delete(:columns) || columns
|
|
1274
|
+
name = opts.delete(:name) || name
|
|
1275
|
+
display_name = opts.delete(:display_name) || display_name
|
|
1276
|
+
style = opts.delete(:style) || style
|
|
1277
|
+
end
|
|
1278
|
+
raise ArgumentError, "table ref must be provided" unless ref
|
|
1279
|
+
raise ArgumentError, "table columns must be provided" if columns.nil?
|
|
1280
|
+
|
|
1281
|
+
@current_tables << DslHelpers.normalize_table_options(ref, columns: columns, name: name, display_name: display_name, style: style, **opts)
|
|
1081
1282
|
end
|
|
1082
1283
|
|
|
1083
1284
|
# Adds a Pivot Table.
|
|
@@ -1134,6 +1335,38 @@ module Xlsxrb
|
|
|
1134
1335
|
@current_sparkline_groups << group
|
|
1135
1336
|
end
|
|
1136
1337
|
|
|
1338
|
+
# Adds a single sparkline to the sheet.
|
|
1339
|
+
#
|
|
1340
|
+
# @example Add a line sparkline
|
|
1341
|
+
# writer.add_sparkline(location: "F1", range: "A1:E1")
|
|
1342
|
+
#
|
|
1343
|
+
# @example Add a column sparkline with high/low markers
|
|
1344
|
+
# writer.add_sparkline(location: "F2", range: "A2:E2", type: :column, high: true, low: true)
|
|
1345
|
+
#
|
|
1346
|
+
# @example Add a win/loss sparkline
|
|
1347
|
+
# writer.add_sparkline(location: "F3", range: "A3:E3", type: :win_loss)
|
|
1348
|
+
#
|
|
1349
|
+
# @param location [String, nil] Target cell for the sparkline (e.g. "F1").
|
|
1350
|
+
# @param range [String, nil] Data range for the sparkline (e.g. "A1:E1").
|
|
1351
|
+
# @param type [Symbol, String, nil] Sparkline type (:line, :column, :win_loss / :stacked).
|
|
1352
|
+
# @param opts [Hash] Additional sparkline options.
|
|
1353
|
+
# @return [void]
|
|
1354
|
+
# @api public
|
|
1355
|
+
#: (?location: String?, ?range: String?, ?type: (String | Symbol)?, **untyped opts) -> void
|
|
1356
|
+
def add_sparkline(location: nil, range: nil, type: nil, **opts)
|
|
1357
|
+
loc = location || opts.delete(:location_ref)
|
|
1358
|
+
rng = range || opts.delete(:data_ref) || opts.delete(:data)
|
|
1359
|
+
raise ArgumentError, "Missing required location: parameter for sparkline" unless loc
|
|
1360
|
+
raise ArgumentError, "Missing required range: parameter for sparkline" unless rng
|
|
1361
|
+
|
|
1362
|
+
mapped_type = case type&.to_s
|
|
1363
|
+
when "win_loss" then "stacked"
|
|
1364
|
+
when nil, "" then nil
|
|
1365
|
+
else type.to_s
|
|
1366
|
+
end
|
|
1367
|
+
sparkline_group(sparklines: [{ data_ref: rng.to_s, location_ref: loc.to_s }], type: mapped_type, **opts)
|
|
1368
|
+
end
|
|
1369
|
+
|
|
1137
1370
|
# Merges a range of cells into a single cell.
|
|
1138
1371
|
#
|
|
1139
1372
|
# @param range [String, Hash, nil] Cell range (e.g. "A1:B2") or hash of coordinates.
|
|
@@ -1322,6 +1555,25 @@ module Xlsxrb
|
|
|
1322
1555
|
@current_sheet_view[name] = value
|
|
1323
1556
|
end
|
|
1324
1557
|
|
|
1558
|
+
# Configures sheet format properties (e.g. default_row_height, default_col_width).
|
|
1559
|
+
#
|
|
1560
|
+
# @param name [Symbol, String, Hash, nil] Property name or hash of properties.
|
|
1561
|
+
# @param value [Object, nil] Property value when name is provided.
|
|
1562
|
+
# @param opts [Hash] Keyword arguments for sheet format properties.
|
|
1563
|
+
# @return [Hash[Symbol, untyped]]
|
|
1564
|
+
# @api public
|
|
1565
|
+
#: (?Symbol | String | Hash[Symbol, untyped] | nil name, ?untyped value, **untyped opts) -> Hash[Symbol, untyped]
|
|
1566
|
+
def sheet_format(name = nil, value = nil, **opts)
|
|
1567
|
+
sheet if @current_sheet.nil?
|
|
1568
|
+
if name.is_a?(Hash)
|
|
1569
|
+
@current_sheet_format.merge!(name)
|
|
1570
|
+
elsif name && value
|
|
1571
|
+
@current_sheet_format[name.to_sym] = value
|
|
1572
|
+
end
|
|
1573
|
+
@current_sheet_format.merge!(opts) unless opts.empty?
|
|
1574
|
+
@current_sheet_format
|
|
1575
|
+
end
|
|
1576
|
+
|
|
1325
1577
|
# Inserts a horizontal page break before a row.
|
|
1326
1578
|
#
|
|
1327
1579
|
# @param row_num [Integer] 1-based row number.
|
|
@@ -1351,6 +1603,36 @@ module Xlsxrb
|
|
|
1351
1603
|
# simplecov:enable
|
|
1352
1604
|
end
|
|
1353
1605
|
|
|
1606
|
+
# Adds a protected range to the current sheet.
|
|
1607
|
+
#
|
|
1608
|
+
# @param name [String] Name of the protected range.
|
|
1609
|
+
# @param sqref [String] Cell range (e.g. "A1:B10").
|
|
1610
|
+
# @param password [String, nil] Optional password or hash.
|
|
1611
|
+
# @param opts [Hash] Additional options.
|
|
1612
|
+
# @return [void]
|
|
1613
|
+
# @api public
|
|
1614
|
+
#: (String name, String sqref, ?password: String?, **untyped opts) -> void
|
|
1615
|
+
def protected_range(name, sqref, password: nil, **opts)
|
|
1616
|
+
sheet if @current_sheet.nil?
|
|
1617
|
+
entry = { name: name.to_s, sqref: sqref.to_s }
|
|
1618
|
+
entry[:password] = password if password
|
|
1619
|
+
entry.merge!(opts) unless opts.empty?
|
|
1620
|
+
@current_protected_ranges << DslHelpers.normalize_protection_options(entry)
|
|
1621
|
+
end
|
|
1622
|
+
alias add_protected_range protected_range
|
|
1623
|
+
|
|
1624
|
+
# Adds a cell watch to the current sheet.
|
|
1625
|
+
#
|
|
1626
|
+
# @param ref [String] Cell reference (e.g. "A1").
|
|
1627
|
+
# @return [void]
|
|
1628
|
+
# @api public
|
|
1629
|
+
#: (String ref) -> void
|
|
1630
|
+
def cell_watch(ref)
|
|
1631
|
+
sheet if @current_sheet.nil?
|
|
1632
|
+
@current_cell_watches << ref.to_s
|
|
1633
|
+
end
|
|
1634
|
+
alias add_cell_watch cell_watch
|
|
1635
|
+
|
|
1354
1636
|
# --- Workbook-Level Methods ---
|
|
1355
1637
|
|
|
1356
1638
|
# Adds a defined name.
|
|
@@ -1398,6 +1680,11 @@ module Xlsxrb
|
|
|
1398
1680
|
#: (?rows: String?, ?cols: String?, ?sheet: String?) -> void
|
|
1399
1681
|
def print_titles(rows: nil, cols: nil, sheet: nil)
|
|
1400
1682
|
sheet_name = sheet || @current_sheet || "Sheet1"
|
|
1683
|
+
existing = @defined_names.find { |dn| dn[:name] == "_xlnm.Print_Titles" && dn[:local_sheet_name] == sheet_name }
|
|
1684
|
+
if existing && (rows.nil? || cols.nil?)
|
|
1685
|
+
cols = Regexp.last_match(1).delete("$") if cols.nil? && existing[:value] =~ /'[^']*'!\$([A-Za-z]+:\$[A-Za-z]+)/
|
|
1686
|
+
rows = Regexp.last_match(1).delete("$") if rows.nil? && existing[:value] =~ /'[^']*'!\$([0-9]+:\$[0-9]+)/
|
|
1687
|
+
end
|
|
1401
1688
|
parts = []
|
|
1402
1689
|
parts << "'#{sheet_name}'!$#{cols.sub(":", ":$")}" if cols
|
|
1403
1690
|
parts << "'#{sheet_name}'!$#{rows.sub(":", ":$")}" if rows
|
|
@@ -1406,6 +1693,55 @@ module Xlsxrb
|
|
|
1406
1693
|
defined_name("_xlnm.Print_Titles", value, sheet: sheet_name)
|
|
1407
1694
|
end
|
|
1408
1695
|
|
|
1696
|
+
# Sets repeating title rows for pagination on the current or named sheet.
|
|
1697
|
+
#
|
|
1698
|
+
# @example Repeat first row
|
|
1699
|
+
# stream.repeat_rows(0)
|
|
1700
|
+
#
|
|
1701
|
+
# @param first [Integer, String] First row index (0-based) or range string (e.g. "1:2").
|
|
1702
|
+
# @param last [Integer, String, nil] Optional last row index (0-based).
|
|
1703
|
+
# @param sheet [String, nil] Target sheet name.
|
|
1704
|
+
# @return [void]
|
|
1705
|
+
# @api public
|
|
1706
|
+
#: (Integer | String first, ?(Integer | String)? last, ?sheet: String?) -> void
|
|
1707
|
+
def repeat_rows(first, last = nil, sheet: nil)
|
|
1708
|
+
rows_str = if first.is_a?(String)
|
|
1709
|
+
first.include?(":") ? first : "#{first}:#{last || first}"
|
|
1710
|
+
else
|
|
1711
|
+
last ||= first
|
|
1712
|
+
"#{first + 1}:#{last + 1}"
|
|
1713
|
+
end
|
|
1714
|
+
print_titles(rows: rows_str, sheet: sheet)
|
|
1715
|
+
end
|
|
1716
|
+
|
|
1717
|
+
# Sets repeating title columns for pagination on the current or named sheet.
|
|
1718
|
+
#
|
|
1719
|
+
# @example Repeat columns A through C
|
|
1720
|
+
# stream.repeat_columns("A", "C")
|
|
1721
|
+
#
|
|
1722
|
+
# @param first [Integer, String] First column index (0-based) or column name/range.
|
|
1723
|
+
# @param last [Integer, String, nil] Optional last column index/name.
|
|
1724
|
+
# @param sheet [String, nil] Target sheet name.
|
|
1725
|
+
# @return [void]
|
|
1726
|
+
# @api public
|
|
1727
|
+
#: (Integer | String first, ?(Integer | String)? last, ?sheet: String?) -> void
|
|
1728
|
+
def repeat_columns(first, last = nil, sheet: nil)
|
|
1729
|
+
cols_str = if first.is_a?(String)
|
|
1730
|
+
first.include?(":") ? first : "#{first}:#{last || first}"
|
|
1731
|
+
else
|
|
1732
|
+
first_name = Utils.col_index_to_name(first)
|
|
1733
|
+
last_name = if last.is_a?(Integer)
|
|
1734
|
+
Utils.col_index_to_name(last)
|
|
1735
|
+
elsif last
|
|
1736
|
+
last.to_s
|
|
1737
|
+
else
|
|
1738
|
+
first_name
|
|
1739
|
+
end
|
|
1740
|
+
"#{first_name}:#{last_name}"
|
|
1741
|
+
end
|
|
1742
|
+
print_titles(cols: cols_str, sheet: sheet)
|
|
1743
|
+
end
|
|
1744
|
+
|
|
1409
1745
|
# Sets workbook protection.
|
|
1410
1746
|
#
|
|
1411
1747
|
# @param opts [Hash] Protection options.
|
|
@@ -1623,9 +1959,12 @@ module Xlsxrb
|
|
|
1623
1959
|
images: @current_images,
|
|
1624
1960
|
shapes: @current_shapes,
|
|
1625
1961
|
sheet_properties: @current_sheet_properties,
|
|
1962
|
+
sheet_format: @current_sheet_format,
|
|
1626
1963
|
sheet_view: @current_sheet_view,
|
|
1627
1964
|
row_breaks: @current_row_breaks,
|
|
1628
|
-
col_breaks: @current_col_breaks
|
|
1965
|
+
col_breaks: @current_col_breaks,
|
|
1966
|
+
protected_ranges: @current_protected_ranges,
|
|
1967
|
+
cell_watches: @current_cell_watches
|
|
1629
1968
|
}
|
|
1630
1969
|
sheet_data[:cells] = @current_cells if @current_cells && !@current_cells.empty?
|
|
1631
1970
|
@current_cells = nil
|
|
@@ -1636,6 +1975,7 @@ module Xlsxrb
|
|
|
1636
1975
|
@current_row_writer.finish(
|
|
1637
1976
|
drawing_rid: info[:drawing_rid],
|
|
1638
1977
|
sheet_protection: @current_sheet_protection,
|
|
1978
|
+
protected_ranges: @current_protected_ranges.empty? ? nil : @current_protected_ranges,
|
|
1639
1979
|
auto_filter: @current_auto_filter,
|
|
1640
1980
|
filter_columns: @current_filter_columns.empty? ? nil : @current_filter_columns,
|
|
1641
1981
|
sort_state: @current_sort_state,
|
|
@@ -1649,6 +1989,7 @@ module Xlsxrb
|
|
|
1649
1989
|
header_footer: @current_header_footer.empty? ? nil : @current_header_footer,
|
|
1650
1990
|
row_breaks: @current_row_breaks.empty? ? nil : @current_row_breaks,
|
|
1651
1991
|
col_breaks: @current_col_breaks.empty? ? nil : @current_col_breaks,
|
|
1992
|
+
cell_watches: @current_cell_watches.empty? ? nil : @current_cell_watches,
|
|
1652
1993
|
tables: @current_tables.empty? ? nil : @current_tables,
|
|
1653
1994
|
table_start_rid: info[:table_start_rid],
|
|
1654
1995
|
legacy_drawing_rid: info[:vml_rid],
|