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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +4 -0
  3. data/.rubocop.yml +9 -0
  4. data/CHANGELOG.md +29 -0
  5. data/CONTRIBUTING.md +110 -0
  6. data/LICENSE +22 -0
  7. data/QUICK_START.md +187 -0
  8. data/README.md +372 -0
  9. data/Rakefile +18 -0
  10. data/SETUP.md +178 -0
  11. data/lib/enumerable.rb +47 -0
  12. data/lib/zaxcel/README.md +37 -0
  13. data/lib/zaxcel/arithmetic.rb +88 -0
  14. data/lib/zaxcel/binary_expression.rb +74 -0
  15. data/lib/zaxcel/binary_expressions/addition.rb +36 -0
  16. data/lib/zaxcel/binary_expressions/division.rb +24 -0
  17. data/lib/zaxcel/binary_expressions/multiplication.rb +24 -0
  18. data/lib/zaxcel/binary_expressions/subtraction.rb +41 -0
  19. data/lib/zaxcel/binary_expressions.rb +38 -0
  20. data/lib/zaxcel/cell.rb +141 -0
  21. data/lib/zaxcel/cell_formula.rb +16 -0
  22. data/lib/zaxcel/column.rb +142 -0
  23. data/lib/zaxcel/document.rb +136 -0
  24. data/lib/zaxcel/function.rb +6 -0
  25. data/lib/zaxcel/functions/abs.rb +18 -0
  26. data/lib/zaxcel/functions/and.rb +23 -0
  27. data/lib/zaxcel/functions/average.rb +17 -0
  28. data/lib/zaxcel/functions/choose.rb +20 -0
  29. data/lib/zaxcel/functions/concatenate.rb +20 -0
  30. data/lib/zaxcel/functions/if.rb +38 -0
  31. data/lib/zaxcel/functions/if_error.rb +25 -0
  32. data/lib/zaxcel/functions/index.rb +20 -0
  33. data/lib/zaxcel/functions/len.rb +16 -0
  34. data/lib/zaxcel/functions/match/match_type.rb +13 -0
  35. data/lib/zaxcel/functions/match.rb +27 -0
  36. data/lib/zaxcel/functions/max.rb +17 -0
  37. data/lib/zaxcel/functions/min.rb +17 -0
  38. data/lib/zaxcel/functions/negate.rb +26 -0
  39. data/lib/zaxcel/functions/or.rb +23 -0
  40. data/lib/zaxcel/functions/round.rb +20 -0
  41. data/lib/zaxcel/functions/sum.rb +18 -0
  42. data/lib/zaxcel/functions/sum_if.rb +20 -0
  43. data/lib/zaxcel/functions/sum_ifs.rb +34 -0
  44. data/lib/zaxcel/functions/sum_product.rb +18 -0
  45. data/lib/zaxcel/functions/text.rb +17 -0
  46. data/lib/zaxcel/functions/unique.rb +23 -0
  47. data/lib/zaxcel/functions/x_lookup.rb +28 -0
  48. data/lib/zaxcel/functions/xirr.rb +27 -0
  49. data/lib/zaxcel/functions.rb +169 -0
  50. data/lib/zaxcel/if_builder.rb +22 -0
  51. data/lib/zaxcel/lang.rb +23 -0
  52. data/lib/zaxcel/reference.rb +28 -0
  53. data/lib/zaxcel/references/cell.rb +42 -0
  54. data/lib/zaxcel/references/column.rb +49 -0
  55. data/lib/zaxcel/references/range.rb +35 -0
  56. data/lib/zaxcel/references/row.rb +34 -0
  57. data/lib/zaxcel/references.rb +5 -0
  58. data/lib/zaxcel/roundable.rb +14 -0
  59. data/lib/zaxcel/row.rb +93 -0
  60. data/lib/zaxcel/sheet.rb +425 -0
  61. data/lib/zaxcel/sorbet/enumerizable_enum.rb +50 -0
  62. data/lib/zaxcel/version.rb +6 -0
  63. data/lib/zaxcel.rb +73 -0
  64. data/zaxcel.gemspec +73 -0
  65. 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!