zaxcel 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.rspec +4 -0
 - data/.rubocop.yml +9 -0
 - data/CHANGELOG.md +29 -0
 - data/CONTRIBUTING.md +110 -0
 - data/LICENSE +22 -0
 - data/QUICK_START.md +187 -0
 - data/README.md +372 -0
 - data/Rakefile +18 -0
 - data/SETUP.md +178 -0
 - data/lib/enumerable.rb +47 -0
 - data/lib/zaxcel/README.md +37 -0
 - data/lib/zaxcel/arithmetic.rb +88 -0
 - data/lib/zaxcel/binary_expression.rb +74 -0
 - data/lib/zaxcel/binary_expressions/addition.rb +36 -0
 - data/lib/zaxcel/binary_expressions/division.rb +24 -0
 - data/lib/zaxcel/binary_expressions/multiplication.rb +24 -0
 - data/lib/zaxcel/binary_expressions/subtraction.rb +41 -0
 - data/lib/zaxcel/binary_expressions.rb +38 -0
 - data/lib/zaxcel/cell.rb +141 -0
 - data/lib/zaxcel/cell_formula.rb +16 -0
 - data/lib/zaxcel/column.rb +142 -0
 - data/lib/zaxcel/document.rb +136 -0
 - data/lib/zaxcel/function.rb +6 -0
 - data/lib/zaxcel/functions/abs.rb +18 -0
 - data/lib/zaxcel/functions/and.rb +23 -0
 - data/lib/zaxcel/functions/average.rb +17 -0
 - data/lib/zaxcel/functions/choose.rb +20 -0
 - data/lib/zaxcel/functions/concatenate.rb +20 -0
 - data/lib/zaxcel/functions/if.rb +38 -0
 - data/lib/zaxcel/functions/if_error.rb +25 -0
 - data/lib/zaxcel/functions/index.rb +20 -0
 - data/lib/zaxcel/functions/len.rb +16 -0
 - data/lib/zaxcel/functions/match/match_type.rb +13 -0
 - data/lib/zaxcel/functions/match.rb +27 -0
 - data/lib/zaxcel/functions/max.rb +17 -0
 - data/lib/zaxcel/functions/min.rb +17 -0
 - data/lib/zaxcel/functions/negate.rb +26 -0
 - data/lib/zaxcel/functions/or.rb +23 -0
 - data/lib/zaxcel/functions/round.rb +20 -0
 - data/lib/zaxcel/functions/sum.rb +18 -0
 - data/lib/zaxcel/functions/sum_if.rb +20 -0
 - data/lib/zaxcel/functions/sum_ifs.rb +34 -0
 - data/lib/zaxcel/functions/sum_product.rb +18 -0
 - data/lib/zaxcel/functions/text.rb +17 -0
 - data/lib/zaxcel/functions/unique.rb +23 -0
 - data/lib/zaxcel/functions/x_lookup.rb +28 -0
 - data/lib/zaxcel/functions/xirr.rb +27 -0
 - data/lib/zaxcel/functions.rb +169 -0
 - data/lib/zaxcel/if_builder.rb +22 -0
 - data/lib/zaxcel/lang.rb +23 -0
 - data/lib/zaxcel/reference.rb +28 -0
 - data/lib/zaxcel/references/cell.rb +42 -0
 - data/lib/zaxcel/references/column.rb +49 -0
 - data/lib/zaxcel/references/range.rb +35 -0
 - data/lib/zaxcel/references/row.rb +34 -0
 - data/lib/zaxcel/references.rb +5 -0
 - data/lib/zaxcel/roundable.rb +14 -0
 - data/lib/zaxcel/row.rb +93 -0
 - data/lib/zaxcel/sheet.rb +425 -0
 - data/lib/zaxcel/sorbet/enumerizable_enum.rb +50 -0
 - data/lib/zaxcel/version.rb +6 -0
 - data/lib/zaxcel.rb +73 -0
 - data/zaxcel.gemspec +73 -0
 - metadata +266 -0
 
    
        data/lib/zaxcel/sheet.rb
    ADDED
    
    | 
         @@ -0,0 +1,425 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
            # typed: strict
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class Zaxcel::Sheet
         
     | 
| 
      
 5 
     | 
    
         
            +
              extend T::Sig
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              HEADER_ROW_KEY = :header_row
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              sig { returns(String) }
         
     | 
| 
      
 10 
     | 
    
         
            +
              attr_reader :name
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              sig { returns(Zaxcel::Document) }
         
     | 
| 
      
 13 
     | 
    
         
            +
              attr_reader :document
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              sig { returns(T::Hash[Zaxcel::Cell::CellExtractionKey, Zaxcel::Cell]) }
         
     | 
| 
      
 16 
     | 
    
         
            +
              attr_reader :cells_by_extraction_key
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              class SheetVisibility < T::Enum
         
     | 
| 
      
 19 
     | 
    
         
            +
                include Sorbet::EnumerizableEnum
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                enums do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Visible = new(:visible)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  Hidden = new(:hidden) # Can be unhidden from Excel UI
         
     | 
| 
      
 24 
     | 
    
         
            +
                  # VeryHidden is here if we really need it at some point, but pay attention to:
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # - who is potentially going to be accessing this sheet and how will they react to a sheet referenced which cannot be accessed via UI
         
     | 
| 
      
 26 
     | 
    
         
            +
                  # VeryHidden = new(:very_hidden) # Requires code to unhide (e.g. VBA)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              sig { params(name: String, document: Zaxcel::Document, worksheet: Axlsx::Worksheet, visibility: Zaxcel::Sheet::SheetVisibility).void }
         
     | 
| 
      
 31 
     | 
    
         
            +
              def initialize(name:, document:, worksheet:, visibility: Zaxcel::Sheet::SheetVisibility::Visible)
         
     | 
| 
      
 32 
     | 
    
         
            +
                @name = name
         
     | 
| 
      
 33 
     | 
    
         
            +
                @document = document
         
     | 
| 
      
 34 
     | 
    
         
            +
                @worksheet = worksheet
         
     | 
| 
      
 35 
     | 
    
         
            +
                @visibility = visibility
         
     | 
| 
      
 36 
     | 
    
         
            +
                @cells_by_extraction_key = T.let({}, T::Hash[Zaxcel::Cell::CellExtractionKey, Zaxcel::Cell])
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              # returns the underlying axlsx worksheet. this an escape hatch to allow operations not supported by zaxcel.
         
     | 
| 
      
 40 
     | 
    
         
            +
              # this is unsafe because it allows you to mutate the worksheet in ways that zaxcel doesn't know about.
         
     | 
| 
      
 41 
     | 
    
         
            +
              sig { returns(Axlsx::Worksheet) }
         
     | 
| 
      
 42 
     | 
    
         
            +
              def unsafe_axlsx_worksheet
         
     | 
| 
      
 43 
     | 
    
         
            +
                @worksheet
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              sig { returns(String) }
         
     | 
| 
      
 47 
     | 
    
         
            +
              def to_excel
         
     | 
| 
      
 48 
     | 
    
         
            +
                @worksheet.name
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 52 
     | 
    
         
            +
              def position_rows!
         
     | 
| 
      
 53 
     | 
    
         
            +
                rows.each_with_index do |row, i|
         
     | 
| 
      
 54 
     | 
    
         
            +
                  row_position = i + 1 # 1 indexed not 0 indexed
         
     | 
| 
      
 55 
     | 
    
         
            +
                  row.position!(row_position)
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # First persist the location of each cell
         
     | 
| 
      
 58 
     | 
    
         
            +
                  columns.each_with_index do |column, j|
         
     | 
| 
      
 59 
     | 
    
         
            +
                    column.position!(j)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    # add an empty cell anywhere that's missing. this makes cell references work more intuitively.
         
     | 
| 
      
 62 
     | 
    
         
            +
                    # for instance, if I want to reference the top left cell in some area so I can define a merge range,
         
     | 
| 
      
 63 
     | 
    
         
            +
                    # it should resolve whether I define that cell or not.
         
     | 
| 
      
 64 
     | 
    
         
            +
                    cell = column.cell(row.name)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    if cell.nil?
         
     | 
| 
      
 66 
     | 
    
         
            +
                      column.add_cell!(row: row)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    elsif cell.to_extract?
         
     | 
| 
      
 68 
     | 
    
         
            +
                      @cells_by_extraction_key[cell.extraction_key] = cell
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              sig { returns(T::Array[T.nilable(T.any(Float, Integer))]) }
         
     | 
| 
      
 75 
     | 
    
         
            +
              def column_widths
         
     | 
| 
      
 76 
     | 
    
         
            +
                columns.map do |col|
         
     | 
| 
      
 77 
     | 
    
         
            +
                  next T.cast(col.width, T.nilable(T.any(Float, Integer))) if !Zaxcel::Column::ComputedColumnWidth.values.include?(col.width)
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  character_length = case col.width
         
     | 
| 
      
 80 
     | 
    
         
            +
                  when Zaxcel::Column::ComputedColumnWidth::MaxContent
         
     | 
| 
      
 81 
     | 
    
         
            +
                    rows.map do |row|
         
     | 
| 
      
 82 
     | 
    
         
            +
                      cell = col.cell(row.name)
         
     | 
| 
      
 83 
     | 
    
         
            +
                      next 0 if cell.nil? || cell.value.is_a?(Zaxcel::References::Column)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                      cell.estimated_formatted_character_length
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end.compact.max
         
     | 
| 
      
 87 
     | 
    
         
            +
                  when Zaxcel::Column::ComputedColumnWidth::Header
         
     | 
| 
      
 88 
     | 
    
         
            +
                    col.cell(HEADER_ROW_KEY)&.estimated_formatted_character_length || 0
         
     | 
| 
      
 89 
     | 
    
         
            +
                  when Zaxcel::Column::ComputedColumnWidth::HeaderTwoLines
         
     | 
| 
      
 90 
     | 
    
         
            +
                    # if we ever have to do fit to more than two lines (don't think we ever would),
         
     | 
| 
      
 91 
     | 
    
         
            +
                    # just refac this to support N lines and pass N in somehow
         
     | 
| 
      
 92 
     | 
    
         
            +
                    uneven_line_break_buffer = 3
         
     | 
| 
      
 93 
     | 
    
         
            +
                    (((col.cell(HEADER_ROW_KEY)&.estimated_formatted_character_length || 0) / 2) + uneven_line_break_buffer)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  next if character_length.nil?
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  [column_width_from_content_length(character_length), col.min_width].max
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
              # An alternative to allowing CAXLSX to auto-calculate the width of a column,
         
     | 
| 
      
 103 
     | 
    
         
            +
              # since it sometimes gives way too much extra space.
         
     | 
| 
      
 104 
     | 
    
         
            +
              sig { params(content_length: Integer).returns(Integer) }
         
     | 
| 
      
 105 
     | 
    
         
            +
              def column_width_from_content_length(content_length)
         
     | 
| 
      
 106 
     | 
    
         
            +
                (document.width_units_by_default_character * content_length).ceil
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 110 
     | 
    
         
            +
              def add_rows_to_worksheet!
         
     | 
| 
      
 111 
     | 
    
         
            +
                rows.each_with_index do |row, _rowi|
         
     | 
| 
      
 112 
     | 
    
         
            +
                  cells_in_row = columns.map { |col| col.cell(row.name) }
         
     | 
| 
      
 113 
     | 
    
         
            +
                  formatted_cells = cells_in_row.map { |cell| format_cell_contents(cell) }
         
     | 
| 
      
 114 
     | 
    
         
            +
                  @worksheet.add_row(
         
     | 
| 
      
 115 
     | 
    
         
            +
                    formatted_cells,
         
     | 
| 
      
 116 
     | 
    
         
            +
                    style: cells_in_row.map { |c| @document.style(c&.style || :default_cell) },
         
     | 
| 
      
 117 
     | 
    
         
            +
                    height: row.height,
         
     | 
| 
      
 118 
     | 
    
         
            +
                  )
         
     | 
| 
      
 119 
     | 
    
         
            +
                  @worksheet.column_widths(*T.unsafe(column_widths))
         
     | 
| 
      
 120 
     | 
    
         
            +
                end
         
     | 
| 
      
 121 
     | 
    
         
            +
              end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
              sig { returns(T.nilable(Zaxcel::Column)) }
         
     | 
| 
      
 124 
     | 
    
         
            +
              def print_boundary_column
         
     | 
| 
      
 125 
     | 
    
         
            +
                columns.find(&:print_boundary?)
         
     | 
| 
      
 126 
     | 
    
         
            +
              end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
              sig { returns(T.nilable(Zaxcel::Row)) }
         
     | 
| 
      
 129 
     | 
    
         
            +
              def print_boundary_row
         
     | 
| 
      
 130 
     | 
    
         
            +
                rows.find(&:print_boundary?)
         
     | 
| 
      
 131 
     | 
    
         
            +
              end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 134 
     | 
    
         
            +
              def set_print_area!
         
     | 
| 
      
 135 
     | 
    
         
            +
                first_column_to_print = columns.first!
         
     | 
| 
      
 136 
     | 
    
         
            +
                last_column_to_print = print_boundary_column || T.must(columns.last)
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                first_row_to_print = rows.first!
         
     | 
| 
      
 139 
     | 
    
         
            +
                last_row_to_print = print_boundary_row || T.must(rows.last)
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                print_area_range = "'#{to_excel}'!#{first_column_to_print.to_excel}#{first_row_to_print.to_excel}:#{last_column_to_print.to_excel}#{last_row_to_print.to_excel}"
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                @document.set_print_area(sheet: @worksheet, range_to_include: print_area_range)
         
     | 
| 
      
 144 
     | 
    
         
            +
              end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 147 
     | 
    
         
            +
              def apply_conditional_formatting!
         
     | 
| 
      
 148 
     | 
    
         
            +
                conditional_formatting.each do |formatting|
         
     | 
| 
      
 149 
     | 
    
         
            +
                  range = formatting[:range]
         
     | 
| 
      
 150 
     | 
    
         
            +
                  if range.is_a?(Zaxcel::References::Column)
         
     | 
| 
      
 151 
     | 
    
         
            +
                    first_cell = range.cells.first!
         
     | 
| 
      
 152 
     | 
    
         
            +
                    last_cell = T.must(range.cells.last)
         
     | 
| 
      
 153 
     | 
    
         
            +
                  else
         
     | 
| 
      
 154 
     | 
    
         
            +
                    range = T.cast(range, T::Array[Zaxcel::References::Cell])
         
     | 
| 
      
 155 
     | 
    
         
            +
                    first_cell = range.first!.cell
         
     | 
| 
      
 156 
     | 
    
         
            +
                    last_cell = T.must(range.last).cell
         
     | 
| 
      
 157 
     | 
    
         
            +
                  end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                  @worksheet.add_conditional_formatting(
         
     | 
| 
      
 160 
     | 
    
         
            +
                    "#{T.must(first_cell).to_excel}:#{T.must(last_cell).to_excel}",
         
     | 
| 
      
 161 
     | 
    
         
            +
                    type: formatting[:rule],
         
     | 
| 
      
 162 
     | 
    
         
            +
                    dxfId: @document.style(formatting[:style]),
         
     | 
| 
      
 163 
     | 
    
         
            +
                    priority: 1, # i don't know what this means :)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  )
         
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 169 
     | 
    
         
            +
              def apply_cell_merges!
         
     | 
| 
      
 170 
     | 
    
         
            +
                ranges_to_merge.each do |range|
         
     | 
| 
      
 171 
     | 
    
         
            +
                  cells = range.map(&:cell).compact
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                  first_column_cell = cells.min_by { |cell| T.must(cell.col_position) }
         
     | 
| 
      
 174 
     | 
    
         
            +
                  first_row_cell = cells.min_by { |cell| T.must(cell.row_position) }
         
     | 
| 
      
 175 
     | 
    
         
            +
                  last_column_cell = cells.max_by { |cell| T.must(cell.col_position) }
         
     | 
| 
      
 176 
     | 
    
         
            +
                  last_row_cell = cells.max_by { |cell| T.must(cell.row_position) }
         
     | 
| 
      
 177 
     | 
    
         
            +
                  # if any of the references don't resolve, then just skip this range
         
     | 
| 
      
 178 
     | 
    
         
            +
                  next if first_column_cell.nil? || first_row_cell.nil? || last_column_cell.nil? || last_row_cell.nil?
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                  top_left_cell_position = "#{first_column_cell.column.to_excel}#{first_row_cell.row.to_excel}"
         
     | 
| 
      
 181 
     | 
    
         
            +
                  bottom_right_cell_position = "#{last_column_cell.column.to_excel}#{last_row_cell.row.to_excel}"
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                  @worksheet.merge_cells("#{top_left_cell_position}:#{bottom_right_cell_position}")
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 188 
     | 
    
         
            +
              def hide_columns!
         
     | 
| 
      
 189 
     | 
    
         
            +
                columns.select(&:hidden?).each do |column|
         
     | 
| 
      
 190 
     | 
    
         
            +
                  @worksheet.column_info[column.position].hidden = true
         
     | 
| 
      
 191 
     | 
    
         
            +
                end
         
     | 
| 
      
 192 
     | 
    
         
            +
              end
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 195 
     | 
    
         
            +
              def hide_rows!
         
     | 
| 
      
 196 
     | 
    
         
            +
                rows.each_with_index do |row, i|
         
     | 
| 
      
 197 
     | 
    
         
            +
                  next if !row.hidden?
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                  @worksheet.rows[i].hidden = true
         
     | 
| 
      
 200 
     | 
    
         
            +
                end
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 204 
     | 
    
         
            +
              def apply_sheet_visibility!
         
     | 
| 
      
 205 
     | 
    
         
            +
                @worksheet.state = @visibility.serialize
         
     | 
| 
      
 206 
     | 
    
         
            +
              end
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
              # it woudl be cool to specify a cell as an image instead...
         
     | 
| 
      
 209 
     | 
    
         
            +
              sig do
         
     | 
| 
      
 210 
     | 
    
         
            +
                params(image_path: String, width: Integer, height: Integer, row_position: Integer, column_position: Integer).void
         
     | 
| 
      
 211 
     | 
    
         
            +
              end
         
     | 
| 
      
 212 
     | 
    
         
            +
              def add_image_to_worksheet!(image_path, width:, height:, row_position:, column_position:)
         
     | 
| 
      
 213 
     | 
    
         
            +
                @worksheet.add_image(
         
     | 
| 
      
 214 
     | 
    
         
            +
                  image_src: image_path,
         
     | 
| 
      
 215 
     | 
    
         
            +
                  noMove: true,
         
     | 
| 
      
 216 
     | 
    
         
            +
                ) do |image|
         
     | 
| 
      
 217 
     | 
    
         
            +
                  image.width = width
         
     | 
| 
      
 218 
     | 
    
         
            +
                  image.height = height
         
     | 
| 
      
 219 
     | 
    
         
            +
                  image.start_at(column_position, row_position)
         
     | 
| 
      
 220 
     | 
    
         
            +
                end
         
     | 
| 
      
 221 
     | 
    
         
            +
              end
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 224 
     | 
    
         
            +
              def generate_sheet!
         
     | 
| 
      
 225 
     | 
    
         
            +
                add_rows_to_worksheet!
         
     | 
| 
      
 226 
     | 
    
         
            +
                set_print_area!
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                apply_cell_merges!
         
     | 
| 
      
 229 
     | 
    
         
            +
                apply_conditional_formatting!
         
     | 
| 
      
 230 
     | 
    
         
            +
                hide_columns!
         
     | 
| 
      
 231 
     | 
    
         
            +
                hide_rows!
         
     | 
| 
      
 232 
     | 
    
         
            +
                apply_sheet_visibility!
         
     | 
| 
      
 233 
     | 
    
         
            +
              end
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
              sig { params(row_name: T.any(Symbol, String)).returns(T.nilable(Zaxcel::Row)) }
         
     | 
| 
      
 236 
     | 
    
         
            +
              def row(row_name)
         
     | 
| 
      
 237 
     | 
    
         
            +
                rows_by_name[row_name.to_sym]
         
     | 
| 
      
 238 
     | 
    
         
            +
              end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
              sig { params(column_name: T.any(Symbol, String)).returns(T.nilable(Zaxcel::Column)) }
         
     | 
| 
      
 241 
     | 
    
         
            +
              def column(column_name)
         
     | 
| 
      
 242 
     | 
    
         
            +
                columns_by_name[column_name.to_sym]
         
     | 
| 
      
 243 
     | 
    
         
            +
              end
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
              sig do
         
     | 
| 
      
 246 
     | 
    
         
            +
                params(
         
     | 
| 
      
 247 
     | 
    
         
            +
                  name: T.any(Symbol, String, Numeric),
         
     | 
| 
      
 248 
     | 
    
         
            +
                  style_group: Symbol,
         
     | 
| 
      
 249 
     | 
    
         
            +
                  height: T.nilable(Integer),
         
     | 
| 
      
 250 
     | 
    
         
            +
                  hidden: T::Boolean,
         
     | 
| 
      
 251 
     | 
    
         
            +
                ).returns(Zaxcel::Row)
         
     | 
| 
      
 252 
     | 
    
         
            +
              end
         
     | 
| 
      
 253 
     | 
    
         
            +
              def add_row!(name, style_group: :row_style, height: nil, hidden: false)
         
     | 
| 
      
 254 
     | 
    
         
            +
                name = name.to_s if name.is_a?(Numeric)
         
     | 
| 
      
 255 
     | 
    
         
            +
                rows_by_name[name.to_sym] ||= Zaxcel::Row.new(
         
     | 
| 
      
 256 
     | 
    
         
            +
                  name.to_sym,
         
     | 
| 
      
 257 
     | 
    
         
            +
                  sheet: self,
         
     | 
| 
      
 258 
     | 
    
         
            +
                  style_group: style_group,
         
     | 
| 
      
 259 
     | 
    
         
            +
                  height: height,
         
     | 
| 
      
 260 
     | 
    
         
            +
                  hidden: hidden,
         
     | 
| 
      
 261 
     | 
    
         
            +
                )
         
     | 
| 
      
 262 
     | 
    
         
            +
              end
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
              sig { params(style_group: Symbol).returns(Zaxcel::Row) }
         
     | 
| 
      
 265 
     | 
    
         
            +
              def add_empty_row!(style_group: :row_style)
         
     | 
| 
      
 266 
     | 
    
         
            +
                add_row!(SecureRandom.uuid.delete('-'), style_group: style_group)
         
     | 
| 
      
 267 
     | 
    
         
            +
              end
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
              sig do
         
     | 
| 
      
 270 
     | 
    
         
            +
                params(
         
     | 
| 
      
 271 
     | 
    
         
            +
                  name: T.any(Symbol, String),
         
     | 
| 
      
 272 
     | 
    
         
            +
                  header: String,
         
     | 
| 
      
 273 
     | 
    
         
            +
                  header_style: Symbol,
         
     | 
| 
      
 274 
     | 
    
         
            +
                  row_style: Symbol,
         
     | 
| 
      
 275 
     | 
    
         
            +
                  first_row_style: Symbol,
         
     | 
| 
      
 276 
     | 
    
         
            +
                  total_style: T.nilable(Symbol),
         
     | 
| 
      
 277 
     | 
    
         
            +
                  width: T.nilable(T.any(Integer, Float, Zaxcel::Column::ComputedColumnWidth)),
         
     | 
| 
      
 278 
     | 
    
         
            +
                  alt_row_style: T.nilable(Symbol),
         
     | 
| 
      
 279 
     | 
    
         
            +
                  min_width: T.nilable(T.any(Integer, Float)),
         
     | 
| 
      
 280 
     | 
    
         
            +
                ).returns(Zaxcel::Column)
         
     | 
| 
      
 281 
     | 
    
         
            +
              end
         
     | 
| 
      
 282 
     | 
    
         
            +
              def add_column!(
         
     | 
| 
      
 283 
     | 
    
         
            +
                name,
         
     | 
| 
      
 284 
     | 
    
         
            +
                header: '',
         
     | 
| 
      
 285 
     | 
    
         
            +
                header_style: :default_cell,
         
     | 
| 
      
 286 
     | 
    
         
            +
                row_style: :default_cell,
         
     | 
| 
      
 287 
     | 
    
         
            +
                first_row_style: :default_cell,
         
     | 
| 
      
 288 
     | 
    
         
            +
                total_style: nil,
         
     | 
| 
      
 289 
     | 
    
         
            +
                width: Zaxcel::Column::DEFAULT_COLUMN_WIDTH,
         
     | 
| 
      
 290 
     | 
    
         
            +
                alt_row_style: nil,
         
     | 
| 
      
 291 
     | 
    
         
            +
                min_width: 0
         
     | 
| 
      
 292 
     | 
    
         
            +
              )
         
     | 
| 
      
 293 
     | 
    
         
            +
                columns_by_name[name.to_sym] ||= Zaxcel::Column.new(
         
     | 
| 
      
 294 
     | 
    
         
            +
                  sheet: self,
         
     | 
| 
      
 295 
     | 
    
         
            +
                  name: name.to_sym,
         
     | 
| 
      
 296 
     | 
    
         
            +
                  header: header,
         
     | 
| 
      
 297 
     | 
    
         
            +
                  header_style: header_style,
         
     | 
| 
      
 298 
     | 
    
         
            +
                  row_style: row_style,
         
     | 
| 
      
 299 
     | 
    
         
            +
                  first_row_style: first_row_style,
         
     | 
| 
      
 300 
     | 
    
         
            +
                  total_style: total_style,
         
     | 
| 
      
 301 
     | 
    
         
            +
                  width: width,
         
     | 
| 
      
 302 
     | 
    
         
            +
                  alt_row_style: alt_row_style,
         
     | 
| 
      
 303 
     | 
    
         
            +
                  min_width: min_width,
         
     | 
| 
      
 304 
     | 
    
         
            +
                )
         
     | 
| 
      
 305 
     | 
    
         
            +
              end
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
              sig { params(width: T.nilable(T.any(Integer, Float))).returns(Zaxcel::Column) }
         
     | 
| 
      
 308 
     | 
    
         
            +
              def add_empty_column!(width: Zaxcel::Column::DEFAULT_COLUMN_WIDTH)
         
     | 
| 
      
 309 
     | 
    
         
            +
                add_column!(SecureRandom.uuid.delete('-'), width: width)
         
     | 
| 
      
 310 
     | 
    
         
            +
              end
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
              sig do
         
     | 
| 
      
 313 
     | 
    
         
            +
                params(
         
     | 
| 
      
 314 
     | 
    
         
            +
                  range: T.any(Zaxcel::References::Column, T::Array[Zaxcel::References::Cell]),
         
     | 
| 
      
 315 
     | 
    
         
            +
                  rule: Symbol,
         
     | 
| 
      
 316 
     | 
    
         
            +
                  style: Symbol,
         
     | 
| 
      
 317 
     | 
    
         
            +
                ).void
         
     | 
| 
      
 318 
     | 
    
         
            +
              end
         
     | 
| 
      
 319 
     | 
    
         
            +
              def add_conditional_formatting!(range:, rule:, style:)
         
     | 
| 
      
 320 
     | 
    
         
            +
                conditional_formatting << { range: range, rule: rule, style: style }
         
     | 
| 
      
 321 
     | 
    
         
            +
              end
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
              sig { params(range: T::Array[Zaxcel::References::Cell]).void }
         
     | 
| 
      
 324 
     | 
    
         
            +
              def merge_cells!(range)
         
     | 
| 
      
 325 
     | 
    
         
            +
                ranges_to_merge << range
         
     | 
| 
      
 326 
     | 
    
         
            +
              end
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
              sig { returns(T::Array[T::Array[Zaxcel::References::Cell]]) }
         
     | 
| 
      
 329 
     | 
    
         
            +
              def ranges_to_merge
         
     | 
| 
      
 330 
     | 
    
         
            +
                @ranges_to_merge ||= T.let([], T.nilable(T::Array[T::Array[Zaxcel::References::Cell]]))
         
     | 
| 
      
 331 
     | 
    
         
            +
              end
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
      
 333 
     | 
    
         
            +
              sig { returns(T::Array[Zaxcel::Column]) }
         
     | 
| 
      
 334 
     | 
    
         
            +
              def columns
         
     | 
| 
      
 335 
     | 
    
         
            +
                columns_by_name.values
         
     | 
| 
      
 336 
     | 
    
         
            +
              end
         
     | 
| 
      
 337 
     | 
    
         
            +
             
     | 
| 
      
 338 
     | 
    
         
            +
              sig { returns(T::Array[Zaxcel::Row]) }
         
     | 
| 
      
 339 
     | 
    
         
            +
              def rows
         
     | 
| 
      
 340 
     | 
    
         
            +
                rows_by_name.values
         
     | 
| 
      
 341 
     | 
    
         
            +
              end
         
     | 
| 
      
 342 
     | 
    
         
            +
             
     | 
| 
      
 343 
     | 
    
         
            +
              sig { params(height: T.nilable(Integer)).returns(Zaxcel::Row) }
         
     | 
| 
      
 344 
     | 
    
         
            +
              def add_column_header_row!(height: nil)
         
     | 
| 
      
 345 
     | 
    
         
            +
                add_row!(HEADER_ROW_KEY, style_group: :header_style, height: height)
         
     | 
| 
      
 346 
     | 
    
         
            +
                  .add_many!(columns.map { |c| [c.name, c.header] }.to_h)
         
     | 
| 
      
 347 
     | 
    
         
            +
              end
         
     | 
| 
      
 348 
     | 
    
         
            +
             
     | 
| 
      
 349 
     | 
    
         
            +
              sig { returns(T::Hash[Symbol, Zaxcel::Row]) }
         
     | 
| 
      
 350 
     | 
    
         
            +
              def rows_by_name
         
     | 
| 
      
 351 
     | 
    
         
            +
                @rows_by_name ||= T.let({}, T.nilable(T::Hash[Symbol, Zaxcel::Row]))
         
     | 
| 
      
 352 
     | 
    
         
            +
              end
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
              sig { returns(T::Hash[Symbol, Zaxcel::Column]) }
         
     | 
| 
      
 355 
     | 
    
         
            +
              def columns_by_name
         
     | 
| 
      
 356 
     | 
    
         
            +
                @columns_by_name ||= T.let({}, T.nilable(T::Hash[Symbol, Zaxcel::Column]))
         
     | 
| 
      
 357 
     | 
    
         
            +
              end
         
     | 
| 
      
 358 
     | 
    
         
            +
             
     | 
| 
      
 359 
     | 
    
         
            +
              sig { returns(T::Array[{ range: T.any(Zaxcel::References::Column, T::Array[Zaxcel::References::Cell]), rule: Symbol, style: Symbol }]) }
         
     | 
| 
      
 360 
     | 
    
         
            +
              def conditional_formatting
         
     | 
| 
      
 361 
     | 
    
         
            +
                @conditional_formatting ||= T.let(
         
     | 
| 
      
 362 
     | 
    
         
            +
                  [],
         
     | 
| 
      
 363 
     | 
    
         
            +
                  T.nilable(T::Array[{
         
     | 
| 
      
 364 
     | 
    
         
            +
                    range: T.any(Zaxcel::References::Column, T::Array[Zaxcel::References::Cell]),
         
     | 
| 
      
 365 
     | 
    
         
            +
                    rule: Symbol,
         
     | 
| 
      
 366 
     | 
    
         
            +
                    style: Symbol,
         
     | 
| 
      
 367 
     | 
    
         
            +
                  }]),
         
     | 
| 
      
 368 
     | 
    
         
            +
                )
         
     | 
| 
      
 369 
     | 
    
         
            +
              end
         
     | 
| 
      
 370 
     | 
    
         
            +
             
     | 
| 
      
 371 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 372 
     | 
    
         
            +
              def hide_gridlines!
         
     | 
| 
      
 373 
     | 
    
         
            +
                @worksheet.sheet_view.show_grid_lines = false
         
     | 
| 
      
 374 
     | 
    
         
            +
              end
         
     | 
| 
      
 375 
     | 
    
         
            +
             
     | 
| 
      
 376 
     | 
    
         
            +
              sig { void }
         
     | 
| 
      
 377 
     | 
    
         
            +
              def print_landscape!
         
     | 
| 
      
 378 
     | 
    
         
            +
                @worksheet.print_options.horizontal_centered = true
         
     | 
| 
      
 379 
     | 
    
         
            +
                @worksheet.page_setup.orientation = :landscape
         
     | 
| 
      
 380 
     | 
    
         
            +
              end
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
              sig do
         
     | 
| 
      
 383 
     | 
    
         
            +
                params(
         
     | 
| 
      
 384 
     | 
    
         
            +
                  col_name: T.any(Symbol, String),
         
     | 
| 
      
 385 
     | 
    
         
            +
                  row_name: T.any(Symbol, String, Numeric),
         
     | 
| 
      
 386 
     | 
    
         
            +
                  sheet_name: T.nilable(String),
         
     | 
| 
      
 387 
     | 
    
         
            +
                ).returns(Zaxcel::References::Cell)
         
     | 
| 
      
 388 
     | 
    
         
            +
              end
         
     | 
| 
      
 389 
     | 
    
         
            +
              def cell_ref(col_name, row_name, sheet_name: nil)
         
     | 
| 
      
 390 
     | 
    
         
            +
                row_name = row_name.to_s if row_name.is_a?(Numeric)
         
     | 
| 
      
 391 
     | 
    
         
            +
                Zaxcel::References::Cell.new(
         
     | 
| 
      
 392 
     | 
    
         
            +
                  document: @document,
         
     | 
| 
      
 393 
     | 
    
         
            +
                  sheet_name: sheet_name || @name,
         
     | 
| 
      
 394 
     | 
    
         
            +
                  row_name: row_name.to_sym,
         
     | 
| 
      
 395 
     | 
    
         
            +
                  col_name: col_name.to_sym,
         
     | 
| 
      
 396 
     | 
    
         
            +
                )
         
     | 
| 
      
 397 
     | 
    
         
            +
              end
         
     | 
| 
      
 398 
     | 
    
         
            +
             
     | 
| 
      
 399 
     | 
    
         
            +
              sig { params(col_name: T.any(Symbol, String), sheet_name: T.nilable(String)).returns(Zaxcel::References::Column) }
         
     | 
| 
      
 400 
     | 
    
         
            +
              def column_ref(col_name, sheet_name: nil)
         
     | 
| 
      
 401 
     | 
    
         
            +
                Zaxcel::References::Column.new(document: @document, sheet_name: sheet_name || @name, col_name: col_name.to_sym)
         
     | 
| 
      
 402 
     | 
    
         
            +
              end
         
     | 
| 
      
 403 
     | 
    
         
            +
             
     | 
| 
      
 404 
     | 
    
         
            +
              private
         
     | 
| 
      
 405 
     | 
    
         
            +
             
     | 
| 
      
 406 
     | 
    
         
            +
              sig { params(cell: T.nilable(Zaxcel::Cell)).returns(T.nilable(T.any(Numeric, Money, String))) }
         
     | 
| 
      
 407 
     | 
    
         
            +
              def format_cell_contents(cell)
         
     | 
| 
      
 408 
     | 
    
         
            +
                value = cell&.value
         
     | 
| 
      
 409 
     | 
    
         
            +
                base_format = Zaxcel::Cell.format(value, on_sheet: @name, quote_strings: false)
         
     | 
| 
      
 410 
     | 
    
         
            +
                # always pass along numerics + money + nil as is for caxlsx to print directly
         
     | 
| 
      
 411 
     | 
    
         
            +
                return base_format if !base_format.is_a?(String)
         
     | 
| 
      
 412 
     | 
    
         
            +
             
     | 
| 
      
 413 
     | 
    
         
            +
                # prefix the evaluation operator if the result is a cell formula
         
     | 
| 
      
 414 
     | 
    
         
            +
                if value.is_a?(Time) || value.is_a?(Zaxcel::CellFormula) || value.is_a?(Zaxcel::Reference) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
         
     | 
| 
      
 415 
     | 
    
         
            +
                  base_format = "=#{base_format}"
         
     | 
| 
      
 416 
     | 
    
         
            +
             
     | 
| 
      
 417 
     | 
    
         
            +
                  # array formulas need to be wrapped in curly braces for CAXLSX. See
         
     | 
| 
      
 418 
     | 
    
         
            +
                  # https://github.com/caxlsx/caxlsx/blob/master/lib/axlsx/workbook/worksheet/cell.rb#L422 and
         
     | 
| 
      
 419 
     | 
    
         
            +
                  # https://github.com/caxlsx/caxlsx/blob/master/lib/axlsx/workbook/worksheet/cell_serializer.rb#L101
         
     | 
| 
      
 420 
     | 
    
         
            +
                  base_format = "{#{base_format}}" if value.respond_to?(:array_formula?) && T.unsafe(value).array_formula?
         
     | 
| 
      
 421 
     | 
    
         
            +
                end
         
     | 
| 
      
 422 
     | 
    
         
            +
             
     | 
| 
      
 423 
     | 
    
         
            +
                base_format
         
     | 
| 
      
 424 
     | 
    
         
            +
              end
         
     | 
| 
      
 425 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
            # typed: strict
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'active_support/concern'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # Include this in a sorbet typed enum (T::Enum) so that it can be used easily with the `enumerize` gem:
         
     | 
| 
      
 7 
     | 
    
         
            +
            # ```ruby
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   class Category < T::Enum
         
     | 
| 
      
 9 
     | 
    
         
            +
            #     enums do
         
     | 
| 
      
 10 
     | 
    
         
            +
            #       One = new(:one)
         
     | 
| 
      
 11 
     | 
    
         
            +
            #       Two = new(:two)
         
     | 
| 
      
 12 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 13 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 14 
     | 
    
         
            +
            #
         
     | 
| 
      
 15 
     | 
    
         
            +
            #   enumerize(
         
     | 
| 
      
 16 
     | 
    
         
            +
            #    :category,
         
     | 
| 
      
 17 
     | 
    
         
            +
            #    in: Category.enumerize_values,
         
     | 
| 
      
 18 
     | 
    
         
            +
            #    value_class: Category,
         
     | 
| 
      
 19 
     | 
    
         
            +
            #  )
         
     | 
| 
      
 20 
     | 
    
         
            +
            # ```
         
     | 
| 
      
 21 
     | 
    
         
            +
            class Sorbet
         
     | 
| 
      
 22 
     | 
    
         
            +
              module EnumerizableEnum
         
     | 
| 
      
 23 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 24 
     | 
    
         
            +
                extend T::Sig
         
     | 
| 
      
 25 
     | 
    
         
            +
                extend T::Generic
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                # Enumerize requires that `value` on an instance of the `value_class` returns the enum's underlying value.
         
     | 
| 
      
 28 
     | 
    
         
            +
                sig { returns(Symbol) }
         
     | 
| 
      
 29 
     | 
    
         
            +
                def value = T.bind(self, T::Enum).serialize
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                class_methods do
         
     | 
| 
      
 32 
     | 
    
         
            +
                  extend T::Sig
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # Monkey patch new to call `new` on `T::Enum` if a single value is passed in, otherwise call `deserialize` on the
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # on the enum class. Enumerize calls `new` on the value class with two args; the second of which is the underlying
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # value.
         
     | 
| 
      
 37 
     | 
    
         
            +
                  sig { params(args: T.untyped).returns(T.untyped) }
         
     | 
| 
      
 38 
     | 
    
         
            +
                  def new(*args)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    return super if args.length == 1
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    T.bind(self, T.class_of(T::Enum)).deserialize(args[1].to_sym)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  sig { returns(T::Array[Symbol]) }
         
     | 
| 
      
 45 
     | 
    
         
            +
                  def enumerize_values
         
     | 
| 
      
 46 
     | 
    
         
            +
                    T.bind(self, T.class_of(T::Enum)).values.map(&:serialize)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/zaxcel.rb
    ADDED
    
    | 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # typed: strict
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'sorbet-runtime'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'caxlsx'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'active_support/core_ext/object/blank'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'active_support/core_ext/object/try'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'active_support/core_ext/string/filters'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'active_support/core_ext/string/access'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'active_support/core_ext/string/inflections'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'money'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require_relative 'zaxcel/version'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require_relative 'zaxcel/sorbet/enumerizable_enum'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require_relative 'enumerable'
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            # Core classes
         
     | 
| 
      
 18 
     | 
    
         
            +
            require_relative 'zaxcel/arithmetic'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require_relative 'zaxcel/roundable'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require_relative 'zaxcel/reference'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require_relative 'zaxcel/cell_formula'
         
     | 
| 
      
 22 
     | 
    
         
            +
            require_relative 'zaxcel/binary_expression'
         
     | 
| 
      
 23 
     | 
    
         
            +
            require_relative 'zaxcel/function'
         
     | 
| 
      
 24 
     | 
    
         
            +
            require_relative 'zaxcel/if_builder'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require_relative 'zaxcel/lang'
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            # Binary expressions
         
     | 
| 
      
 28 
     | 
    
         
            +
            require_relative 'zaxcel/binary_expressions'
         
     | 
| 
      
 29 
     | 
    
         
            +
            require_relative 'zaxcel/binary_expressions/addition'
         
     | 
| 
      
 30 
     | 
    
         
            +
            require_relative 'zaxcel/binary_expressions/subtraction'
         
     | 
| 
      
 31 
     | 
    
         
            +
            require_relative 'zaxcel/binary_expressions/multiplication'
         
     | 
| 
      
 32 
     | 
    
         
            +
            require_relative 'zaxcel/binary_expressions/division'
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            # References
         
     | 
| 
      
 35 
     | 
    
         
            +
            require_relative 'zaxcel/references'
         
     | 
| 
      
 36 
     | 
    
         
            +
            require_relative 'zaxcel/references/cell'
         
     | 
| 
      
 37 
     | 
    
         
            +
            require_relative 'zaxcel/references/column'
         
     | 
| 
      
 38 
     | 
    
         
            +
            require_relative 'zaxcel/references/row'
         
     | 
| 
      
 39 
     | 
    
         
            +
            require_relative 'zaxcel/references/range'
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            # Functions
         
     | 
| 
      
 42 
     | 
    
         
            +
            require_relative 'zaxcel/functions'
         
     | 
| 
      
 43 
     | 
    
         
            +
            require_relative 'zaxcel/functions/abs'
         
     | 
| 
      
 44 
     | 
    
         
            +
            require_relative 'zaxcel/functions/and'
         
     | 
| 
      
 45 
     | 
    
         
            +
            require_relative 'zaxcel/functions/average'
         
     | 
| 
      
 46 
     | 
    
         
            +
            require_relative 'zaxcel/functions/choose'
         
     | 
| 
      
 47 
     | 
    
         
            +
            require_relative 'zaxcel/functions/concatenate'
         
     | 
| 
      
 48 
     | 
    
         
            +
            require_relative 'zaxcel/functions/if'
         
     | 
| 
      
 49 
     | 
    
         
            +
            require_relative 'zaxcel/functions/if_error'
         
     | 
| 
      
 50 
     | 
    
         
            +
            require_relative 'zaxcel/functions/index'
         
     | 
| 
      
 51 
     | 
    
         
            +
            require_relative 'zaxcel/functions/len'
         
     | 
| 
      
 52 
     | 
    
         
            +
            require_relative 'zaxcel/functions/match'
         
     | 
| 
      
 53 
     | 
    
         
            +
            require_relative 'zaxcel/functions/match/match_type'
         
     | 
| 
      
 54 
     | 
    
         
            +
            require_relative 'zaxcel/functions/max'
         
     | 
| 
      
 55 
     | 
    
         
            +
            require_relative 'zaxcel/functions/min'
         
     | 
| 
      
 56 
     | 
    
         
            +
            require_relative 'zaxcel/functions/negate'
         
     | 
| 
      
 57 
     | 
    
         
            +
            require_relative 'zaxcel/functions/or'
         
     | 
| 
      
 58 
     | 
    
         
            +
            require_relative 'zaxcel/functions/round'
         
     | 
| 
      
 59 
     | 
    
         
            +
            require_relative 'zaxcel/functions/sum'
         
     | 
| 
      
 60 
     | 
    
         
            +
            require_relative 'zaxcel/functions/sum_if'
         
     | 
| 
      
 61 
     | 
    
         
            +
            require_relative 'zaxcel/functions/sum_ifs'
         
     | 
| 
      
 62 
     | 
    
         
            +
            require_relative 'zaxcel/functions/sum_product'
         
     | 
| 
      
 63 
     | 
    
         
            +
            require_relative 'zaxcel/functions/text'
         
     | 
| 
      
 64 
     | 
    
         
            +
            require_relative 'zaxcel/functions/unique'
         
     | 
| 
      
 65 
     | 
    
         
            +
            require_relative 'zaxcel/functions/x_lookup'
         
     | 
| 
      
 66 
     | 
    
         
            +
            require_relative 'zaxcel/functions/xirr'
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            # Main classes
         
     | 
| 
      
 69 
     | 
    
         
            +
            require_relative 'zaxcel/cell'
         
     | 
| 
      
 70 
     | 
    
         
            +
            require_relative 'zaxcel/column'
         
     | 
| 
      
 71 
     | 
    
         
            +
            require_relative 'zaxcel/row'
         
     | 
| 
      
 72 
     | 
    
         
            +
            require_relative 'zaxcel/sheet'
         
     | 
| 
      
 73 
     | 
    
         
            +
            require_relative 'zaxcel/document'
         
     | 
    
        data/zaxcel.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'lib/zaxcel/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 6 
     | 
    
         
            +
              spec.name          = 'zaxcel'
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.version       = Zaxcel::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors       = ['AngelList Engineering']
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email         = ['engineering@angellist.com']
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary       = 'A Ruby DSL for building Excel spreadsheets programmatically'
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description   = <<~DESC
         
     | 
| 
      
 13 
     | 
    
         
            +
                Zaxcel is a Ruby library built on top of caxlsx that adds an abstraction layer#{' '}
         
     | 
| 
      
 14 
     | 
    
         
            +
                to building Excel documents. It provides simple methods for building formulas#{' '}
         
     | 
| 
      
 15 
     | 
    
         
            +
                and references to other cells, even across many worksheets, using clean Ruby idioms#{' '}
         
     | 
| 
      
 16 
     | 
    
         
            +
                without having to think about the underlying Excel implementation.
         
     | 
| 
      
 17 
     | 
    
         
            +
              DESC
         
     | 
| 
      
 18 
     | 
    
         
            +
              spec.homepage      = 'https://github.com/angellist/zaxcel'
         
     | 
| 
      
 19 
     | 
    
         
            +
              spec.license       = 'MIT'
         
     | 
| 
      
 20 
     | 
    
         
            +
              spec.required_ruby_version = '>= 3.0.0'
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              spec.metadata = {
         
     | 
| 
      
 23 
     | 
    
         
            +
                'bug_tracker_uri' => 'https://github.com/angellist/zaxcel/issues',
         
     | 
| 
      
 24 
     | 
    
         
            +
                'changelog_uri' => 'https://github.com/angellist/zaxcel/blob/main/CHANGELOG.md',
         
     | 
| 
      
 25 
     | 
    
         
            +
                'documentation_uri' => 'https://github.com/angellist/zaxcel',
         
     | 
| 
      
 26 
     | 
    
         
            +
                'homepage_uri' => 'https://github.com/angellist/zaxcel',
         
     | 
| 
      
 27 
     | 
    
         
            +
                'source_code_uri' => 'https://github.com/angellist/zaxcel',
         
     | 
| 
      
 28 
     | 
    
         
            +
                'rubygems_mfa_required' => 'true',
         
     | 
| 
      
 29 
     | 
    
         
            +
              }
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              spec.files = Dir.chdir(__dir__) do
         
     | 
| 
      
 32 
     | 
    
         
            +
                %x(git ls-files -z).split("\x0").reject do |f|
         
     | 
| 
      
 33 
     | 
    
         
            +
                  (File.expand_path(f) == __FILE__) ||
         
     | 
| 
      
 34 
     | 
    
         
            +
                    f.start_with?(*%w[
         
     | 
| 
      
 35 
     | 
    
         
            +
                      bin/
         
     | 
| 
      
 36 
     | 
    
         
            +
                      test/
         
     | 
| 
      
 37 
     | 
    
         
            +
                      spec/
         
     | 
| 
      
 38 
     | 
    
         
            +
                      features/
         
     | 
| 
      
 39 
     | 
    
         
            +
                      .git
         
     | 
| 
      
 40 
     | 
    
         
            +
                      .circleci
         
     | 
| 
      
 41 
     | 
    
         
            +
                      .github/
         
     | 
| 
      
 42 
     | 
    
         
            +
                      appveyor
         
     | 
| 
      
 43 
     | 
    
         
            +
                      Gemfile
         
     | 
| 
      
 44 
     | 
    
         
            +
                      vendor/
         
     | 
| 
      
 45 
     | 
    
         
            +
                      vendor/bundle/
         
     | 
| 
      
 46 
     | 
    
         
            +
                      coverage/
         
     | 
| 
      
 47 
     | 
    
         
            +
                      tmp/
         
     | 
| 
      
 48 
     | 
    
         
            +
                      docs/
         
     | 
| 
      
 49 
     | 
    
         
            +
                      script/
         
     | 
| 
      
 50 
     | 
    
         
            +
                      sorbet/
         
     | 
| 
      
 51 
     | 
    
         
            +
                      examples/
         
     | 
| 
      
 52 
     | 
    
         
            +
                    ])
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
              spec.bindir        = 'exe'
         
     | 
| 
      
 56 
     | 
    
         
            +
              spec.executables   = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
         
     | 
| 
      
 57 
     | 
    
         
            +
              spec.require_paths = ['lib']
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              # Runtime dependencies
         
     | 
| 
      
 60 
     | 
    
         
            +
              spec.add_dependency 'activesupport', '>= 6.0'
         
     | 
| 
      
 61 
     | 
    
         
            +
              spec.add_dependency 'caxlsx', '~> 4.0'
         
     | 
| 
      
 62 
     | 
    
         
            +
              spec.add_dependency 'money', '~> 6.0'
         
     | 
| 
      
 63 
     | 
    
         
            +
              spec.add_dependency 'sorbet-runtime', '~> 0.5'
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              # Development dependencies
         
     | 
| 
      
 66 
     | 
    
         
            +
              spec.add_development_dependency 'bundler', '~> 2.0'
         
     | 
| 
      
 67 
     | 
    
         
            +
              spec.add_development_dependency 'rake', '~> 13.0'
         
     | 
| 
      
 68 
     | 
    
         
            +
              spec.add_development_dependency 'rspec', '~> 3.0'
         
     | 
| 
      
 69 
     | 
    
         
            +
              spec.add_development_dependency 'rubocop', '~> 1.72'
         
     | 
| 
      
 70 
     | 
    
         
            +
              spec.add_development_dependency 'rubocop-rspec', '~> 3.5'
         
     | 
| 
      
 71 
     | 
    
         
            +
              spec.add_development_dependency 'sorbet', '~> 0.5'
         
     | 
| 
      
 72 
     | 
    
         
            +
              spec.add_development_dependency 'tapioca', '~> 0.11'
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     |