Module: Xlsxrb
- Defined in:
- lib/xlsxrb.rb,
lib/xlsxrb/ooxml.rb,
lib/xlsxrb/version.rb,
lib/xlsxrb/elements.rb,
lib/xlsxrb/ooxml/utils.rb,
lib/xlsxrb/elements/row.rb,
lib/xlsxrb/ooxml/reader.rb,
lib/xlsxrb/ooxml/writer.rb,
lib/xlsxrb/elements/cell.rb,
lib/xlsxrb/style_builder.rb,
lib/xlsxrb/elements/types.rb,
lib/xlsxrb/elements/column.rb,
lib/xlsxrb/ooxml/xml_parser.rb,
lib/xlsxrb/ooxml/zip_reader.rb,
lib/xlsxrb/ooxml/zip_writer.rb,
lib/xlsxrb/elements/workbook.rb,
lib/xlsxrb/ooxml/xml_builder.rb,
lib/xlsxrb/elements/worksheet.rb,
lib/xlsxrb/ooxml/styles_parser.rb,
lib/xlsxrb/ooxml/zip_generator.rb,
lib/xlsxrb/ooxml/workbook_parser.rb,
lib/xlsxrb/ooxml/workbook_writer.rb,
lib/xlsxrb/ooxml/worksheet_parser.rb,
lib/xlsxrb/ooxml/worksheet_writer.rb,
lib/xlsxrb/ooxml/shared_strings_parser.rb,
sig/generated/xlsxrb/ooxml.rbs,
sig/generated/xlsxrb/version.rbs,
sig/generated/xlsxrb/elements.rbs,
sig/generated/xlsxrb/style_builder.rbs
Overview
rbs_inline: enabled
Defined Under Namespace
Modules: Elements, Ooxml Classes: ChartBuilder, Error, ParseError, StreamSheet, StreamWriter, StyleBuilder, ValidationError, WorkbookBuilder, WorksheetBuilder, ZipError
Constant Summary collapse
- TRACER =
OpenTelemetry.tracer_provider.tracer("xlsxrb", Xlsxrb::VERSION)
- VERSION =
"0.1.5"
Class Method Summary collapse
-
.build(strict_excel_mode: true) {|builder| ... } ⇒ Elements::Workbook
Builds an Elements::Workbook in memory using a DSL.
-
.build_raw_cell_from_value(row_index, col_index, value, sst, sst_index) ⇒ Object
Builds a raw cell hash from a value for streaming writes.
-
.foreach(source) {|sheet| ... } ⇒ Enumerator, void
Streaming read: yields StreamSheet objects one at a time for each sheet.
-
.formula(expression, cached_value: nil) ⇒ Elements::Formula
Creates a Formula object for use in row values.
-
.generate(target, strict_excel_mode: true) {|stream_writer| ... } ⇒ void
Streaming write: yields a StreamWriter context for building XLSX on-the-fly.
- .in_span(name, attributes: nil) ⇒ Object
-
.modify(source, target = nil) {|workbook| ... } ⇒ void
Modifies an existing XLSX file.
-
.read(source) ⇒ Elements::Workbook
Reads an XLSX file into an Elements::Workbook.
-
.rich_text(*runs, text: nil, **font_props) ⇒ Elements::RichText
Helper to easily create RichText objects.
-
.write(target, workbook) ⇒ void
Writes an Elements::Workbook to an XLSX file.
Class Method Details
.build(strict_excel_mode: true) {|builder| ... } ⇒ Elements::Workbook
Builds an Elements::Workbook in memory using a DSL.
: (?strict_excel_mode: bool) ?{ (WorkbookBuilder) -> void } -> Elements::Workbook
511 512 513 514 515 516 517 518 519 |
# File 'lib/xlsxrb.rb', line 511 def self.build(strict_excel_mode: true) raise Error, "block is required" unless block_given? Xlsxrb.in_span("Xlsxrb.build") do builder = WorkbookBuilder.new(strict_excel_mode: strict_excel_mode) yield builder builder.build end end |
.build_raw_cell_from_value(row_index, col_index, value, sst, sst_index) ⇒ Object
Builds a raw cell hash from a value for streaming writes. : (untyped row_index, untyped col_index, untyped value, untyped sst, untyped sst_index) -> untyped
2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 |
# File 'lib/xlsxrb.rb', line 2675 def self.build_raw_cell_from_value(row_index, col_index, value, sst, sst_index) ref = "#{Elements::Cell.column_letter(col_index)}#{row_index + 1}" result = { ref: ref } case value when Elements::Formula result[:formula] = value.expression result[:formula_ca] = true if value.calculate_always result[:value] = value.cached_value if value.cached_value when String idx = sst_index[value] ||= begin sst << value sst.size - 1 end result[:value] = idx result[:type] = "s" when true, false result[:value] = value result[:type] = "b" when Integer, Float result[:value] = value when Date result[:value] = Xlsxrb::Ooxml::Utils.date_to_serial(value) when Time result[:value] = Xlsxrb::Ooxml::Utils.datetime_to_serial(value) when NilClass # empty cell end result end |
.foreach(source) {|sheet| ... } ⇒ Enumerator, void
Streaming read: yields StreamSheet objects one at a time for each sheet.
: (String | IO source) ?{ (StreamSheet) -> void } -> (Enumerator[StreamSheet, void] | void)
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
# File 'lib/xlsxrb.rb', line 457 def self.foreach(source) return enum_for(:foreach, source) unless block_given? attributes = source.is_a?(String) ? { "filepath" => source } : {} Xlsxrb.in_span("Xlsxrb.foreach", attributes: attributes) do entries = Ooxml::ZipReader.open(source, &:read_all) shared_strings = Ooxml::SharedStringsParser.parse(entries["xl/sharedStrings.xml"]) workbook_sheets = Ooxml::WorkbookParser.parse(entries["xl/workbook.xml"]) rels = Ooxml::RelationshipsParser.parse(entries["xl/_rels/workbook.xml.rels"]) workbook_sheets.each do |sheet_info| target = rels[sheet_info[:r_id]] next unless target sheet_path = target.start_with?("/") ? target.delete_prefix("/") : "xl/#{target}" sheet_xml = entries[sheet_path] next if sheet_xml.nil? || sheet_xml.empty? yield StreamSheet.new(sheet_info[:name], sheet_xml, shared_strings) end end end |
.formula(expression, cached_value: nil) ⇒ Elements::Formula
Creates a Formula object for use in row values.
: (String expression, ?cached_value: String | Numeric | bool | nil) -> Elements::Formula
299 300 301 302 303 304 305 |
# File 'lib/xlsxrb.rb', line 299 def self.formula(expression, cached_value: nil) Elements::Formula.new( expression: expression, cached_value: cached_value, calculate_always: cached_value.nil? || nil ) end |
.generate(target, strict_excel_mode: true) {|stream_writer| ... } ⇒ void
This method returns an undefined value.
Streaming write: yields a StreamWriter context for building XLSX on-the-fly.
: (String | IO target, ?strict_excel_mode: bool) ?{ (StreamWriter) -> void } -> void
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/xlsxrb.rb', line 488 def self.generate(target, strict_excel_mode: true) raise Error, "target is required" if target.nil? raise Error, "block is required" unless block_given? attributes = target.is_a?(String) ? { "filepath" => target } : {} Xlsxrb.in_span("Xlsxrb.generate", attributes: attributes) do stream_writer = StreamWriter.new(target, strict_excel_mode: strict_excel_mode) begin yield stream_writer stream_writer.close ensure stream_writer.cleanup! end end end |
.in_span(name, attributes: nil) ⇒ Object
44 45 46 47 48 49 50 51 52 |
# File 'lib/xlsxrb.rb', line 44 def self.in_span(name, attributes: nil, &) if defined?(Ractor) && Ractor.current != Ractor.main yield elsif attributes TRACER.in_span(name, attributes: attributes, &) else TRACER.in_span(name, &) end end |
.modify(source, target = nil) {|workbook| ... } ⇒ void
This method returns an undefined value.
Modifies an existing XLSX file.
Reads the workbook, passes it to the block, and writes the result.
The block receives an Elements::Workbook and must return a modified one (e.g. via update_sheet).
If no target is given, the source is overwritten.
: (String | IO source, ?(String | IO)? target) ?{ (Elements::Workbook) -> Elements::Workbook } -> void
414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/xlsxrb.rb', line 414 def self.modify(source, target = nil) raise Error, "source is required" if source.nil? raise Error, "block is required" unless block_given? workbook = read(source) result_workbook = yield workbook result_workbook = workbook unless result_workbook.is_a?(Elements::Workbook) write_target = target || source write(write_target, result_workbook) end |
.read(source) ⇒ Elements::Workbook
Reads an XLSX file into an Elements::Workbook.
: (String | IO source) -> Elements::Workbook
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/xlsxrb.rb', line 313 def self.read(source) attributes = source.is_a?(String) ? { "filepath" => source } : {} Xlsxrb.in_span("Xlsxrb.read", attributes: attributes) do entries = Ooxml::ZipReader.open(source, &:read_all) shared_strings = Ooxml::SharedStringsParser.parse(entries["xl/sharedStrings.xml"]) styles = Ooxml::StylesParser.parse(entries["xl/styles.xml"]) workbook_sheets = Ooxml::WorkbookParser.parse(entries["xl/workbook.xml"]) rels = Ooxml::RelationshipsParser.parse(entries["xl/_rels/workbook.xml.rels"]) sheets = workbook_sheets.map do |sheet_info| target = rels[sheet_info[:r_id]] next nil unless target sheet_path = target.start_with?("/") ? target.delete_prefix("/") : "xl/#{target}" sheet_xml = entries[sheet_path] build_worksheet(sheet_info[:name], sheet_xml, shared_strings, styles) end.compact Elements::Workbook.new(sheets: sheets, shared_strings: shared_strings, styles: styles) end end |
.rich_text(*runs, text: nil, **font_props) ⇒ Elements::RichText
Helper to easily create RichText objects.
Supports both Xlsxrb.rich_text({ text: "A" }, { text: "B" })
and Xlsxrb.rich_text(text: "Hi", bold: true)
: (*Hash[Symbol, String | Integer | bool | nil] runs, ?text: String?, **String | Integer | bool | nil font_props) -> Elements::RichText
64 65 66 67 |
# File 'lib/xlsxrb.rb', line 64 def self.rich_text(*runs, text: nil, **font_props) runs = [{ text: text, font: font_props }] if text Elements::RichText.new(runs: runs) end |
.write(target, workbook) ⇒ void
This method returns an undefined value.
Writes an Elements::Workbook to an XLSX file.
: (String | IO target, Elements::Workbook workbook) -> void
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
# File 'lib/xlsxrb.rb', line 342 def self.write(target, workbook) raise Error, "target is required" if target.nil? raise Error, "workbook must be an Elements::Workbook" unless workbook.is_a?(Elements::Workbook) attributes = target.is_a?(String) ? { "filepath" => target } : {} Xlsxrb.in_span("Xlsxrb.write", attributes: attributes) do sst = [] sst_index = {} # Collect shared strings and build index without allocating new Hashes sheet_data = workbook.sheets.map do |ws| ws.rows.each do |row| row.cells.each do |cell| val = cell.value if (val.is_a?(String) || val.is_a?(Elements::RichText)) && !sst_index.key?(val) sst << val sst_index[val] = sst.size - 1 end end end columns = ws.columns.map do |col| { index: col.index, width: col.width, hidden: col.hidden, custom_width: col.custom_width, outline_level: col.outline_level } end sd = { name: ws.name, rows: ws.rows, columns: columns } sd[:charts] = ws.charts unless ws.charts.empty? # Extract facade metadata from unmapped_data facade = ws.unmapped_data[:facade] facade&.each { |key, val| sd[key] = val } sd end # Extract workbook-level facade metadata wb_facade = workbook.unmapped_data[:facade] || {} Ooxml::WorkbookWriter.write( target, sheets: sheet_data, shared_strings: sst, shared_strings_index: sst_index, styles: workbook.styles, defined_names: wb_facade[:defined_names], core_properties: wb_facade[:core_properties], app_properties: wb_facade[:app_properties], custom_properties: wb_facade[:custom_properties], workbook_protection: wb_facade[:workbook_protection], workbook_properties: wb_facade[:workbook_properties] ) end end |