Class: Xlsxrb::StreamWriter

Inherits:
Object
  • Object
show all
Defined in:
lib/xlsxrb/stream_writer.rb,
sig/generated/xlsxrb/stream_writer.rbs

Overview

High-performance streaming writer that outputs XLSX files with O(1) constant memory.

Examples:

Streaming write using StreamWriter

Xlsxrb.write("output.xlsx") do |writer|
  writer.sheet("Sales") do |s|
    s.row(["Item", "Price"])
    s.row(["Coffee", 3.50])
  end
end

Defined Under Namespace

Classes: WorksheetProxy

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target, strict_excel_mode: true) ⇒ StreamWriter

Initializes a streaming writer context.

: (untyped target, ?strict_excel_mode: bool) -> void

Parameters:

  • target (String, IO, StringIO)

    Destination file path or writable IO stream.

  • strict_excel_mode (Boolean) (defaults to: true)

    Whether to enforce Microsoft Excel specification limits.

  • strict_excel_mode: (Boolean) (defaults to: true)


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/xlsxrb/stream_writer.rb', line 34

def initialize(target, strict_excel_mode: true)
  @target = target
  @strict_excel_mode = strict_excel_mode
  @io = target.is_a?(String) ? File.open(target, "wb") : target
  @owns_io = target.is_a?(String)
  @zip = Ooxml::ZipWriter.new(@io)
  @sst = []
  @sst_index = {}
  @sheets = []
  @current_sheet = nil
  @current_sheet_index = 0
  @current_row_index = 0
  @sheet_entry_started = false
  @current_row_writer = nil
  @current_columns = []
  @current_charts = []
  @current_hyperlinks = []
  @current_auto_filter = nil
  @current_filter_columns = {}
  @current_sort_state = nil
  @current_data_validations = []
  @current_conditional_formats = []
  @current_tables = []
  @current_pivot_tables = []
  @current_sparkline_groups = []
  @current_comments = []
  @current_merge_cells = []
  @current_freeze_pane = nil
  @current_split_pane = nil
  @current_selection = nil
  @current_page_margins = nil
  @current_page_setup = {}
  @current_header_footer = {}
  @current_print_options = {}
  @current_sheet_protection = nil
  @current_images = []
  @current_shapes = []
  @current_sheet_properties = {}
  @current_sheet_view = {}
  @current_row_breaks = []
  @current_col_breaks = []
  @current_cells = {}
  @styles = {} # { style_name => StyleBuilder }
  @style_writer = Ooxml::Writer.new
  @style_name_to_id = {}
  style("__xlsxrb_date", number_format: "yyyy-mm-dd")
  style("__xlsxrb_time", number_format: "yyyy-mm-dd hh:mm:ss")
  # Workbook-level settings
  @defined_names = []
  @core_properties = {}
  @app_properties = {}
  @custom_properties = []
  @workbook_protection = nil
  @workbook_properties = { update_links: "never" }
end

Instance Attribute Details

#current_sheetString? (readonly)

: String?

Returns:

  • (String, nil)

    Name of the currently active worksheet.



27
28
29
# File 'lib/xlsxrb/stream_writer.rb', line 27

def current_sheet
  @current_sheet
end

Instance Method Details

#absolute_range(range) ⇒ Object

: (untyped range) -> untyped

Parameters:

  • range (Object)

Returns:

  • (Object)


1606
1607
1608
1609
1610
1611
# File 'lib/xlsxrb/stream_writer.rb', line 1606

def absolute_range(range)
  # simplecov:disable
  # Edge case / untested delegation block
  range.gsub(/([A-Z]+)(\d+)/, '$\1$\2')
  # simplecov:enable
end

#app_property(name, value) ⇒ void

This method returns an undefined value.

Sets an app document property.

: (Symbol name, String | Integer | Time value) -> void

Parameters:

  • name (Symbol)

    Property name.

  • value (String, Integer, Time)

    Property value.



1499
1500
1501
1502
1503
1504
# File 'lib/xlsxrb/stream_writer.rb', line 1499

def app_property(name, value)
  # simplecov:disable
  # Edge case / untested delegation block
  @app_properties[name] = value
  # simplecov:enable
end

#auto_filter(range) ⇒ void

This method returns an undefined value.

Sets the auto-filter range on the active sheet.

: (String range) -> void

Parameters:

  • range (String)

    Cell range (e.g. "A1:E100").



1047
1048
1049
1050
# File 'lib/xlsxrb/stream_writer.rb', line 1047

def auto_filter(range)
  sheet if @current_sheet.nil?
  @current_auto_filter = range
end

#chart(**options) {|builder| ... } ⇒ void

This method returns an undefined value.

Adds a chart to the current worksheet.

: (**untyped options) ?{ (ChartBuilder) -> void } -> void

Parameters:

  • options (Hash)

    Chart options.

Yields:

  • (builder)

Yield Parameters:



1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
# File 'lib/xlsxrb/stream_writer.rb', line 1009

def chart(**options)
  sheet if @current_sheet.nil?

  if block_given?
    builder = ChartBuilder.new
    yield builder
    options = builder.options.merge(options)
  end

  @current_charts << options
end

#cleanup!void

This method returns an undefined value.

Explicitly cleans up any resources if not already closed.

: () -> void



1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
# File 'lib/xlsxrb/stream_writer.rb', line 1586

def cleanup!
  if @zip && !@zip.instance_variable_get(:@closed)
    begin
      @zip.close
    rescue StandardError
      nil
    end
  end
  return unless @owns_io && @io && !@io.closed?

  begin
    @io.close
  rescue StandardError
    nil
  end
end

#closevoid

This method returns an undefined value.

Finalizes and writes all streaming sheet contents to the destination target.

: () -> untyped



1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
# File 'lib/xlsxrb/stream_writer.rb', line 1543

def close
  raise ArgumentError, "Workbook must contain at least one sheet (Excel limitation)" if @strict_excel_mode && @sheets.empty? && @current_sheet.nil?

  Xlsxrb.in_span("StreamWriter#close") do
    flush_current_sheet

    styles_definition = {
      fonts: @style_writer.fonts.dup,
      fills: @style_writer.fills.dup,
      borders: @style_writer.borders.dup,
      xf_entries: @style_writer.xf_entries.dup,
      num_fmts: @style_writer.num_fmts.dup,
      dxfs: @dxfs || []
    }

    resolved_names = resolve_defined_names(@defined_names, @sheets)

    wb_writer = Ooxml::WorkbookWriter.new(
      sheets: @sheets,
      shared_strings: @sst,
      shared_strings_index: @sst_index,
      styles: styles_definition,
      defined_names: resolved_names.empty? ? nil : resolved_names,
      core_properties: @core_properties.empty? ? nil : @core_properties,
      app_properties: @app_properties.empty? ? nil : @app_properties,
      custom_properties: @custom_properties.empty? ? nil : @custom_properties,
      workbook_protection: @workbook_protection,
      workbook_properties: @workbook_properties
    )
    wb_writer.write_package_parts(@zip)

    @zip.close
    @io.close if @owns_io && !@io.closed?
  end
ensure
  cleanup!
end

#column(index, width: nil, hidden: false, custom_width: false, outline_level: nil) ⇒ void

This method returns an undefined value.

Sets column formatting and properties for one or multiple columns.

: (Integer | String | Range[Integer | String] | Array[Integer | String] index, ?width: Float | Integer | nil, ?hidden: bool, ?custom_width: bool, ?outline_level: Integer | nil) -> void

Parameters:

  • index (Integer, String, Range, Array)

    Column index (0-based) or letter ("A".."D").

  • width (Float, Integer, nil) (defaults to: nil)

    Column width in character units (0 - 255).

  • hidden (Boolean) (defaults to: false)

    Whether the column is hidden.

  • custom_width (Boolean) (defaults to: false)

    Whether custom width is set.

  • outline_level (Integer, nil) (defaults to: nil)

    Grouping/outline level.

  • width: (Float, Integer, nil) (defaults to: nil)
  • hidden: (Boolean) (defaults to: false)
  • custom_width: (Boolean) (defaults to: false)
  • outline_level: (Integer, nil) (defaults to: nil)


984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
# File 'lib/xlsxrb/stream_writer.rb', line 984

def column(index, width: nil, hidden: false, custom_width: false, outline_level: nil)
  raise ArgumentError, "Column width #{width} must be between 0 and 255 characters (Excel limitation)" if @strict_excel_mode && width && (width.negative? || width > 255)

  indices = case index
            when Range, Array
              index.map { |i| Elements::Cell.column_index(i) }
            else
              [Elements::Cell.column_index(index)]
            end

  sheet if @current_sheet.nil?

  indices.each do |idx|
    @current_columns << { index: idx, width: width, hidden: hidden, custom_width: custom_width || !width.nil?, outline_level: outline_level }
  end
end

#comment(cell, text, author: "Author") ⇒ void

This method returns an undefined value.

Adds a comment to a cell.

: (String | Integer cell, String text, ?author: ::String) -> void

Parameters:

  • cell (String, Integer)

    Cell coordinate (e.g. "A1").

  • text (String)

    Comment text.

  • author (String) (defaults to: "Author")

    Author name.

  • author: (::String) (defaults to: "Author")


1155
1156
1157
1158
# File 'lib/xlsxrb/stream_writer.rb', line 1155

def comment(cell, text, author: "Author")
  sheet if @current_sheet.nil?
  @current_comments << { cell: cell, text: text, author: author }
end

#conditional_format(sqref, **opts) ⇒ void

This method returns an undefined value.

Adds a conditional formatting rule.

: (untyped sqref, **untyped opts) -> void

Parameters:

  • sqref (String)

    Cell range.

  • opts (Hash)

    Rule options.



1096
1097
1098
1099
# File 'lib/xlsxrb/stream_writer.rb', line 1096

def conditional_format(sqref, **opts)
  sheet if @current_sheet.nil?
  @current_conditional_formats << opts.merge(sqref: sqref)
end

#core_property(name, value) ⇒ void

This method returns an undefined value.

Sets a core document metadata property.

: (Symbol name, String | Integer | Time value) -> void

Parameters:

  • name (Symbol)

    Property name.

  • value (String, Integer, Time)

    Property value.



1488
1489
1490
# File 'lib/xlsxrb/stream_writer.rb', line 1488

def core_property(name, value)
  @core_properties[name] = value
end

#custom_property(name, value, type: :string) ⇒ void

This method returns an undefined value.

Adds a custom document property.

: (String name, String | Integer | Float | bool | Time value, ?type: ::Symbol) -> void

Parameters:

  • name (String)

    Property name.

  • value (String, Integer, Float, Boolean, Time)

    Property value.

  • type (Symbol) (defaults to: :string)

    Value type.

  • type: (::Symbol) (defaults to: :string)


1531
1532
1533
1534
1535
1536
# File 'lib/xlsxrb/stream_writer.rb', line 1531

def custom_property(name, value, type: :string)
  # simplecov:disable
  # Edge case / untested delegation block
  @custom_properties << { name: name, value: value, type: type }
  # simplecov:enable
end

#defined_name(name, value, sheet: nil, hidden: false) ⇒ void

This method returns an undefined value.

Adds a defined name.

: (String name, String value, ?sheet: String?, ?hidden: bool) -> void

Parameters:

  • name (String)

    The defined name.

  • value (String)

    The formula or value expression.

  • sheet (String, nil) (defaults to: nil)

    Local sheet name.

  • hidden (Boolean) (defaults to: false)

    Whether the defined name is hidden.

  • sheet: (String, nil) (defaults to: nil)
  • hidden: (Boolean) (defaults to: false)


1427
1428
1429
1430
1431
1432
1433
1434
# File 'lib/xlsxrb/stream_writer.rb', line 1427

def defined_name(name, value, sheet: nil, hidden: false)
  entry = { name: name, value: value, hidden: hidden }
  if sheet
    # local_sheet_id will be resolved at close time
    entry[:local_sheet_name] = sheet
  end
  @defined_names << entry
end

#filter_column(col_id, filter) ⇒ void

This method returns an undefined value.

Sets filter criteria on a column in the auto-filter.

: (untyped col_id, untyped filter) -> untyped

Parameters:

  • col_id (Integer)

    0-based column index.

  • filter (Hash)

    Filter criteria.



1059
1060
1061
1062
# File 'lib/xlsxrb/stream_writer.rb', line 1059

def filter_column(col_id, filter)
  sheet if @current_sheet.nil?
  @current_filter_columns[col_id] = filter
end

#flush_current_sheetnil, untyped

: () -> (nil | untyped)

Returns:

  • (nil, untyped)


1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
# File 'lib/xlsxrb/stream_writer.rb', line 1628

def flush_current_sheet
  return unless @current_sheet

  # Normalize conditional formatting rules and record dxfs in @dxfs
  unless @current_conditional_formats.empty?
    @dxfs ||= []
    @current_conditional_formats = @current_conditional_formats.map do |rule|
      next rule if rule[:format_id]

      normalized = rule.dup
      font = {}
      font[:color] = normalized.delete(:font_color) if normalized.key?(:font_color)
      font[:bold] = normalized.delete(:bold) if normalized.key?(:bold)
      font[:italic] = normalized.delete(:italic) if normalized.key?(:italic)
      font[:underline] = normalized.delete(:underline) if normalized.key?(:underline)

      fill = {}
      if normalized.key?(:fill_color)
        fill[:pattern] = "solid"
        fill[:fg_color] = normalized.delete(:fill_color)
      end

      dxf = {}
      dxf[:font] = font unless font.empty?
      dxf[:fill] = fill unless fill.empty?
      next normalized if dxf.empty?

      dxf_id = @dxfs.index(dxf)
      unless dxf_id
        @dxfs << dxf
        dxf_id = @dxfs.size - 1
      end
      normalized[:format_id] = dxf_id
      normalized
    end
  end

  start_sheet_entry unless @sheet_entry_started

  sheet_data = {
    name: @current_sheet,
    columns: @current_columns,
    charts: @current_charts,
    hyperlinks: @current_hyperlinks,
    auto_filter: @current_auto_filter,
    filter_columns: @current_filter_columns,
    sort_state: @current_sort_state,
    data_validations: @current_data_validations,
    conditional_formats: @current_conditional_formats,
    tables: @current_tables,
    pivot_tables: @current_pivot_tables,
    sparkline_groups: @current_sparkline_groups,
    comments: @current_comments,
    merge_cells: @current_merge_cells,
    freeze_pane: @current_freeze_pane,
    split_pane: @current_split_pane,
    selection: @current_selection,
    page_margins: @current_page_margins,
    page_setup: @current_page_setup,
    header_footer: @current_header_footer,
    print_options: @current_print_options,
    sheet_protection: @current_sheet_protection,
    images: @current_images,
    shapes: @current_shapes,
    sheet_properties: @current_sheet_properties,
    sheet_view: @current_sheet_view,
    row_breaks: @current_row_breaks,
    col_breaks: @current_col_breaks
  }
  sheet_data[:cells] = @current_cells if @current_cells && !@current_cells.empty?
  @current_cells = nil

  temp_wb_writer = Ooxml::WorkbookWriter.new(sheets: [sheet_data])
  info = temp_wb_writer.prepare_sheet_auxiliary(sheet_data, @current_sheet_index - 1)

  @current_row_writer.finish(
    drawing_rid: info[:drawing_rid],
    sheet_protection: @current_sheet_protection,
    auto_filter: @current_auto_filter,
    filter_columns: @current_filter_columns.empty? ? nil : @current_filter_columns,
    sort_state: @current_sort_state,
    merge_cells: @current_merge_cells.empty? ? nil : @current_merge_cells,
    conditional_formats: @current_conditional_formats.empty? ? nil : @current_conditional_formats,
    data_validations: @current_data_validations.empty? ? nil : @current_data_validations,
    hyperlinks: info[:enriched_hyperlinks].empty? ? nil : info[:enriched_hyperlinks],
    print_options: @current_print_options.empty? ? nil : @current_print_options,
    page_margins: @current_page_margins,
    page_setup: @current_page_setup.empty? ? nil : @current_page_setup,
    header_footer: @current_header_footer.empty? ? nil : @current_header_footer,
    row_breaks: @current_row_breaks.empty? ? nil : @current_row_breaks,
    col_breaks: @current_col_breaks.empty? ? nil : @current_col_breaks,
    tables: @current_tables.empty? ? nil : @current_tables,
    table_start_rid: info[:table_start_rid],
    legacy_drawing_rid: info[:vml_rid],
    sparkline_groups: @current_sparkline_groups.empty? ? nil : @current_sparkline_groups
  )

  @zip.finish_entry
  @sheets << sheet_data

  @current_sheet = nil
  @current_row_writer = nil
  @sheet_entry_started = false
end

#freeze_pane(row: 0, col: 0) ⇒ void

This method returns an undefined value.

Freezes window panes at the given row and column.

: (?row: Integer, ?col: (Integer | String)) -> void

Parameters:

  • row (Integer) (defaults to: 0)

    Number of rows to freeze.

  • col (Integer, String) (defaults to: 0)

    Number of columns to freeze.

  • row: (Integer) (defaults to: 0)
  • col: (Integer, String) (defaults to: 0)


1220
1221
1222
1223
1224
# File 'lib/xlsxrb/stream_writer.rb', line 1220

def freeze_pane(row: 0, col: 0)
  col = Elements::Cell.column_index(col)
  sheet if @current_sheet.nil?
  @current_freeze_pane = { row: row, col: col }
end

This method returns an undefined value.

Configures headers and footers for printing.

: (**untyped opts) -> void

Parameters:

  • opts (Hash)

    Header/footer options.



1286
1287
1288
1289
# File 'lib/xlsxrb/stream_writer.rb', line 1286

def header_footer(**opts)
  sheet if @current_sheet.nil?
  @current_header_footer.merge!(opts)
end

This method returns an undefined value.

Adds a hyperlink on a cell.

: (String | Integer cell, ?String? url, ?display: String?, ?tooltip: String?, ?location: String?) -> void

Parameters:

  • cell (String, Integer)

    Cell coordinate (e.g. "A1").

  • url (String, nil) (defaults to: nil)

    Target URL.

  • display (String, nil) (defaults to: nil)

    Display text.

  • tooltip (String, nil) (defaults to: nil)

    Tooltip text.

  • location (String, nil) (defaults to: nil)

    Internal location.

  • display: (String, nil) (defaults to: nil)
  • tooltip: (String, nil) (defaults to: nil)
  • location: (String, nil) (defaults to: nil)


1031
1032
1033
1034
1035
1036
1037
1038
1039
# File 'lib/xlsxrb/stream_writer.rb', line 1031

def hyperlink(cell, url = nil, display: nil, tooltip: nil, location: nil)
  sheet if @current_sheet.nil?
  link = { cell: cell }
  link[:url] = url if url
  link[:display] = display if display
  link[:tooltip] = tooltip if tooltip
  link[:location] = location if location
  @current_hyperlinks << link
end

#image(file_data, ext: "png", from_col: 0, from_row: 0, to_col: 5, to_row: 10, **opts) ⇒ void

This method returns an undefined value.

Inserts an embedded image into the active sheet.

: (String file_data, ?ext: ::String, ?from_col: ::Integer, ?from_row: ::Integer, ?to_col: ::Integer, ?to_row: ::Integer, **untyped opts) -> void

Parameters:

  • file_data (String)

    Binary image data.

  • ext (String) (defaults to: "png")

    File extension ("png", "jpeg", etc.).

  • from_col (Integer) (defaults to: 0)

    Top-left starting column.

  • from_row (Integer) (defaults to: 0)

    Top-left starting row.

  • to_col (Integer) (defaults to: 5)

    Bottom-right ending column.

  • to_row (Integer) (defaults to: 10)

    Bottom-right ending row.

  • opts (Hash)

    Additional options.

  • ext: (::String) (defaults to: "png")
  • from_col: (::Integer) (defaults to: 0)
  • from_row: (::Integer) (defaults to: 0)
  • to_col: (::Integer) (defaults to: 5)
  • to_row: (::Integer) (defaults to: 10)


1336
1337
1338
1339
1340
1341
# File 'lib/xlsxrb/stream_writer.rb', line 1336

def image(file_data, ext: "png", from_col: 0, from_row: 0, to_col: 5, to_row: 10, **opts)
  sheet if @current_sheet.nil?
  img = { file_data: file_data, ext: ext, from_col: from_col, from_row: from_row, to_col: to_col, to_row: to_row }
  img.merge!(opts)
  @current_images << img
end

#internal_sheet_setup(name = nil) ⇒ void

This method returns an undefined value.

Internal: Start or switch to a named sheet (internal helper). : (?String? name) ?{ (WorksheetProxy) -> void } -> (WorksheetProxy | nil)

Parameters:

  • name (String, nil) (defaults to: nil)


822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
# File 'lib/xlsxrb/stream_writer.rb', line 822

def internal_sheet_setup(name = nil)
  flush_current_sheet
  name ||= "Sheet#{@sheets.size + 1}"
  @current_sheet = name
  @current_sheet_index = @sheets.size + 1
  @current_row_index = 0
  @sheet_entry_started = false
  @current_row_buffer = String.new(capacity: 65_536)
  @current_sheet_io = StringIO.new(@current_row_buffer)
  @current_row_writer = Ooxml::WorksheetWriter.new(@current_sheet_io)
  @current_row_writer.instance_variable_set(:@started, true)

  @current_columns = []
  @current_charts = []
  @current_hyperlinks = []
  @current_auto_filter = nil
  @current_filter_columns = {}
  @current_sort_state = nil
  @current_data_validations = []
  @current_conditional_formats = []
  @current_tables = []
  @current_pivot_tables = []
  @current_sparkline_groups = []
  @current_comments = []
  @current_merge_cells = []
  @current_freeze_pane = nil
  @current_split_pane = nil
  @current_selection = nil
  @current_page_margins = nil
  @current_page_setup = {}
  @current_header_footer = {}
  @current_print_options = {}
  @current_sheet_protection = nil
  @current_images = []
  @current_shapes = []
  @current_sheet_properties = {}
  @current_sheet_view = {}
  @current_row_breaks = []
  @current_col_breaks = []
  @current_cells = {}

  return unless block_given?

  # simplecov:disable
  # Edge case / untested delegation block
  yield self
  flush_current_sheet
  # simplecov:enable
end

#merge(range = nil, row: nil, col_start: nil, col_end: nil, row_start: nil, row_end: nil) ⇒ void

This method returns an undefined value.

Merges a range of cells into a single cell.

: (?(String | Hash[Symbol, Integer | String])? range, ?row: Integer?, ?col_start: (Integer | String)?, ?col_end: (Integer | String)?, ?row_start: Integer?, ?row_end: Integer?) -> void

Parameters:

  • range (String, Hash, nil) (defaults to: nil)

    Cell range (e.g. "A1:B2") or hash of coordinates.

  • row (Integer, nil) (defaults to: nil)

    Single row index.

  • col_start (Integer, String, nil) (defaults to: nil)

    Starting column.

  • col_end (Integer, String, nil) (defaults to: nil)

    Ending column.

  • row_start (Integer, nil) (defaults to: nil)

    Starting row index.

  • row_end (Integer, nil) (defaults to: nil)

    Ending row index.

  • row: (Integer, nil) (defaults to: nil)
  • col_start: (Integer, String, nil) (defaults to: nil)
  • col_end: (Integer, String, nil) (defaults to: nil)
  • row_start: (Integer, nil) (defaults to: nil)
  • row_end: (Integer, nil) (defaults to: nil)


1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
# File 'lib/xlsxrb/stream_writer.rb', line 1187

def merge(range = nil, row: nil, col_start: nil, col_end: nil, row_start: nil, row_end: nil)
  sheet if @current_sheet.nil?
  if range.is_a?(Hash)
    row = range[:row]
    row_start = range[:row_start]
    row_end = range[:row_end]
    col_start = range[:col_start]
    col_end = range[:col_end]
    range = nil
  end

  if range
    raise ArgumentError, "Invalid merge range format: '#{range}'. Expected format like 'A1:B2'." if @strict_excel_mode && !range.match?(/^[A-Za-z]{1,3}\d+(:[A-Za-z]{1,3}\d+)?$/)

    @current_merge_cells << range
  else
    r_start = row || row_start || 0
    r_end = row || row_end || 0
    c_start = Elements::Cell.column_index(col_start || 0)
    c_end = Elements::Cell.column_index(col_end || 0)
    start_ref = "#{Xlsxrb::Elements::Cell.column_letter(c_start)}#{r_start + 1}"
    end_ref = "#{Xlsxrb::Elements::Cell.column_letter(c_end)}#{r_end + 1}"
    @current_merge_cells << "#{start_ref}:#{end_ref}"
  end
end

#page_break_col(col_index) ⇒ void

This method returns an undefined value.

Inserts a vertical page break before a column.

: (Integer col_index) -> void

Parameters:

  • col_index (Integer, String)

    0-based column index or letter ("B").



1407
1408
1409
1410
1411
1412
1413
1414
# File 'lib/xlsxrb/stream_writer.rb', line 1407

def page_break_col(col_index)
  # simplecov:disable
  # Edge case / untested delegation block
  col_index = Elements::Cell.column_index(col_index)
  sheet if @current_sheet.nil?
  @current_col_breaks << col_index
  # simplecov:enable
end

#page_break_row(row_num) ⇒ void

This method returns an undefined value.

Inserts a horizontal page break before a row.

: (Integer row_num) -> void

Parameters:

  • row_num (Integer)

    1-based row number.



1393
1394
1395
1396
1397
1398
1399
# File 'lib/xlsxrb/stream_writer.rb', line 1393

def page_break_row(row_num)
  # simplecov:disable
  # Edge case / untested delegation block
  sheet if @current_sheet.nil?
  @current_row_breaks << row_num
  # simplecov:enable
end

#page_margins(left: nil, right: nil, top: nil, bottom: nil, header: nil, footer: nil) ⇒ void

This method returns an undefined value.

Sets page margins in inches for printing.

: (?left: Float?, ?right: Float?, ?top: Float?, ?bottom: Float?, ?header: Float?, ?footer: Float?) -> void

Parameters:

  • left (Float, nil) (defaults to: nil)

    Left margin.

  • right (Float, nil) (defaults to: nil)

    Right margin.

  • top (Float, nil) (defaults to: nil)

    Top margin.

  • bottom (Float, nil) (defaults to: nil)

    Bottom margin.

  • header (Float, nil) (defaults to: nil)

    Header margin.

  • footer (Float, nil) (defaults to: nil)

    Footer margin.

  • left: (Float, nil) (defaults to: nil)
  • right: (Float, nil) (defaults to: nil)
  • top: (Float, nil) (defaults to: nil)
  • bottom: (Float, nil) (defaults to: nil)
  • header: (Float, nil) (defaults to: nil)
  • footer: (Float, nil) (defaults to: nil)


1264
1265
1266
1267
# File 'lib/xlsxrb/stream_writer.rb', line 1264

def page_margins(left: nil, right: nil, top: nil, bottom: nil, header: nil, footer: nil)
  sheet if @current_sheet.nil?
  @current_page_margins = { left: left, right: right, top: top, bottom: bottom, header: header, footer: footer }.compact
end

#page_setup(**opts) ⇒ void

This method returns an undefined value.

Sets page setup configuration.

: (**untyped opts) -> void

Parameters:

  • opts (Hash)

    Page setup options (e.g. orientation: :landscape).



1275
1276
1277
1278
# File 'lib/xlsxrb/stream_writer.rb', line 1275

def page_setup(**opts)
  sheet if @current_sheet.nil?
  @current_page_setup.merge!(opts)
end

#pivot_table(source_ref, row_fields:, data_fields:, col_fields: [], dest_ref: "E1", name: nil, field_names: nil, items: nil) ⇒ void

This method returns an undefined value.

Adds a Pivot Table.

: (untyped source_ref, row_fields: untyped, data_fields: untyped, ?col_fields: untyped, ?dest_ref: untyped, ?name: untyped, ?field_names: untyped, ?items: untyped, **untyped opts) -> void

Parameters:

  • source_ref (String)

    Source data range.

  • row_fields (Array<Integer>)

    0-based field indices for rows.

  • data_fields (Array<Hash>)

    Data fields.

  • col_fields (Array<Integer>) (defaults to: [])

    0-based field indices for columns.

  • dest_ref (String) (defaults to: "E1")

    Top-left destination cell (default: "E1").

  • name (String, nil) (defaults to: nil)

    Pivot table name.

  • field_names (Array<String>, nil) (defaults to: nil)

    Override field names.

  • items (Array, nil) (defaults to: nil)

    Items configuration.

  • opts (Hash)

    Additional options.

  • row_fields: (Object)
  • data_fields: (Object)
  • col_fields: (Object) (defaults to: [])
  • dest_ref: (Object) (defaults to: "E1")
  • name: (Object) (defaults to: nil)
  • field_names: (Object) (defaults to: nil)
  • items: (Object) (defaults to: nil)


1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
# File 'lib/xlsxrb/stream_writer.rb', line 1136

def pivot_table(source_ref, row_fields:, data_fields:, col_fields: [], dest_ref: "E1", name: nil, field_names: nil, items: nil)
  sheet if @current_sheet.nil?
  @current_pivot_tables ||= []
  @current_pivot_tables << {
    source_ref: source_ref, row_fields: row_fields,
    data_fields: data_fields, col_fields: col_fields,
    dest_ref: dest_ref, name: name,
    field_names: field_names, items: items
  }
end

This method returns an undefined value.

Sets the print area for the current or named sheet.

: (String range, ?sheet: String?) -> void

Parameters:

  • range (String)

    Cell range (e.g. "A1:G50").

  • sheet (String, nil) (defaults to: nil)

    Target sheet name.

  • sheet: (String, nil) (defaults to: nil)


1443
1444
1445
1446
1447
1448
1449
1450
1451
# File 'lib/xlsxrb/stream_writer.rb', line 1443

def print_area(range, sheet: nil)
  # simplecov:disable
  # Edge case / untested delegation block
  sheet_name = sheet || @current_sheet || "Sheet1"
  value = "'#{sheet_name}'!#{absolute_range(range)}"
  @defined_names.reject! { |dn| dn[:name] == "_xlnm.Print_Area" && dn[:local_sheet_name] == sheet_name }
  defined_name("_xlnm.Print_Area", value, sheet: sheet_name)
  # simplecov:enable
end

This method returns an undefined value.

Sets a print option (e.g. grid_lines: true).

: (Symbol name, untyped value) -> void

Parameters:

  • name (Symbol)

    Option name.

  • value (Object)

    Option value.



1298
1299
1300
1301
# File 'lib/xlsxrb/stream_writer.rb', line 1298

def print_options(name, value)
  sheet if @current_sheet.nil?
  @current_print_options[name] = value
end

This method returns an undefined value.

Sets print titles for the current or named sheet.

: (?rows: String?, ?cols: String?, ?sheet: String?) -> void

Parameters:

  • rows (String, nil) (defaults to: nil)

    Repeating row range (e.g. "1:2").

  • cols (String, nil) (defaults to: nil)

    Repeating column range (e.g. "A:B").

  • sheet (String, nil) (defaults to: nil)

    Target sheet name.

  • rows: (String, nil) (defaults to: nil)
  • cols: (String, nil) (defaults to: nil)
  • sheet: (String, nil) (defaults to: nil)


1461
1462
1463
1464
1465
1466
1467
1468
1469
# File 'lib/xlsxrb/stream_writer.rb', line 1461

def print_titles(rows: nil, cols: nil, sheet: nil)
  sheet_name = sheet || @current_sheet || "Sheet1"
  parts = []
  parts << "'#{sheet_name}'!$#{cols.sub(":", ":$")}" if cols
  parts << "'#{sheet_name}'!$#{rows.sub(":", ":$")}" if rows
  value = parts.join(",")
  @defined_names.reject! { |dn| dn[:name] == "_xlnm.Print_Titles" && dn[:local_sheet_name] == sheet_name }
  defined_name("_xlnm.Print_Titles", value, sheet: sheet_name)
end

#properties(core: nil, app: nil, custom: nil) ⇒ void

This method returns an undefined value.

Sets multiple core and/or app properties.

: (?core: Hash[Symbol, String | Integer | Time]?, ?app: Hash[Symbol, String | Integer | Time]?, ?custom: Hash[String | Symbol, untyped]?) -> void

Parameters:

  • core (Hash, nil) (defaults to: nil)

    Core properties.

  • app (Hash, nil) (defaults to: nil)

    App properties.

  • custom (Hash, nil) (defaults to: nil)

    Custom properties.

  • core: (Hash[Symbol, String | Integer | Time], nil) (defaults to: nil)
  • app: (Hash[Symbol, String | Integer | Time], nil) (defaults to: nil)
  • custom: (Hash[String | Symbol, untyped], nil) (defaults to: nil)


1514
1515
1516
1517
1518
1519
1520
1521
# File 'lib/xlsxrb/stream_writer.rb', line 1514

def properties(core: nil, app: nil, custom: nil)
  # simplecov:disable
  # Edge case / untested delegation block
  core&.each { |k, v| core_property(k, v) }
  app&.each { |k, v| app_property(k, v) }
  custom&.each { |k, v| custom_property(k.to_s, v) }
  # simplecov:enable
end

#protect_sheet(**opts) ⇒ void

This method returns an undefined value.

Sets sheet-level protection with optional password hashing.

: (**untyped opts) -> void

Parameters:

  • opts (Hash)

    Protection options.



1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
# File 'lib/xlsxrb/stream_writer.rb', line 1309

def protect_sheet(**opts)
  sheet if @current_sheet.nil?
  normalized = opts.dup
  plain_password = normalized[:password]
  needs_hash = plain_password.is_a?(String) && !plain_password.empty? &&
               normalized[:algorithm_name].nil? && normalized[:hash_value].nil? &&
               normalized[:salt_value].nil? && normalized[:spin_count].nil? &&
               !plain_password.match?(/\A[0-9A-Fa-f]{4}\z/)
  if needs_hash
    normalized.delete(:password)
    normalized.merge!(Xlsxrb::Ooxml::Utils.hash_password(plain_password))
  end
  @current_sheet_protection = normalized
end

#protect_workbook(**opts) ⇒ void

This method returns an undefined value.

Sets workbook protection.

: (**String | Integer | bool | nil opts) -> void

Parameters:

  • opts (Hash)

    Protection options.



1477
1478
1479
# File 'lib/xlsxrb/stream_writer.rb', line 1477

def protect_workbook(**opts)
  @workbook_protection = opts
end

#resolve_defined_names(names, sheets) ⇒ Object

: (untyped names, untyped sheets) -> untyped

Parameters:

  • names (Object)
  • sheets (Object)

Returns:

  • (Object)


1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
# File 'lib/xlsxrb/stream_writer.rb', line 1614

def resolve_defined_names(names, sheets)
  sheet_names = sheets.map { |s| s[:name] }
  names.map do |dn|
    resolved = dn.dup
    if dn[:local_sheet_name]
      idx = sheet_names.index(dn[:local_sheet_name])
      resolved[:local_sheet_id] = idx if idx
      resolved.delete(:local_sheet_name)
    end
    resolved
  end
end

#row(values, styles: nil, height: nil, hidden: false, custom_height: false, outline_level: nil) ⇒ void Also known as: <<

This method returns an undefined value.

Appends a row of values to the active sheet.

: (Array | Hash[untyped, untyped] values, ?styles: untyped, ?height: Float | Integer | nil, ?hidden: bool, ?custom_height: bool, ?outline_level: Integer | nil) -> void

Parameters:

  • values (Array<Object>, Hash)

    The cell values.

  • styles (String, Symbol, Array, Hash, nil) (defaults to: nil)

    Style names or inline style definitions.

  • height (Float, Integer, nil) (defaults to: nil)

    The row height in points (0 - 409).

  • hidden (Boolean) (defaults to: false)

    Whether the row is hidden.

  • custom_height (Boolean) (defaults to: false)

    Whether custom row height is set.

  • outline_level (Integer, nil) (defaults to: nil)

    Grouping/outline level (0 - 7).

  • styles: (Object) (defaults to: nil)
  • height: (Float, Integer, nil) (defaults to: nil)
  • hidden: (Boolean) (defaults to: false)
  • custom_height: (Boolean) (defaults to: false)
  • outline_level: (Integer, nil) (defaults to: nil)


909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
# File 'lib/xlsxrb/stream_writer.rb', line 909

def row(values, styles: nil, height: nil, hidden: false, custom_height: false, outline_level: nil)
  sheet if @current_sheet.nil?

  row_index = @current_row_index
  # See: https://support.microsoft.com/en-us/office/excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3
  if @strict_excel_mode
    raise ArgumentError, "Row index #{row_index} exceeds Excel limit of 1,048,576 rows" if row_index >= 1_048_576
    raise ArgumentError, "Row height #{height} must be between 0 and 409 points (Excel limitation)" if height && (height.negative? || height > 409)
  end
  @current_row_index += 1

  if values.is_a?(Hash)
    max_col = values.keys.map { |k| Elements::Cell.column_index(k) }.max || -1
    cells_array = Array.new(max_col + 1)
    values.each do |k, v|
      idx = Elements::Cell.column_index(k)
      cells_array[idx] = v
    end
    values = cells_array
  end

  if styles.is_a?(Hash)
    expanded_styles = {}
    styles.each do |k, v|
      if k.is_a?(Range) || k.is_a?(Array)
        k.each { |idx| expanded_styles[Elements::Cell.column_index(idx)] = v }
      else
        expanded_styles[Elements::Cell.column_index(k)] = v
      end
    end
    max_col_style = expanded_styles.keys.max || -1
    styles_array = Array.new(max_col_style + 1)
    expanded_styles.each do |idx, v|
      styles_array[idx] = v
    end
    styles = styles_array
  end

  if @current_charts && !@current_charts.empty?
    @current_cells ||= {}
    row_num = row_index + 1
    values.each_with_index do |val, col_idx|
      next if val.nil?

      addr = "#{Elements::Cell.column_letter(col_idx)}#{row_num}"
      @current_cells[addr] = val
    end
  end

  raise ArgumentError, "Row contains #{values.length} columns, exceeding Excel limit of 16_384 columns" if @strict_excel_mode && values.length > 16_384

  attrs = nil
  if height || hidden || outline_level
    attrs = {}
    attrs[:height] = height if height
    attrs[:hidden] = true if hidden
    attrs[:custom_height] = custom_height || !height.nil?
    attrs[:outline_level] = outline_level if outline_level
  end

  @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)
  start_sheet_entry if !@sheet_entry_started && @current_row_buffer.bytesize >= 65_536
end

#select_cell(active_cell, sqref: nil, pane: nil) ⇒ void

This method returns an undefined value.

Sets the active cell selection on the current sheet.

: (String active_cell, ?sqref: String?, ?pane: (String | Symbol)?) -> void

Parameters:

  • active_cell (String)

    Active cell reference (e.g. "A1").

  • sqref (String, nil) (defaults to: nil)

    Selection range.

  • pane (String, Symbol, nil) (defaults to: nil)

    Target pane.

  • sqref: (String, nil) (defaults to: nil)
  • pane: (String, Symbol, nil) (defaults to: nil)


1247
1248
1249
1250
1251
# File 'lib/xlsxrb/stream_writer.rb', line 1247

def select_cell(active_cell, sqref: nil, pane: nil)
  sheet if @current_sheet.nil?
  @current_selection = { active_cell: active_cell, sqref: sqref || active_cell }
  @current_selection[:pane] = pane if pane
end

#shape(preset: "rect", text: nil, from_col: 0, from_row: 0, to_col: 5, to_row: 5, **opts) ⇒ void

This method returns an undefined value.

Inserts a drawing shape.

: (**untyped opts) -> void

Parameters:

  • preset (String) (defaults to: "rect")

    Preset shape name.

  • text (String, nil) (defaults to: nil)

    Label text.

  • from_col (Integer) (defaults to: 0)

    Top-left column.

  • from_row (Integer) (defaults to: 0)

    Top-left row.

  • to_col (Integer) (defaults to: 5)

    Bottom-right column.

  • to_row (Integer) (defaults to: 5)

    Bottom-right row.

  • opts (Hash)

    Additional options.



1355
1356
1357
1358
1359
1360
1361
# File 'lib/xlsxrb/stream_writer.rb', line 1355

def shape(preset: "rect", text: nil, from_col: 0, from_row: 0, to_col: 5, to_row: 5, **opts)
  sheet if @current_sheet.nil?
  shape = { preset: preset, text: text, from_col: from_col, from_row: from_row, to_col: to_col, to_row: to_row }
  shape[:name] = opts.delete(:name) || "Shape #{@current_shapes.size + 1}"
  shape.merge!(opts)
  @current_shapes << shape
end

#sheet(name = nil, **opts) {|sheet_proxy| ... } ⇒ String

Adds a new sheet to the workbook and starts streaming rows into it.

: (?String? name, **untyped opts) ?{ (WorksheetProxy) -> void } -> untyped

Parameters:

  • name (String, nil) (defaults to: nil)

    Sheet name (max 31 characters).

  • opts (Hash)

    Sheet-level configuration.

Yields:

  • (sheet_proxy)

Yield Parameters:

Returns:

  • (String)

    The sheet name.



807
808
809
810
811
812
813
814
815
816
817
818
# File 'lib/xlsxrb/stream_writer.rb', line 807

def sheet(name = nil, **opts)
  name ||= "Sheet#{@sheets.size + 1}"
  raise ArgumentError, "Sheet name '#{name}' must be <= 31 characters (Excel limitation)" if @strict_excel_mode && name.length > 31
  raise ArgumentError, "Sheet name '#{name}' contains invalid characters (ECMA-376 OOXML specification)" if name.match?(%r{[\[\]*?/\\]})
  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)

  internal_sheet_setup(name)
  opts.each { |k, v| sheet_properties(k, v) }

  yield WorksheetProxy.new(self, @current_sheet) if block_given?
  @current_sheet
end

#sheet_properties(name, value) ⇒ void

This method returns an undefined value.

Sets a sheet-level property (e.g. tab_color: "FF0000").

: (Symbol name, untyped value) -> void

Parameters:

  • name (Symbol)

    Property name.

  • value (Object)

    Property value.



1370
1371
1372
1373
# File 'lib/xlsxrb/stream_writer.rb', line 1370

def sheet_properties(name, value)
  sheet if @current_sheet.nil?
  @current_sheet_properties[name] = value
end

#sheet_view(name, value) ⇒ void

This method returns an undefined value.

Sets a sheet view property (e.g. zoom_scale: 120).

: (Symbol name, untyped value) -> void

Parameters:

  • name (Symbol)

    View property name.

  • value (Object)

    View property value.



1382
1383
1384
1385
# File 'lib/xlsxrb/stream_writer.rb', line 1382

def sheet_view(name, value)
  sheet if @current_sheet.nil?
  @current_sheet_view[name] = value
end

#sort_state(ref, sort_conditions, **opts) ⇒ void

This method returns an undefined value.

Configures column sort state on the active sheet.

: (untyped ref, untyped sort_conditions, **untyped opts) -> untyped

Parameters:

  • ref (String)

    The sorted range.

  • sort_conditions (Array<Hash>)

    Sort conditions.

  • opts (Hash)

    Additional options.



1072
1073
1074
1075
# File 'lib/xlsxrb/stream_writer.rb', line 1072

def sort_state(ref, sort_conditions, **opts)
  sheet if @current_sheet.nil?
  @current_sort_state = { ref: ref, sort_conditions: sort_conditions }.merge(opts)
end

#sparkline_group(sparklines:, type: nil, **opts) ⇒ void

This method returns an undefined value.

Adds a sparkline group.

: (sparklines: untyped, ?type: untyped, **untyped opts) -> void

Parameters:

  • sparklines (Array<Hash>)

    Sparkline definitions.

  • type (String, nil) (defaults to: nil)

    "line", "column", or "stacked".

  • opts (Hash)

    Additional options.

  • sparklines: (Object)
  • type: (Object) (defaults to: nil)


1168
1169
1170
1171
1172
1173
1174
# File 'lib/xlsxrb/stream_writer.rb', line 1168

def sparkline_group(sparklines:, type: nil, **opts)
  sheet if @current_sheet.nil?
  group = { sparklines: sparklines }
  group[:type] = type if type
  group.merge!(opts)
  @current_sparkline_groups << group
end

#split_pane(x_split: 0, y_split: 0, top_left_cell: nil) ⇒ void

This method returns an undefined value.

Splits window panes without freezing.

: (?x_split: ::Integer, ?y_split: ::Integer, ?top_left_cell: String?) -> void

Parameters:

  • x_split (Integer) (defaults to: 0)

    Horizontal split in points.

  • y_split (Integer) (defaults to: 0)

    Vertical split in points.

  • top_left_cell (String, nil) (defaults to: nil)

    Top-left cell reference in bottom-right pane.

  • x_split: (::Integer) (defaults to: 0)
  • y_split: (::Integer) (defaults to: 0)
  • top_left_cell: (String, nil) (defaults to: nil)


1234
1235
1236
1237
# File 'lib/xlsxrb/stream_writer.rb', line 1234

def split_pane(x_split: 0, y_split: 0, top_left_cell: nil)
  sheet if @current_sheet.nil?
  @current_split_pane = { x_split: x_split, y_split: y_split, top_left_cell: top_left_cell }
end

#start_sheet_entryObject

Returns:

  • (Object)


872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
# File 'lib/xlsxrb/stream_writer.rb', line 872

def start_sheet_entry
  return if @sheet_entry_started

  @sheet_entry_started = true
  @zip.start_entry("xl/worksheets/sheet#{@current_sheet_index}.xml")
  zip_io = Ooxml::WorkbookWriter::ZipEntryIO.new(@zip)

  row_buf = @current_row_writer.instance_variable_get(:@row_buffer)
  if row_buf && !row_buf.empty?
    @current_sheet_io.write(row_buf)
    row_buf.clear
  end

  @current_row_writer = Ooxml::WorksheetWriter.new(zip_io)
  @current_row_writer.start(
    columns: @current_columns,
    sheet_properties: @current_sheet_properties.empty? ? nil : @current_sheet_properties,
    freeze_pane: @current_freeze_pane,
    split_pane: @current_split_pane,
    selection: @current_selection,
    sheet_view: @current_sheet_view.empty? ? nil : @current_sheet_view
  )
  @zip.write_data(@current_row_buffer) unless @current_row_buffer.empty?
  @current_row_buffer.clear
end

#style(name, **opts) {|style_builder| ... } ⇒ StyleBuilder

Defines or configures a named cell style.

: (String | Symbol name, **untyped opts) ?{ (StyleBuilder) -> void } -> StyleBuilder

Parameters:

  • name (String, Symbol)

    The name of the style.

  • opts (Hash)

    Style options (e.g. bold: true, fill_color: "FF0000").

Yields:

  • (style_builder)

Yield Parameters:

Returns:



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/xlsxrb/stream_writer.rb', line 112

def style(name, **opts)
  style_name = name.to_s
  style_builder = StyleBuilder.new(style_name)
  style_builder.apply_options!(**opts) unless opts.empty?
  yield style_builder if block_given?
  @styles[style_name] = style_builder

  # Register immediately with low-level style writer
  @style_name_to_id[style_name] = style_builder.register_with(@style_writer)

  style_builder
end

#table(ref, columns:, name: nil, display_name: nil, style: nil, **opts) ⇒ void

This method returns an undefined value.

Adds an Excel Table (ListObject).

: (untyped ref, columns: untyped, ?name: untyped, ?display_name: untyped, ?style: untyped, **untyped opts) -> void

Parameters:

  • ref (String)

    Table range.

  • columns (Array<String>)

    Column names.

  • name (String, nil) (defaults to: nil)

    Table name.

  • display_name (String, nil) (defaults to: nil)

    Display name.

  • style (String, nil) (defaults to: nil)

    Table style.

  • opts (Hash)

    Additional options.

  • columns: (Object)
  • name: (Object) (defaults to: nil)
  • display_name: (Object) (defaults to: nil)
  • style: (Object) (defaults to: nil)


1112
1113
1114
1115
1116
1117
1118
1119
1120
# File 'lib/xlsxrb/stream_writer.rb', line 1112

def table(ref, columns:, name: nil, display_name: nil, style: nil, **opts)
  sheet if @current_sheet.nil?
  tbl = { ref: ref, columns: columns }
  tbl[:name] = name if name
  tbl[:display_name] = display_name if display_name
  tbl[:style] = style if style
  tbl.merge!(opts)
  @current_tables << tbl
end

#validate_data(sqref, **opts) ⇒ void

This method returns an undefined value.

Adds a data validation rule.

: (untyped sqref, **untyped opts) -> void

Parameters:

  • sqref (String)

    Cell range.

  • opts (Hash)

    Validation options.



1084
1085
1086
1087
# File 'lib/xlsxrb/stream_writer.rb', line 1084

def validate_data(sqref, **opts)
  sheet if @current_sheet.nil?
  @current_data_validations << opts.merge(sqref: sqref)
end

#workbook_property(name, value) ⇒ void

Note:

SECURITY WARNING: If you set :update_links to anything other than "never", you may expose end-users to malicious external reference vulnerabilities (e.g., CSV/DDE Injection) when they open the generated Excel file. Ensure you fully trust the exported data.

This method returns an undefined value.

Sets a workbook property.

: (Symbol name, String | Integer | bool value) -> void

Parameters:

  • name (Symbol)

    Property name (e.g. :update_links).

  • value (String, Integer, Boolean)

    Property value.



100
101
102
# File 'lib/xlsxrb/stream_writer.rb', line 100

def workbook_property(name, value)
  @workbook_properties[name] = value
end