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/README.md
    ADDED
    
    | 
         @@ -0,0 +1,372 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Zaxcel
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Zaxcel is a Ruby library built on top of [caxlsx](https://github.com/caxlsx/caxlsx) that adds an abstraction layer to building Excel documents. It provides simple methods for building formulas and references to other cells, even across many worksheets, using a clean Ruby DSL without having to think about the underlying Excel implementation.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Philosophy
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            - **Goal**: Enable building Excel sheets in a Ruby-idiomatic DSL without having to think about the underlying Excel. We want to interact with purely Ruby objects in a purely Ruby way while building Excel sheets.
         
     | 
| 
      
 8 
     | 
    
         
            +
            - **Anti-goal**: Reimplementing Excel in Ruby.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 15 
     | 
    
         
            +
            gem 'zaxcel'
         
     | 
| 
      
 16 
     | 
    
         
            +
            ```
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 21 
     | 
    
         
            +
            $ bundle install
         
     | 
| 
      
 22 
     | 
    
         
            +
            ```
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 27 
     | 
    
         
            +
            $ gem install zaxcel
         
     | 
| 
      
 28 
     | 
    
         
            +
            ```
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            ### Requirements
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            - Ruby >= 3.0 (tested up to 3.4)
         
     | 
| 
      
 33 
     | 
    
         
            +
            - Runtime dependencies are managed automatically via Rubygems, but you should have Bundler set up in your project. Zaxcel depends on:
         
     | 
| 
      
 34 
     | 
    
         
            +
              - `caxlsx` (~> 4.0)
         
     | 
| 
      
 35 
     | 
    
         
            +
              - `activesupport` (>= 6.0)
         
     | 
| 
      
 36 
     | 
    
         
            +
              - `money` (~> 6.0)
         
     | 
| 
      
 37 
     | 
    
         
            +
              - `sorbet-runtime` (~> 0.5)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            For running examples directly from the repo, prefer using Bundler:
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 42 
     | 
    
         
            +
            bundle install
         
     | 
| 
      
 43 
     | 
    
         
            +
            bundle exec ruby examples/basic_spreadsheet.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            ```
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ### Basic Example
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 51 
     | 
    
         
            +
            require 'zaxcel'
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            # Create a new document
         
     | 
| 
      
 54 
     | 
    
         
            +
            document = Zaxcel::Document.new
         
     | 
| 
      
 55 
     | 
    
         
            +
            sheet = document.add_sheet!('my_sheet')
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            # Add columns
         
     | 
| 
      
 58 
     | 
    
         
            +
            sheet.add_column!(:column_1)
         
     | 
| 
      
 59 
     | 
    
         
            +
            sheet.add_column!(:column_2)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            # Add rows with data
         
     | 
| 
      
 62 
     | 
    
         
            +
            row_1 = sheet.add_row!(:row_1)
         
     | 
| 
      
 63 
     | 
    
         
            +
              .add!(:column_1, value: 'Row 1')
         
     | 
| 
      
 64 
     | 
    
         
            +
              .add!(:column_2, value: 99)
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            row_2 = sheet.add_row!(:row_2)
         
     | 
| 
      
 67 
     | 
    
         
            +
              .add!(:column_1, value: 'Row 2')
         
     | 
| 
      
 68 
     | 
    
         
            +
              .add!(:column_2, value: 1)
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            # Add a total row with a formula that references other cells
         
     | 
| 
      
 71 
     | 
    
         
            +
            sheet.add_row!(:total)
         
     | 
| 
      
 72 
     | 
    
         
            +
              .add!(:column_1, value: 'Total')
         
     | 
| 
      
 73 
     | 
    
         
            +
              .add!(:column_2, row_1.ref(:column_2) + row_2.ref(:column_2))
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            # Finalize the sheet (position and generate after all content is added)
         
     | 
| 
      
 76 
     | 
    
         
            +
            sheet.position_rows!
         
     | 
| 
      
 77 
     | 
    
         
            +
            sheet.generate_sheet!
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            # Write to file (binary-safe)
         
     | 
| 
      
 80 
     | 
    
         
            +
            data = document.file_contents
         
     | 
| 
      
 81 
     | 
    
         
            +
            raise 'Document had no contents' if data.nil?
         
     | 
| 
      
 82 
     | 
    
         
            +
            File.write('output.xlsx', data, mode: 'wb')
         
     | 
| 
      
 83 
     | 
    
         
            +
            ```
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            ### Working with Formulas
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            Zaxcel makes it easy to build Excel formulas using Ruby operators:
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 90 
     | 
    
         
            +
            # Arithmetic operations
         
     | 
| 
      
 91 
     | 
    
         
            +
            cell_sum = row_1.ref(:amount) + row_2.ref(:amount)
         
     | 
| 
      
 92 
     | 
    
         
            +
            cell_diff = row_1.ref(:amount) - row_2.ref(:amount)
         
     | 
| 
      
 93 
     | 
    
         
            +
            cell_product = row_1.ref(:amount) * row_2.ref(:amount)
         
     | 
| 
      
 94 
     | 
    
         
            +
            cell_quotient = row_1.ref(:amount) / row_2.ref(:amount)
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            # Excel functions
         
     | 
| 
      
 97 
     | 
    
         
            +
            sum_formula = Zaxcel::Functions.sum(
         
     | 
| 
      
 98 
     | 
    
         
            +
              Zaxcel::Lang.range(row_1.ref(:amount), row_10.ref(:amount))
         
     | 
| 
      
 99 
     | 
    
         
            +
            )
         
     | 
| 
      
 100 
     | 
    
         
            +
            average_formula = Zaxcel::Functions::Average.new(
         
     | 
| 
      
 101 
     | 
    
         
            +
              Zaxcel::Lang.range(row_1.ref(:amount), row_10.ref(:amount))
         
     | 
| 
      
 102 
     | 
    
         
            +
            )
         
     | 
| 
      
 103 
     | 
    
         
            +
            max_formula = Zaxcel::Functions.max(
         
     | 
| 
      
 104 
     | 
    
         
            +
              Zaxcel::Lang.range(row_1.ref(:amount), row_10.ref(:amount))
         
     | 
| 
      
 105 
     | 
    
         
            +
            )
         
     | 
| 
      
 106 
     | 
    
         
            +
            min_formula = Zaxcel::Functions.min(
         
     | 
| 
      
 107 
     | 
    
         
            +
              Zaxcel::Lang.range(row_1.ref(:amount), row_10.ref(:amount))
         
     | 
| 
      
 108 
     | 
    
         
            +
            )
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            # Conditional formulas
         
     | 
| 
      
 111 
     | 
    
         
            +
            if_formula = Zaxcel::Lang
         
     | 
| 
      
 112 
     | 
    
         
            +
              .if(row_1.ref(:amount) > 100)
         
     | 
| 
      
 113 
     | 
    
         
            +
              .then('High')
         
     | 
| 
      
 114 
     | 
    
         
            +
              .else('Low')
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            # Rounding
         
     | 
| 
      
 117 
     | 
    
         
            +
            rounded = Zaxcel::Functions.round(row_1.ref(:amount), precision: 2)
         
     | 
| 
      
 118 
     | 
    
         
            +
            ```
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
            ### Cross-Sheet References
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
            One of Zaxcel's strengths is making cross-sheet references easy:
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 125 
     | 
    
         
            +
            document = Zaxcel::Document.new
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
            # Create first sheet with data
         
     | 
| 
      
 128 
     | 
    
         
            +
            data_sheet = document.add_sheet!('Data')
         
     | 
| 
      
 129 
     | 
    
         
            +
            data_sheet.add_column!(:category)
         
     | 
| 
      
 130 
     | 
    
         
            +
            data_sheet.add_column!(:value)
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
            row_1 = data_sheet.add_row!(:row_1)
         
     | 
| 
      
 133 
     | 
    
         
            +
              .add!(:category, value: 'Sales')
         
     | 
| 
      
 134 
     | 
    
         
            +
              .add!(:value, value: 1000)
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
            # Create summary sheet that references the data sheet
         
     | 
| 
      
 137 
     | 
    
         
            +
            summary_sheet = document.add_sheet!('Summary')
         
     | 
| 
      
 138 
     | 
    
         
            +
            summary_sheet.add_column!(:description)
         
     | 
| 
      
 139 
     | 
    
         
            +
            summary_sheet.add_column!(:amount)
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
            summary_sheet.add_row!(:sales_summary)
         
     | 
| 
      
 142 
     | 
    
         
            +
              .add!(:description, value: 'Total Sales')
         
     | 
| 
      
 143 
     | 
    
         
            +
              .add!(:amount, data_sheet.cell_ref(:value, :row_1))
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
            # Position and generate all sheets at once (after all content is added)
         
     | 
| 
      
 146 
     | 
    
         
            +
            # This allows bidirectional references between sheets
         
     | 
| 
      
 147 
     | 
    
         
            +
            document.sheet_by_name.values.each do |sheet|
         
     | 
| 
      
 148 
     | 
    
         
            +
              sheet.position_rows!
         
     | 
| 
      
 149 
     | 
    
         
            +
              sheet.generate_sheet!
         
     | 
| 
      
 150 
     | 
    
         
            +
            end
         
     | 
| 
      
 151 
     | 
    
         
            +
            ```
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
            ### Styling
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            Apply styles to cells and columns:
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 158 
     | 
    
         
            +
            # Define styles
         
     | 
| 
      
 159 
     | 
    
         
            +
            document.add_style!(:header, {
         
     | 
| 
      
 160 
     | 
    
         
            +
              bg_color: '0066CC',
         
     | 
| 
      
 161 
     | 
    
         
            +
              fg_color: 'FFFFFF',
         
     | 
| 
      
 162 
     | 
    
         
            +
              b: true,
         
     | 
| 
      
 163 
     | 
    
         
            +
              alignment: { horizontal: :center }
         
     | 
| 
      
 164 
     | 
    
         
            +
            })
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
            document.add_style!(:currency, {
         
     | 
| 
      
 167 
     | 
    
         
            +
              format_code: '$#,##0.00'
         
     | 
| 
      
 168 
     | 
    
         
            +
            })
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
            document.add_style!(:percentage, {
         
     | 
| 
      
 171 
     | 
    
         
            +
              format_code: '0.00%'
         
     | 
| 
      
 172 
     | 
    
         
            +
            })
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
            # Apply to cells
         
     | 
| 
      
 175 
     | 
    
         
            +
            sheet.add_row!(:header)
         
     | 
| 
      
 176 
     | 
    
         
            +
              .add!(:name, value: 'Product', style: :header)
         
     | 
| 
      
 177 
     | 
    
         
            +
              .add!(:price, value: 'Price', style: :header)
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
            sheet.add_row!(:product_1)
         
     | 
| 
      
 180 
     | 
    
         
            +
              .add!(:name, value: 'Widget')
         
     | 
| 
      
 181 
     | 
    
         
            +
              .add!(:price, value: 19.99, style: :currency)
         
     | 
| 
      
 182 
     | 
    
         
            +
            ```
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
            ### Column Configuration
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
            Configure column widths and other properties:
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 189 
     | 
    
         
            +
            sheet.add_column!(:narrow, width: 10)
         
     | 
| 
      
 190 
     | 
    
         
            +
            sheet.add_column!(:wide, width: 30)
         
     | 
| 
      
 191 
     | 
    
         
            +
            sheet.add_column!(:auto, width: nil)  # Let caxlsx auto-calc width from contents
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
            # Or use computed widths
         
     | 
| 
      
 194 
     | 
    
         
            +
            sheet.add_column!(
         
     | 
| 
      
 195 
     | 
    
         
            +
              :fit_header,
         
     | 
| 
      
 196 
     | 
    
         
            +
              width: Zaxcel::Column::ComputedColumnWidth::Header,
         
     | 
| 
      
 197 
     | 
    
         
            +
            )
         
     | 
| 
      
 198 
     | 
    
         
            +
            sheet.add_column!(
         
     | 
| 
      
 199 
     | 
    
         
            +
              :fit_content,
         
     | 
| 
      
 200 
     | 
    
         
            +
              width: Zaxcel::Column::ComputedColumnWidth::MaxContent,
         
     | 
| 
      
 201 
     | 
    
         
            +
            )
         
     | 
| 
      
 202 
     | 
    
         
            +
            ```
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
            ### Advanced Features
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
            #### SUMIF and SUMIFS
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 209 
     | 
    
         
            +
            # Sum values where a condition is met
         
     | 
| 
      
 210 
     | 
    
         
            +
            sum_if = Zaxcel::Functions.sum_if(
         
     | 
| 
      
 211 
     | 
    
         
            +
              column_to_check: category_column,
         
     | 
| 
      
 212 
     | 
    
         
            +
              value_to_check: 'Sales',
         
     | 
| 
      
 213 
     | 
    
         
            +
              column_to_sum: amount_column,
         
     | 
| 
      
 214 
     | 
    
         
            +
            )
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
            # Sum with multiple conditions
         
     | 
| 
      
 217 
     | 
    
         
            +
            sum_ifs = Zaxcel::Functions.sum_ifs(
         
     | 
| 
      
 218 
     | 
    
         
            +
              ranges_to_check: [
         
     | 
| 
      
 219 
     | 
    
         
            +
                Zaxcel::Lang.range(category_column),
         
     | 
| 
      
 220 
     | 
    
         
            +
                Zaxcel::Lang.range(region_column),
         
     | 
| 
      
 221 
     | 
    
         
            +
              ],
         
     | 
| 
      
 222 
     | 
    
         
            +
              values_to_check: ['Sales', 'West'],
         
     | 
| 
      
 223 
     | 
    
         
            +
              range_to_sum: Zaxcel::Lang.range(amount_column),
         
     | 
| 
      
 224 
     | 
    
         
            +
            )
         
     | 
| 
      
 225 
     | 
    
         
            +
            ```
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
            #### XLOOKUP and INDEX/MATCH
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 230 
     | 
    
         
            +
            # Modern XLOOKUP
         
     | 
| 
      
 231 
     | 
    
         
            +
            lookup = Zaxcel::Functions.x_lookup(
         
     | 
| 
      
 232 
     | 
    
         
            +
              'Product A',
         
     | 
| 
      
 233 
     | 
    
         
            +
              idx_range: Zaxcel::Lang.range(product_column),
         
     | 
| 
      
 234 
     | 
    
         
            +
              value_range: Zaxcel::Lang.range(price_column),
         
     | 
| 
      
 235 
     | 
    
         
            +
            )
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
            # Traditional INDEX/MATCH
         
     | 
| 
      
 238 
     | 
    
         
            +
            match = Zaxcel::Functions.match(
         
     | 
| 
      
 239 
     | 
    
         
            +
              value: 'Product A',
         
     | 
| 
      
 240 
     | 
    
         
            +
              range: Zaxcel::Lang.range(product_column),
         
     | 
| 
      
 241 
     | 
    
         
            +
              match_type: Zaxcel::Functions::Match::MatchType::EXACT,
         
     | 
| 
      
 242 
     | 
    
         
            +
            )
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
            index = Zaxcel::Functions.index(
         
     | 
| 
      
 245 
     | 
    
         
            +
              index_value: match,
         
     | 
| 
      
 246 
     | 
    
         
            +
              range: price_column,
         
     | 
| 
      
 247 
     | 
    
         
            +
            )
         
     | 
| 
      
 248 
     | 
    
         
            +
            ```
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
            #### Conditional Logic
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 253 
     | 
    
         
            +
            # Build conditional logic
         
     | 
| 
      
 254 
     | 
    
         
            +
            status = Zaxcel::Lang
         
     | 
| 
      
 255 
     | 
    
         
            +
              .if(row.ref(:amount) > 1000)
         
     | 
| 
      
 256 
     | 
    
         
            +
              .then('High')
         
     | 
| 
      
 257 
     | 
    
         
            +
              .else('Low')
         
     | 
| 
      
 258 
     | 
    
         
            +
            ```
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
            ### Sheet Visibility
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
            Control whether sheets are visible:
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 265 
     | 
    
         
            +
            # Create a hidden sheet
         
     | 
| 
      
 266 
     | 
    
         
            +
            hidden_sheet = document.add_sheet!(
         
     | 
| 
      
 267 
     | 
    
         
            +
              'Calculations',
         
     | 
| 
      
 268 
     | 
    
         
            +
              sheet_visibility: Zaxcel::Sheet::SheetVisibility::Hidden
         
     | 
| 
      
 269 
     | 
    
         
            +
            )
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
            # Create a visible sheet (default)
         
     | 
| 
      
 272 
     | 
    
         
            +
            visible_sheet = document.add_sheet!(
         
     | 
| 
      
 273 
     | 
    
         
            +
              'Report',
         
     | 
| 
      
 274 
     | 
    
         
            +
              sheet_visibility: Zaxcel::Sheet::SheetVisibility::Visible
         
     | 
| 
      
 275 
     | 
    
         
            +
            )
         
     | 
| 
      
 276 
     | 
    
         
            +
            ```
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
            ## API Documentation
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
            ### Core Classes
         
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
            #### `Zaxcel::Document`
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
            The main container for your Excel workbook.
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
            - `new(width_units_by_default_character: Float)` - Create a new document
         
     | 
| 
      
 287 
     | 
    
         
            +
            - `add_sheet!(name, sheet_visibility: SheetVisibility)` - Add a new worksheet
         
     | 
| 
      
 288 
     | 
    
         
            +
            - `add_style!(name, **kwargs)` - Define a named style
         
     | 
| 
      
 289 
     | 
    
         
            +
            - `sheet(name)` - Get a sheet by name
         
     | 
| 
      
 290 
     | 
    
         
            +
            - `file_contents` - Get the binary Excel file content
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
            #### `Zaxcel::Sheet`
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
            Represents a worksheet within the document.
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
            - `add_column!(name, width: nil)` - Add a column (use `nil` for auto width; or `Zaxcel::Column::ComputedColumnWidth`)
         
     | 
| 
      
 297 
     | 
    
         
            +
            - `add_row!(name, style_group: nil)` - Add a row
         
     | 
| 
      
 298 
     | 
    
         
            +
            - `cell_ref(row_name, col_name, sheet_name: nil)` - Get a reference to a cell
         
     | 
| 
      
 299 
     | 
    
         
            +
            - `position_rows!` then `generate_sheet!` - Finalize the sheet (call before writing)
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
            #### `Zaxcel::Row`
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
            Represents a row within a sheet.
         
     | 
| 
      
 304 
     | 
    
         
            +
             
     | 
| 
      
 305 
     | 
    
         
            +
            - `add!(column_name, value:, style: nil, to_extract: false)` - Add a cell value
         
     | 
| 
      
 306 
     | 
    
         
            +
            - `add_many!(hash)` - Add multiple cells at once
         
     | 
| 
      
 307 
     | 
    
         
            +
            - `ref(column_name)` - Get a reference to a cell in this row
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
            #### `Zaxcel::Column`
         
     | 
| 
      
 310 
     | 
    
         
            +
             
     | 
| 
      
 311 
     | 
    
         
            +
            Represents a column within a sheet.
         
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
            ### Functions Module
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
            All Excel functions are available under `Zaxcel::Functions`:
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
            - `abs(value)` - Absolute value
         
     | 
| 
      
 318 
     | 
    
         
            +
            - `sum(*values_or_ranges)` - Sum values and/or ranges
         
     | 
| 
      
 319 
     | 
    
         
            +
            - `sum_range([first_ref, last_ref])` - Sum a contiguous range (convenience)
         
     | 
| 
      
 320 
     | 
    
         
            +
            - `sum_if(column_to_check:, value_to_check:, column_to_sum:)`
         
     | 
| 
      
 321 
     | 
    
         
            +
            - `sum_ifs(ranges_to_check:, values_to_check:, range_to_sum:)`
         
     | 
| 
      
 322 
     | 
    
         
            +
            - `average(range)` - Average of a contiguous range
         
     | 
| 
      
 323 
     | 
    
         
            +
            - `max(*values_or_ranges)` - Maximum value
         
     | 
| 
      
 324 
     | 
    
         
            +
            - `min(*values_or_ranges)` - Minimum value
         
     | 
| 
      
 325 
     | 
    
         
            +
            - `round(value, precision:)` - Round to decimal places
         
     | 
| 
      
 326 
     | 
    
         
            +
            - `and(lhs, rhs)` / `or(lhs, rhs)` - Logical operations
         
     | 
| 
      
 327 
     | 
    
         
            +
            - `concatenate(*values)` - Join strings
         
     | 
| 
      
 328 
     | 
    
         
            +
            - `text(value, format_string:)` - Format value as text
         
     | 
| 
      
 329 
     | 
    
         
            +
            - `len(value)` - String length
         
     | 
| 
      
 330 
     | 
    
         
            +
            - `x_lookup(condition, idx_range:, value_range:)`
         
     | 
| 
      
 331 
     | 
    
         
            +
            - `index(index_value:, range:)`
         
     | 
| 
      
 332 
     | 
    
         
            +
            - `match(value:, range:, match_type:)` with `MatchType::EXACT`, `LESS_THAN_OR_EQUAL`, `GREATER_THAN_OR_EQUAL`
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
            ## Development
         
     | 
| 
      
 335 
     | 
    
         
            +
             
     | 
| 
      
 336 
     | 
    
         
            +
            After checking out the repo, run:
         
     | 
| 
      
 337 
     | 
    
         
            +
             
     | 
| 
      
 338 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 339 
     | 
    
         
            +
            bundle install
         
     | 
| 
      
 340 
     | 
    
         
            +
            ```
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
            Run the test suite:
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 345 
     | 
    
         
            +
            bundle exec rspec
         
     | 
| 
      
 346 
     | 
    
         
            +
            ```
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
            Run type checking:
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 351 
     | 
    
         
            +
            bundle exec srb tc
         
     | 
| 
      
 352 
     | 
    
         
            +
            ```
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/angellist/zaxcel.
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
            1. Fork it
         
     | 
| 
      
 359 
     | 
    
         
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
      
 360 
     | 
    
         
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         
     | 
| 
      
 361 
     | 
    
         
            +
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
      
 362 
     | 
    
         
            +
            5. Create a new Pull Request
         
     | 
| 
      
 363 
     | 
    
         
            +
             
     | 
| 
      
 364 
     | 
    
         
            +
            ## License
         
     | 
| 
      
 365 
     | 
    
         
            +
             
     | 
| 
      
 366 
     | 
    
         
            +
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         
     | 
| 
      
 367 
     | 
    
         
            +
             
     | 
| 
      
 368 
     | 
    
         
            +
            ## Credits
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
            Created by the engineering team at [AngelList](https://www.angellist.com).
         
     | 
| 
      
 371 
     | 
    
         
            +
             
     | 
| 
      
 372 
     | 
    
         
            +
            Built on top of the excellent [caxlsx](https://github.com/caxlsx/caxlsx) library.
         
     | 
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'bundler/gem_tasks'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rspec/core/rake_task'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'rubocop/rake_task'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            RSpec::Core::RakeTask.new(:spec)
         
     | 
| 
      
 8 
     | 
    
         
            +
            RuboCop::RakeTask.new
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            desc 'Run Sorbet type checker'
         
     | 
| 
      
 11 
     | 
    
         
            +
            task sorbet: :environment do
         
     | 
| 
      
 12 
     | 
    
         
            +
              sh 'bundle exec srb tc'
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            desc 'Run all checks (tests, linting, type checking)'
         
     | 
| 
      
 16 
     | 
    
         
            +
            task checks: [:spec, :rubocop, :sorbet]
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            task default: :checks
         
     | 
    
        data/SETUP.md
    ADDED
    
    | 
         @@ -0,0 +1,178 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Zaxcel - Setup Guide for Open Sourcing
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            This directory contains a complete, standalone Ruby gem for Zaxcel that's ready to be open-sourced.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## What's Included
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            ### Core Files
         
     | 
| 
      
 8 
     | 
    
         
            +
            - `lib/zaxcel/` - All source code copied from the Venture codebase
         
     | 
| 
      
 9 
     | 
    
         
            +
            - `lib/zaxcel.rb` - Main entry point with proper requires
         
     | 
| 
      
 10 
     | 
    
         
            +
            - `zaxcel.gemspec` - Gem specification with dependencies
         
     | 
| 
      
 11 
     | 
    
         
            +
            - `Gemfile` - Development dependencies
         
     | 
| 
      
 12 
     | 
    
         
            +
            - `Rakefile` - Build and test tasks
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            ### Documentation
         
     | 
| 
      
 15 
     | 
    
         
            +
            - `README.md` - Comprehensive user documentation with examples
         
     | 
| 
      
 16 
     | 
    
         
            +
            - `CHANGELOG.md` - Version history (template)
         
     | 
| 
      
 17 
     | 
    
         
            +
            - `CONTRIBUTING.md` - Contribution guidelines
         
     | 
| 
      
 18 
     | 
    
         
            +
            - `LICENSE` - MIT License
         
     | 
| 
      
 19 
     | 
    
         
            +
            - `SETUP.md` - This file
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ### Testing
         
     | 
| 
      
 22 
     | 
    
         
            +
            - `spec/spec_helper.rb` - RSpec configuration
         
     | 
| 
      
 23 
     | 
    
         
            +
            - `spec/zaxcel/document_spec.rb` - Document tests
         
     | 
| 
      
 24 
     | 
    
         
            +
            - `spec/zaxcel/functions_spec.rb` - Functions tests
         
     | 
| 
      
 25 
     | 
    
         
            +
            - `.rspec` - RSpec configuration
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            ### Examples
         
     | 
| 
      
 28 
     | 
    
         
            +
            - `examples/basic_spreadsheet.rb` - Simple sales report example
         
     | 
| 
      
 29 
     | 
    
         
            +
            - `examples/cross_sheet_references.rb` - Multi-sheet example
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            ### Configuration
         
     | 
| 
      
 32 
     | 
    
         
            +
            - `.gitignore` - Files to ignore in git
         
     | 
| 
      
 33 
     | 
    
         
            +
            - `.rubocop.yml` - Ruby style configuration
         
     | 
| 
      
 34 
     | 
    
         
            +
            - `sorbet/config` - Sorbet type checker configuration
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            ### CI/CD
         
     | 
| 
      
 37 
     | 
    
         
            +
            - `.github/workflows/ci.yml` - GitHub Actions for testing
         
     | 
| 
      
 38 
     | 
    
         
            +
            - `.github/workflows/release.yml` - Automated gem publishing
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            ## Steps to Open Source
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ### 1. Review and Approval (REQUIRED)
         
     | 
| 
      
 43 
     | 
    
         
            +
            - [ ] Get legal approval from AngelList to open-source
         
     | 
| 
      
 44 
     | 
    
         
            +
            - [ ] Verify no proprietary information or secrets in code
         
     | 
| 
      
 45 
     | 
    
         
            +
            - [ ] Update LICENSE file if needed (currently MIT)
         
     | 
| 
      
 46 
     | 
    
         
            +
            - [ ] Update copyright year and company name if needed
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ### 2. Create GitHub Repository
         
     | 
| 
      
 49 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 50 
     | 
    
         
            +
            # On GitHub, create a new repository: angellist/zaxcel
         
     | 
| 
      
 51 
     | 
    
         
            +
            # Then locally:
         
     | 
| 
      
 52 
     | 
    
         
            +
            cd zaxcel_gem
         
     | 
| 
      
 53 
     | 
    
         
            +
            git init
         
     | 
| 
      
 54 
     | 
    
         
            +
            git add .
         
     | 
| 
      
 55 
     | 
    
         
            +
            git commit -m "Initial commit"
         
     | 
| 
      
 56 
     | 
    
         
            +
            git branch -M main
         
     | 
| 
      
 57 
     | 
    
         
            +
            git remote add origin git@github.com:angellist/zaxcel.git
         
     | 
| 
      
 58 
     | 
    
         
            +
            git push -u origin main
         
     | 
| 
      
 59 
     | 
    
         
            +
            ```
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            ### 3. Set Up Repository Settings
         
     | 
| 
      
 62 
     | 
    
         
            +
            - Add repository description: "A Ruby DSL for building Excel spreadsheets programmatically"
         
     | 
| 
      
 63 
     | 
    
         
            +
            - Add topics: ruby, excel, spreadsheet, caxlsx, dsl
         
     | 
| 
      
 64 
     | 
    
         
            +
            - Set up branch protection for main
         
     | 
| 
      
 65 
     | 
    
         
            +
            - Configure required status checks
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            ### 4. Test Locally
         
     | 
| 
      
 68 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 69 
     | 
    
         
            +
            cd zaxcel_gem
         
     | 
| 
      
 70 
     | 
    
         
            +
            bundle install
         
     | 
| 
      
 71 
     | 
    
         
            +
            bundle exec rspec
         
     | 
| 
      
 72 
     | 
    
         
            +
            bundle exec rubocop
         
     | 
| 
      
 73 
     | 
    
         
            +
            bundle exec srb tc
         
     | 
| 
      
 74 
     | 
    
         
            +
            ```
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            ### 5. Update Dependencies (Optional)
         
     | 
| 
      
 77 
     | 
    
         
            +
            Review if you want to make any dependencies optional:
         
     | 
| 
      
 78 
     | 
    
         
            +
            - `money` gem - Used in type definitions, could be made optional
         
     | 
| 
      
 79 
     | 
    
         
            +
            - `activesupport` - Consider minimizing dependency or making optional
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            ### 6. Set Up RubyGems Account
         
     | 
| 
      
 82 
     | 
    
         
            +
            - Create account at https://rubygems.org if needed
         
     | 
| 
      
 83 
     | 
    
         
            +
            - Get API key from account settings
         
     | 
| 
      
 84 
     | 
    
         
            +
            - Add as GitHub secret: `RUBYGEMS_API_KEY`
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            ### 7. Publish First Release
         
     | 
| 
      
 87 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 88 
     | 
    
         
            +
            # Update version in lib/zaxcel.rb if needed
         
     | 
| 
      
 89 
     | 
    
         
            +
            # Update CHANGELOG.md with release date
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            git tag -a v1.0.0 -m "First public release"
         
     | 
| 
      
 92 
     | 
    
         
            +
            git push origin v1.0.0
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
            # Or build and publish manually:
         
     | 
| 
      
 95 
     | 
    
         
            +
            gem build zaxcel.gemspec
         
     | 
| 
      
 96 
     | 
    
         
            +
            gem push zaxcel-1.0.0.gem
         
     | 
| 
      
 97 
     | 
    
         
            +
            ```
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            ### 8. Post-Release Tasks
         
     | 
| 
      
 100 
     | 
    
         
            +
            - [ ] Announce on Ruby Weekly
         
     | 
| 
      
 101 
     | 
    
         
            +
            - [ ] Write blog post on AngelList engineering blog
         
     | 
| 
      
 102 
     | 
    
         
            +
            - [ ] Share on social media
         
     | 
| 
      
 103 
     | 
    
         
            +
            - [ ] Submit to Ruby Toolbox
         
     | 
| 
      
 104 
     | 
    
         
            +
            - [ ] Monitor GitHub issues
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
            ### 9. Update Venture Codebase
         
     | 
| 
      
 107 
     | 
    
         
            +
            After the gem is published, update the main Venture repository:
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 110 
     | 
    
         
            +
            # In Gemfile
         
     | 
| 
      
 111 
     | 
    
         
            +
            gem 'zaxcel', '~> 1.0'
         
     | 
| 
      
 112 
     | 
    
         
            +
            ```
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
            Then remove `lib/zaxcel/` from Venture.
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            ## Before Publishing Checklist
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
            - [ ] Legal approval obtained
         
     | 
| 
      
 119 
     | 
    
         
            +
            - [ ] No secrets or proprietary code
         
     | 
| 
      
 120 
     | 
    
         
            +
            - [ ] Tests pass locally
         
     | 
| 
      
 121 
     | 
    
         
            +
            - [ ] Documentation is complete
         
     | 
| 
      
 122 
     | 
    
         
            +
            - [ ] Examples work correctly
         
     | 
| 
      
 123 
     | 
    
         
            +
            - [ ] LICENSE file is correct
         
     | 
| 
      
 124 
     | 
    
         
            +
            - [ ] CHANGELOG is updated
         
     | 
| 
      
 125 
     | 
    
         
            +
            - [ ] Version number is set
         
     | 
| 
      
 126 
     | 
    
         
            +
            - [ ] GitHub repository created
         
     | 
| 
      
 127 
     | 
    
         
            +
            - [ ] RubyGems account set up
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            ## Testing the Gem Locally
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
            To test the gem before publishing:
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 134 
     | 
    
         
            +
            cd zaxcel_gem
         
     | 
| 
      
 135 
     | 
    
         
            +
            gem build zaxcel.gemspec
         
     | 
| 
      
 136 
     | 
    
         
            +
            gem install zaxcel-1.0.0.gem
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
            # Try running examples
         
     | 
| 
      
 139 
     | 
    
         
            +
            ruby examples/basic_spreadsheet.rb
         
     | 
| 
      
 140 
     | 
    
         
            +
            ruby examples/cross_sheet_references.rb
         
     | 
| 
      
 141 
     | 
    
         
            +
            ```
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
            ## Potential Issues to Address
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
            1. **ActiveSupport Dependency**: The gem currently requires ActiveSupport for methods like `try`, `blank?`, and `parameterize`. Consider either:
         
     | 
| 
      
 146 
     | 
    
         
            +
               - Keeping it as a dependency (simplest)
         
     | 
| 
      
 147 
     | 
    
         
            +
               - Implementing these methods internally
         
     | 
| 
      
 148 
     | 
    
         
            +
               - Making it optional
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
            2. **Money Gem**: Used in type definitions but may not be essential. Consider making it optional.
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
            3. **Sorbet RBI Files**: May need to generate RBI files for dependencies:
         
     | 
| 
      
 153 
     | 
    
         
            +
               ```bash
         
     | 
| 
      
 154 
     | 
    
         
            +
               bundle exec tapioca init
         
     | 
| 
      
 155 
     | 
    
         
            +
               bundle exec tapioca gems
         
     | 
| 
      
 156 
     | 
    
         
            +
               ```
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
            4. **Documentation Site**: Consider setting up GitHub Pages for better documentation.
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            5. **Versioning**: Start with 1.0.0 or consider 0.1.0 for initial release.
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            ## Maintenance Plan
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
            After open-sourcing:
         
     | 
| 
      
 165 
     | 
    
         
            +
            - Respond to issues within 48 hours
         
     | 
| 
      
 166 
     | 
    
         
            +
            - Review PRs weekly
         
     | 
| 
      
 167 
     | 
    
         
            +
            - Release bug fixes promptly
         
     | 
| 
      
 168 
     | 
    
         
            +
            - Plan quarterly feature releases
         
     | 
| 
      
 169 
     | 
    
         
            +
            - Keep dependencies updated
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            ## Questions or Issues?
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
            If you encounter any issues during the open-sourcing process, document them here or create issues in the repository.
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
            ## Contact
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
            For questions about this gem: engineering@angellist.com
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
    
        data/lib/enumerable.rb
    ADDED
    
    | 
         @@ -0,0 +1,47 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
            # typed: false
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            # sigs and typing for these methods are defined in a separate rbi file
         
     | 
| 
      
 5 
     | 
    
         
            +
            # sorbet/rbi/core/enumerable.rbi
         
     | 
| 
      
 6 
     | 
    
         
            +
            module Enumerable
         
     | 
| 
      
 7 
     | 
    
         
            +
              include Kernel
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              def first!
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_not_nil!(first)
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def last!
         
     | 
| 
      
 14 
     | 
    
         
            +
                assert_not_nil!(last)
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              def find!(&blk)
         
     | 
| 
      
 18 
     | 
    
         
            +
                assert_not_nil!(find(&blk))
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              def detect!(&blk)
         
     | 
| 
      
 22 
     | 
    
         
            +
                find!(&blk)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              def min!
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert_not_nil!(min)
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              def max!
         
     | 
| 
      
 30 
     | 
    
         
            +
                assert_not_nil!(max)
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              def max_by!(&blk)
         
     | 
| 
      
 34 
     | 
    
         
            +
                assert_not_nil!(max_by(&blk))
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              private
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def assert_not_nil!(item)
         
     | 
| 
      
 40 
     | 
    
         
            +
                case item
         
     | 
| 
      
 41 
     | 
    
         
            +
                when NilClass
         
     | 
| 
      
 42 
     | 
    
         
            +
                  raise "No items in #{self.class}"
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                item
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Zaxcel (Zach's Excel)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Zaxcel is a ruby library built on top of (c)axlsx that adds an abstraction layer to building excel documents. It add simple methods for building formulas and references to other cells, even across many worksheets.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              * The goal of Zaxcel is to enable building excel sheets in a ruby idiomatic DSL without having to think about the underlying excel. We want to interact with purely Ruby objects in a purely Ruby way while building excel sheets.
         
     | 
| 
      
 6 
     | 
    
         
            +
              * Reimplementing Excel in Ruby is an explicit anti-goal.
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            ### How to use Zaxcel
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 11 
     | 
    
         
            +
            document = Zaxcel::Document.new
         
     | 
| 
      
 12 
     | 
    
         
            +
            my_sheet = document.add_sheet!('my_sheet')
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            my_sheet.add_column!(:column_1)
         
     | 
| 
      
 15 
     | 
    
         
            +
            my_sheet.add_column!(:column_2)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            row_1 = my_sheet.add_row!(:row_1).add!(:column_1, value: 'Row 1').add!(:column_2, value: 99)
         
     | 
| 
      
 18 
     | 
    
         
            +
            row_2 = my_sheet.add_row!(:row_2).add!(:column_1, value: 'Row 2').add!(:column_2, value: 1)
         
     | 
| 
      
 19 
     | 
    
         
            +
            my_sheet.add_row!(:total).add!(:column_1, value: 'Total').add!(:column_2, row_1.ref(:column_2) + row_2.ref(:column_2))
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            my_sheet.generate_sheet!
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            file = Tempfile.new('my_file.xlsx', encoding: 'ASCII-8BIT')
         
     | 
| 
      
 24 
     | 
    
         
            +
            file.write(document.file_contents)
         
     | 
| 
      
 25 
     | 
    
         
            +
            file.close
         
     | 
| 
      
 26 
     | 
    
         
            +
            ```
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            ### Todo
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            1. Implement more expressive methods to eliminate unnecessary typing.
         
     | 
| 
      
 31 
     | 
    
         
            +
               `(row.ref(:fair_value) / end_balances_cell).round(precision: 4)`
         
     | 
| 
      
 32 
     | 
    
         
            +
            2. More expressive styling apis.
         
     | 
| 
      
 33 
     | 
    
         
            +
            3. Different underlying implementations.
         
     | 
| 
      
 34 
     | 
    
         
            +
               Right now we use CAXLSX to "print" excel sheets. But there's no reason we couldn't use google sheets or excel api under the hood to print direct to other end sources.
         
     | 
| 
      
 35 
     | 
    
         
            +
            4. Can we read sheets into Zaxcel in a reasonable way?
         
     | 
| 
      
 36 
     | 
    
         
            +
            5. clean up references api
         
     | 
| 
      
 37 
     | 
    
         
            +
            6. Launch gem!
         
     |