Class: Xlsxrb::WorkbookBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/xlsxrb.rb

Overview

DSL context for Xlsxrb.build.

Instance Method Summary collapse

Constructor Details

#initialize(strict_excel_mode: true) ⇒ WorkbookBuilder

: (?strict_excel_mode: bool) -> void



524
525
526
527
528
529
530
531
532
533
534
# File 'lib/xlsxrb.rb', line 524

def initialize(strict_excel_mode: true)
  @strict_excel_mode = strict_excel_mode
  @sheets = []
  @sheet_builders = [] # Keep track of sheet builders for style processing
  @defined_names = []
  @core_properties = {}
  @app_properties = {}
  @custom_properties = []
  @workbook_protection = nil
  @workbook_properties = { update_links: "never" }
end

Instance Method Details

#app_property(name, value) ⇒ void

This method returns an undefined value.

Set an app document property.

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

Parameters:

  • name (Symbol)

    The property name.

  • value (String, Integer, Time)

    The property value.



651
652
653
# File 'lib/xlsxrb.rb', line 651

def app_property(name, value)
  @app_properties[name] = value
end

#buildObject

: () -> Elements::Workbook

Raises:

  • (ArgumentError)


681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
# File 'lib/xlsxrb.rb', line 681

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

  # Process styles from all sheets and collect style definitions
  processed_sheets, styles_definition = process_styles(@sheets)

  # Store workbook-level metadata in unmapped_data
  wb_meta = {}
  wb_meta[:defined_names] = resolve_defined_names(@defined_names, processed_sheets) unless @defined_names.empty?
  wb_meta[:core_properties] = @core_properties unless @core_properties.empty?
  wb_meta[:app_properties] = @app_properties unless @app_properties.empty?
  wb_meta[:custom_properties] = @custom_properties unless @custom_properties.empty?
  wb_meta[:workbook_protection] = @workbook_protection if @workbook_protection
  wb_meta[:workbook_properties] = @workbook_properties unless @workbook_properties.empty?

  Elements::Workbook.new(
    sheets: processed_sheets,
    styles: styles_definition,
    unmapped_data: wb_meta.empty? ? {} : { facade: wb_meta }
  )
end

#core_property(name, value) ⇒ void

This method returns an undefined value.

Set a core document property.

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

Parameters:

  • name (Symbol)

    The property name.

  • value (String, Integer, Time)

    The property value.



640
641
642
# File 'lib/xlsxrb.rb', line 640

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

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

This method returns an undefined value.

Add a custom document property.

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

Parameters:

  • name (String)

    The property name.

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

    The property value.

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

    The type of property (:string, :number, :bool, :date).



675
676
677
# File 'lib/xlsxrb.rb', line 675

def custom_property(name, value, type: :string)
  @custom_properties << { name: name, value: value, type: type }
end

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

This method returns an undefined value.

Add a defined name.

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

Parameters:

  • name (String)

    The defined name.

  • value (String)

    The formula or value.

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

    Local sheet name.

  • hidden (Boolean) (defaults to: false)

    Whether the defined name is hidden.



585
586
587
588
589
# File 'lib/xlsxrb.rb', line 585

def defined_name(name, value, sheet: nil, hidden: false)
  entry = { name: name, value: value, hidden: hidden }
  entry[:local_sheet_name] = sheet if sheet
  @defined_names << entry
end

This method returns an undefined value.

Set the print area for a sheet.

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

Parameters:

  • range (String)

    The range string (e.g. "A1:B10").

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

    The sheet name.



598
599
600
601
602
603
# File 'lib/xlsxrb.rb', line 598

def print_area(range, sheet: nil)
  sheet_name = sheet || @sheets.last&.name || "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)
end

This method returns an undefined value.

Set print titles for a sheet.

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

Parameters:

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

    Rows to repeat (e.g. "1:2").

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

    Columns to repeat (e.g. "A:B").

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

    The sheet name.



613
614
615
616
617
618
619
620
621
# File 'lib/xlsxrb.rb', line 613

def print_titles(rows: nil, cols: nil, sheet: nil)
  sheet_name = sheet || @sheets.last&.name || "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) ⇒ void

This method returns an undefined value.

Set multiple core and/or app properties.

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

Parameters:

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

    Core properties.

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

    App properties.



662
663
664
665
# File 'lib/xlsxrb.rb', line 662

def properties(core: nil, app: nil)
  core&.each { |k, v| core_property(k, v) }
  app&.each { |k, v| app_property(k, v) }
end

#protect_workbook(**opts) ⇒ void

This method returns an undefined value.

Set workbook protection.

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

Parameters:

  • opts (Hash)

    Protection options.



629
630
631
# File 'lib/xlsxrb.rb', line 629

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

#sheet(name = nil, **opts) {|sheet_builder| ... } ⇒ void Also known as: []

This method returns an undefined value.

Add a new sheet.

: (?String? name, **String | Integer | bool | nil opts) ?{ (WorksheetBuilder) -> void } -> void

Parameters:

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

    The name of the sheet.

  • opts (Hash)

    Sheet properties.

Yields:

  • (sheet_builder)

Yield Parameters:

Raises:

  • (ArgumentError)


560
561
562
563
564
565
566
567
568
569
570
571
# File 'lib/xlsxrb.rb', line 560

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)

  sheet_builder = WorksheetBuilder.new(name, strict_excel_mode: @strict_excel_mode)
  opts.each { |k, v| sheet_builder.sheet_properties(k, v) }
  yield sheet_builder if block_given?
  @sheet_builders << sheet_builder
  @sheets << sheet_builder.build
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.

Set a workbook property.

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

Parameters:

  • name (Symbol)

    The property name (e.g. :update_links).

  • value (String, Integer, Boolean)

    The property value.



547
548
549
# File 'lib/xlsxrb.rb', line 547

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