Class: Xlsxrb::Elements::Worksheet

Inherits:
Data
  • Object
show all
Includes:
Enumerable
Defined in:
lib/xlsxrb/elements/worksheet.rb,
sig/generated/xlsxrb/elements/worksheet.rbs

Overview

Represents a single worksheet in a workbook.

Examples:

Access cells and rows

sheet = workbook.sheet(0)
cell = sheet["A1"]
sheet.each_row { |row| puts row.to_a.inspect }

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, rows: [], columns: [], charts: [], unmapped_data: {}, errors: nil) ⇒ Worksheet

Returns a new instance of Worksheet.

Signature:

  • (name: String, ?rows: Array[Elements::Row], ?columns: Array[Elements::Column], ?charts: Array[Hash[Symbol, untyped]], ?unmapped_data: Hash[untyped, untyped], ?errors: Array[String]?) -> void

Parameters:

  • name (String)

    The worksheet name (max 31 characters).

  • rows (Array<Elements::Row>) (defaults to: [])

    Rows in the sheet.

  • columns (Array<Elements::Column>) (defaults to: [])

    Column definitions.

  • charts (Array<Hash>) (defaults to: [])

    Charts in the sheet.

  • unmapped_data (Hash) (defaults to: {})

    Additional metadata for round-tripping.

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

    Validation errors.



25
26
27
28
29
# File 'lib/xlsxrb/elements/worksheet.rb', line 25

def initialize(name:, rows: [], columns: [], charts: [], unmapped_data: {}, errors: nil)
  computed_errors = errors || self.class.validate(name, rows)
  super(name: name, rows: rows.freeze, columns: columns.freeze, charts: charts.freeze,
        unmapped_data: unmapped_data, errors: computed_errors.freeze)
end

Instance Attribute Details

#chartsObject (readonly)

Returns the value of attribute charts

Returns:

  • (Object)

    the current value of charts



15
16
17
# File 'lib/xlsxrb/elements/worksheet.rb', line 15

def charts
  @charts
end

#columnsObject (readonly)

Returns the value of attribute columns

Returns:

  • (Object)

    the current value of columns



15
16
17
# File 'lib/xlsxrb/elements/worksheet.rb', line 15

def columns
  @columns
end

#errorsObject (readonly)

Returns the value of attribute errors

Returns:

  • (Object)

    the current value of errors



15
16
17
# File 'lib/xlsxrb/elements/worksheet.rb', line 15

def errors
  @errors
end

#nameObject (readonly)

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



15
16
17
# File 'lib/xlsxrb/elements/worksheet.rb', line 15

def name
  @name
end

#rowsObject (readonly)

Returns the value of attribute rows

Returns:

  • (Object)

    the current value of rows



15
16
17
# File 'lib/xlsxrb/elements/worksheet.rb', line 15

def rows
  @rows
end

#unmapped_dataObject (readonly)

Returns the value of attribute unmapped_data

Returns:

  • (Object)

    the current value of unmapped_data



15
16
17
# File 'lib/xlsxrb/elements/worksheet.rb', line 15

def unmapped_data
  @unmapped_data
end

Class Method Details

.members[ :name, :rows, :columns, :charts, :unmapped_data, :errors ]

Returns:

  • ([ :name, :rows, :columns, :charts, :unmapped_data, :errors ])


29
# File 'sig/generated/xlsxrb/elements/worksheet.rbs', line 29

def self.members: () -> [ :name, :rows, :columns, :charts, :unmapped_data, :errors ]

.new(name, rows, columns, charts, unmapped_data, errors) ⇒ instance .new(name:, rows:, columns:, charts:, unmapped_data:, errors:) ⇒ instance

Overloads:

  • .new(name, rows, columns, charts, unmapped_data, errors) ⇒ instance

    Parameters:

    • name (Object)
    • rows (Object)
    • columns (Object)
    • charts (Object)
    • unmapped_data (Object)
    • errors (Object)

    Returns:

    • (instance)
  • .new(name:, rows:, columns:, charts:, unmapped_data:, errors:) ⇒ instance

    Parameters:

    • name: (Object)
    • rows: (Object)
    • columns: (Object)
    • charts: (Object)
    • unmapped_data: (Object)
    • errors: (Object)

    Returns:

    • (instance)


26
27
# File 'sig/generated/xlsxrb/elements/worksheet.rbs', line 26

def self.new: (untyped name, untyped rows, untyped columns, untyped charts, untyped unmapped_data, untyped errors) -> instance
| (name: untyped, rows: untyped, columns: untyped, charts: untyped, unmapped_data: untyped, errors: untyped) -> instance

.validate(name, rows) ⇒ Array<String>

Validates worksheet name and rows against OOXML limits.

Signature:

  • (untyped name, untyped rows) -> Array[String]

Parameters:

Returns:

  • (Array<String>)

    List of errors.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/xlsxrb/elements/worksheet.rb', line 236

def self.validate(name, rows)
  errs = []
  if name.nil? || !name.is_a?(String) || name.empty?
    errs << "worksheet name must be a non-empty String (got #{name.inspect})"
  else
    errs << "worksheet name cannot exceed 31 characters (got #{name.size})" if name.size > 31
    errs << "worksheet name cannot contain \\, /, ?, *, [, or ]" if name.match?(%r{[\\/?*\[\]]})
  end
  errs << "rows must be an Array (got #{rows.class})" unless rows.is_a?(Array)
  if rows.is_a?(Array)
    indices = rows.map(&:index)
    if indices.uniq.size != indices.size
      dups = indices.select { |i| indices.count(i) > 1 }.uniq
      errs << "duplicate row index: #{dups.join(", ")} — row indices within a sheet must be unique"
    end
  end
  errs
end

Instance Method Details

#[](ref) ⇒ Elements::Cell?

Access a cell by its Excel-style reference (e.g. "A1").

Examples:

sheet["A1"] #=> #<Elements::Cell value="Hello">

Signature:

  • (String | Symbol ref) -> Elements::Cell?

Parameters:

  • ref (String, Symbol)

    Cell reference (e.g. "A1" or :A1).

Returns:



65
66
67
# File 'lib/xlsxrb/elements/worksheet.rb', line 65

def [](ref)
  cells_hash[ref.to_s.upcase]
end

#cell_value(ref) ⇒ Object?

Returns the raw cell value at the given Excel-style reference (e.g. "A1").

Examples:

sheet.cell_value("A1") #=> "Sales Report"

Signature:

  • (String ref) -> untyped

Parameters:

  • ref (String)

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

Returns:

  • (Object, nil)


171
172
173
174
175
176
177
178
179
180
181
# File 'lib/xlsxrb/elements/worksheet.rb', line 171

def cell_value(ref)
  parsed = Cell.parse_ref(ref)
  return nil unless parsed

  row_idx, col_idx = parsed
  row = row_at(row_idx)
  return nil unless row

  cell = row.cell_at(col_idx)
  cell&.value
end

#cellsArray<Elements::Cell>

Returns all cells ordered by row and column index.

Signature:

  • () -> Array[Elements::Cell]

Returns:



51
52
53
54
# File 'lib/xlsxrb/elements/worksheet.rb', line 51

def cells
  # Ensure ordered traversal
  cells_hash.values.sort_by { |c| [c.row_index, c.column_index] }
end

#cells_hashHash<String, Elements::Cell>

Returns a Hash mapping Excel cell references (e.g. "A1") to Cell objects.

Signature:

  • () -> Hash[String, Elements::Cell]

Returns:



35
36
37
38
39
40
41
42
43
44
# File 'lib/xlsxrb/elements/worksheet.rb', line 35

def cells_hash
  h = {}
  rows.each do |r|
    r.cells.each do |c|
      ref = "#{Cell.column_letter(c.column_index)}#{c.row_index + 1}"
      h[ref] = c
    end
  end
  h
end

#each {|cell| ... } ⇒ Enumerator, void

Iterate over cells in the worksheet.

Examples:

sheet.each do |cell|
  puts cell.value
end

Signature:

  • () { (Elements::Cell) -> void } -> void

  • | () -> Enumerator[Elements::Cell, void]

Yields:

  • (cell)

Yield Parameters:

Returns:

  • (Enumerator, void)


82
83
84
85
86
# File 'lib/xlsxrb/elements/worksheet.rb', line 82

def each(&)
  return to_enum(:each) unless block_given?

  cells.each(&)
end

#each_cell {|cell| ... } ⇒ Enumerator, void

Iterate over cells in the worksheet.

Examples:

sheet.each_cell do |cell|
  puts "#{cell.ref}: #{cell.value}"
end

Signature:

  • () { (Elements::Cell) -> void } -> void

  • | () -> Enumerator[Elements::Cell, void]

Yields:

  • (cell)

Yield Parameters:

Returns:

  • (Enumerator, void)


101
102
103
104
105
# File 'lib/xlsxrb/elements/worksheet.rb', line 101

def each_cell(&)
  return to_enum(:each_cell) unless block_given?

  cells.each(&)
end

#each_row {|row| ... } ⇒ Enumerator, void

Iterate over rows in the worksheet.

Examples:

sheet.each_row do |row|
  puts "Row #{row.index}: #{row.to_a.inspect}"
end

Signature:

  • () { (Elements::Row) -> void } -> void

  • | () -> Enumerator[Elements::Row, void]

Yields:

  • (row)

Yield Parameters:

Returns:

  • (Enumerator, void)


120
121
122
123
124
# File 'lib/xlsxrb/elements/worksheet.rb', line 120

def each_row(&)
  return to_enum(:each_row) unless block_given?

  rows.each(&)
end

#first_rowElements::Row?

Returns the first row in the sheet, or nil.

Signature:

  • () -> Elements::Row?

Returns:



149
150
151
# File 'lib/xlsxrb/elements/worksheet.rb', line 149

def first_row
  rows.min_by(&:index)
end

#last_rowElements::Row?

Returns the last row in the sheet, or nil.

Signature:

  • () -> Elements::Row?

Returns:



158
159
160
# File 'lib/xlsxrb/elements/worksheet.rb', line 158

def last_row
  rows.max_by(&:index)
end

#members[ :name, :rows, :columns, :charts, :unmapped_data, :errors ]

Returns:

  • ([ :name, :rows, :columns, :charts, :unmapped_data, :errors ])


31
# File 'sig/generated/xlsxrb/elements/worksheet.rbs', line 31

def members: () -> [ :name, :rows, :columns, :charts, :unmapped_data, :errors ]

#row_at(index) ⇒ Elements::Row?

Returns the row at the given 0-based index, or nil.

Signature:

  • (Integer index) -> Elements::Row?

Parameters:

  • index (Integer)

    0-based row index.

Returns:



140
141
142
# File 'lib/xlsxrb/elements/worksheet.rb', line 140

def row_at(index)
  rows.find { |r| r.index == index }
end

#update_cell(ref, value: nil, style_index: nil, formula: nil) ⇒ Worksheet

Returns a new Worksheet with the specified cell updated.

Examples:

new_sheet = sheet.update_cell("B1", value: "Updated")

Signature:

  • (String ref, ?value: untyped, ?style_index: Integer | String | nil, ?formula: Elements::Formula?) -> Elements::Worksheet

Parameters:

  • ref (String)

    The cell reference (e.g. "B1").

  • value (Object) (defaults to: nil)

    The new cell value.

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

    Optional new style index.

  • formula (Elements::Formula, nil) (defaults to: nil)

    Optional new formula.

Returns:

Raises:

  • (ArgumentError)


195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/xlsxrb/elements/worksheet.rb', line 195

def update_cell(ref, value: nil, style_index: nil, formula: nil)
  parsed = Cell.parse_ref(ref)
  raise ArgumentError, "invalid cell reference: #{ref}" unless parsed

  row_idx, col_idx = parsed
  existing_row = row_at(row_idx)

  if existing_row
    existing_cell = existing_row.cell_at(col_idx)
    new_cell = if existing_cell
                 existing_cell.with(
                   value: value || existing_cell.value,
                   style_index: style_index || existing_cell.style_index,
                   formula: formula || existing_cell.formula
                 )
               else
                 Cell.new(row_index: row_idx, column_index: col_idx, value: value, style_index: style_index, formula: formula)
               end

    # Replace cell in the existing row
    new_cells = existing_row.cells.reject { |c| c.column_index == col_idx }
    new_cells << new_cell
    new_cells.sort_by!(&:column_index)

    new_row = existing_row.with(cells: new_cells)
    new_rows = rows.map { |r| r.index == row_idx ? new_row : r }
  else
    # Row doesn't exist, create it
    new_cell = Cell.new(row_index: row_idx, column_index: col_idx, value: value, style_index: style_index, formula: formula)
    new_row = Row.new(index: row_idx, cells: [new_cell])
    new_rows = (rows + [new_row]).sort_by!(&:index)
  end
  with(rows: new_rows)
end

#valid?Boolean

Returns whether the worksheet is valid according to OOXML specifications.

Signature:

  • () -> bool

Returns:

  • (Boolean)


130
131
132
# File 'lib/xlsxrb/elements/worksheet.rb', line 130

def valid?
  errors.empty?
end