Module: Rbxl

Defined in:
lib/rbxl.rb,
lib/rbxl/row.rb,
lib/rbxl/cell.rb,
lib/rbxl/errors.rb,
lib/rbxl/version.rb,
lib/rbxl/empty_cell.rb,
lib/rbxl/editable_cell.rb,
lib/rbxl/read_only_cell.rb,
lib/rbxl/write_only_cell.rb,
lib/rbxl/editable_workbook.rb,
lib/rbxl/editable_worksheet.rb,
lib/rbxl/read_only_workbook.rb,
lib/rbxl/read_only_worksheet.rb,
lib/rbxl/write_only_workbook.rb,
lib/rbxl/write_only_worksheet.rb,
lib/rbxl/shared_strings_loader.rb,
ext/rbxl_native/native.c

Overview

Minimal, memory-friendly XLSX reader/writer inspired by openpyxl.

Rbxl exposes three explicit, non-overlapping modes, each picked up by Rbxl.open / Rbxl.new:

The API is intentionally narrow so that memory usage stays predictable for large workbooks. Neither mode materializes the full workbook in memory; reads pull rows from the underlying XML one at a time, and writes accumulate only the rows added before WriteOnlyWorkbook#save.

Reading

require "rbxl"

book = Rbxl.open("report.xlsx")
sheet = book.sheet("Report")
sheet.each_row(values_only: true) { |values| p values }
book.close

Pass date_conversion: true to return Date/Time objects for numeric cells that carry a date numFmt style.

Writing

require "rbxl"

book  = Rbxl.new
sheet = book.add_sheet("Report")
sheet << ["id", "name", "score"]
sheet << [1, "alice", 100]
book.save("report.xlsx")

Native extension

Requiring "rbxl/native" after "rbxl" swaps the hot worksheet XML paths for a libxml2-backed C implementation with the same observable behavior. See the README for build requirements.

Defined Under Namespace

Modules: Native, SharedStringsLoader Classes: Cell, CellValueError, ClosedWorkbookError, EditableCell, EditableCellTypeError, EditableWorkbook, EditableWorksheet, EmptyCell, Error, ReadOnlyCell, ReadOnlyWorkbook, ReadOnlyWorksheet, Row, SharedStringsTooLargeError, SheetNotFoundError, UnsizedWorksheetError, UnsupportedFormatError, WorkbookAlreadySavedError, WorkbookFormatError, WorksheetFormatError, WorksheetTooLargeError, WriteOnlyCell, WriteOnlyWorkbook, WriteOnlyWorksheet

Constant Summary collapse

VERSION =

Gem version string, tracked with semantic versioning.

"1.4.0"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.max_shared_string_bytesInteger?

Returns configured shared-strings byte cap.

Returns:

  • (Integer, nil)

    configured shared-strings byte cap



92
93
94
# File 'lib/rbxl.rb', line 92

def max_shared_string_bytes
  @max_shared_string_bytes
end

.max_shared_stringsInteger?

Returns configured shared-strings count cap.

Returns:

  • (Integer, nil)

    configured shared-strings count cap



89
90
91
# File 'lib/rbxl.rb', line 89

def max_shared_strings
  @max_shared_strings
end

.max_worksheet_bytesInteger?

Returns per-worksheet streaming byte cap.

Returns:

  • (Integer, nil)

    per-worksheet streaming byte cap



95
96
97
# File 'lib/rbxl.rb', line 95

def max_worksheet_bytes
  @max_worksheet_bytes
end

Instance Attribute Details

#coordinateString (readonly)

Returns Excel-style coordinate such as “A1”.

Returns:

  • (String)

    Excel-style coordinate such as “A1”



12
# File 'lib/rbxl/read_only_cell.rb', line 12

ReadOnlyCell = Data.define(:coordinate, :value)

#valueObject? (readonly)

Returns decoded Ruby value (String, Numeric, Boolean, or nil).

Returns:

  • (Object, nil)

    decoded Ruby value (String, Numeric, Boolean, or nil)



12
# File 'lib/rbxl/read_only_cell.rb', line 12

ReadOnlyCell = Data.define(:coordinate, :value)

Class Method Details

.new(write_only: true) ⇒ Rbxl::WriteOnlyWorkbook

Creates a new workbook in write-only mode.

The write_only keyword defaults to true and exists to mark the save-once, append-only contract explicitly. Passing write_only: false raises NotImplementedError.

Parameters:

  • write_only (Boolean) (defaults to: true)

    retained for call-site clarity; must be true

Returns:

Raises:

  • (NotImplementedError)

    if write_only is not true



188
189
190
191
192
# File 'lib/rbxl.rb', line 188

def new(write_only: true)
  raise NotImplementedError, "read/write mode is not supported; pass write_only: true" unless write_only

  WriteOnlyWorkbook.new
end

.open(path, read_only: true, edit: false, streaming: false, date_conversion: false) {|book| ... } ⇒ Rbxl::ReadOnlyWorkbook, ...

Opens an existing workbook.

By default opens in read-only row-by-row mode and returns a ReadOnlyWorkbook. Pass edit: true to open in read-modify-save mode and receive a EditableWorkbook instead. The two modes are wired up here at the module level so call sites pick a mode by keyword without juggling backend classes directly.

The read_only keyword defaults to true and exists to mark the intent explicitly at the call site. Passing read_only: false without also passing edit: true raises NotImplementedError — there is no promiscuous read/write mode that mixes streaming reads with surgical writes.

When a block is given, the workbook is yielded and automatically closed when the block returns (or raises), mirroring the File.open and Zip::File.open idiom:

Rbxl.open("report.xlsx") do |book|
  book.sheet("Report").each_row(values_only: true) { |row| p row }
end

Rbxl.open("template.xlsx", edit: true) do |book|
  book.sheet("Sheet1")["B5"].value = "Acme Inc."
  book.save
end

With streaming: true, the native backend (when loaded) feeds worksheet XML to the parser in chunks pulled from the ZIP input stream instead of materializing the entire worksheet as one Ruby string. This keeps peak memory roughly independent of worksheet size and lets max_worksheet_bytes bound how much is inflated. Streaming mode is the same API and output shape — only the inflation strategy differs — and typically pays back a few percent of throughput on small sheets in exchange for the flat memory profile.

With date_conversion: true, numeric cells whose style points at a date/time numFmt (built-in ids 14–22, 27–36, 45–47, 50–58, or any custom format code containing a date/time token) are returned as Date, Time, or DateTime instead of a raw serial Float. The flag is off by default to preserve byte-for-byte behavior and skip the styles.xml parse for workbooks that don’t need it; enabling it disables the native fast path and routes reads through the Ruby worksheet parser.

streaming: and date_conversion: are read-mode options and are rejected when paired with edit: true, since the editable backend does not run worksheets through the streaming parser.

Parameters:

  • path (String, #to_path)

    filesystem path to an .xlsx file

  • read_only (Boolean) (defaults to: true)

    retained for call-site clarity; must be true unless edit: true is also passed

  • edit (Boolean) (defaults to: false)

    open in read-modify-save mode; returns an EditableWorkbook

  • streaming (Boolean) (defaults to: false)

    feed worksheet XML to the native parser in chunks instead of fully inflating the entry in advance. Ignored when the native extension is not loaded.

  • date_conversion (Boolean) (defaults to: false)

    convert numeric cells backed by a date/time numFmt to Date / Time / DateTime

Yield Parameters:

Returns:

Raises:

  • (NotImplementedError)

    if read_only is false without edit: true

  • (ArgumentError)

    if edit: true is paired with read-only options



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/rbxl.rb', line 163

def open(path, read_only: true, edit: false, streaming: false, date_conversion: false, &block)
  if edit
    if streaming || date_conversion
      raise ArgumentError,
            "edit: true is incompatible with streaming:/date_conversion:; " \
            "those options apply to the read-only mode"
    end

    return EditableWorkbook.open(path, &block)
  end

  raise NotImplementedError, "read/write mode is not supported; pass read_only: true or edit: true" unless read_only

  ReadOnlyWorkbook.open(path, streaming: streaming, date_conversion: date_conversion, &block)
end