xlsxrb 0.1.3 → 0.1.5

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +2 -1
  3. data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +9 -0
  4. data/.gem_rbs_collection/ast/2.4/ast.rbs +73 -0
  5. data/.gem_rbs_collection/concurrent-ruby/1.1/.rbs_meta.yaml +9 -0
  6. data/.gem_rbs_collection/concurrent-ruby/1.1/array.rbs +4 -0
  7. data/.gem_rbs_collection/concurrent-ruby/1.1/atomic_reference.rbs +16 -0
  8. data/.gem_rbs_collection/concurrent-ruby/1.1/executor.rbs +96 -0
  9. data/.gem_rbs_collection/concurrent-ruby/1.1/hash.rbs +4 -0
  10. data/.gem_rbs_collection/concurrent-ruby/1.1/map.rbs +68 -0
  11. data/.gem_rbs_collection/concurrent-ruby/1.1/promises.rbs +249 -0
  12. data/.gem_rbs_collection/concurrent-ruby/1.1/set.rbs +4 -0
  13. data/.gem_rbs_collection/concurrent-ruby/1.1/timer_task.rbs +47 -0
  14. data/.gem_rbs_collection/concurrent-ruby/1.1/utility/processor_counter.rbs +5 -0
  15. data/.gem_rbs_collection/csv/3.3/.rbs_meta.yaml +9 -0
  16. data/.gem_rbs_collection/csv/3.3/csv.rbs +3871 -0
  17. data/.gem_rbs_collection/csv/3.3/manifest.yaml +3 -0
  18. data/.gem_rbs_collection/lint_roller/1.1/.rbs_meta.yaml +9 -0
  19. data/.gem_rbs_collection/lint_roller/1.1/lint_roller.rbs +48 -0
  20. data/.gem_rbs_collection/listen/3.9/.rbs_meta.yaml +9 -0
  21. data/.gem_rbs_collection/listen/3.9/listen.rbs +25 -0
  22. data/.gem_rbs_collection/listen/3.9/listener.rbs +24 -0
  23. data/.gem_rbs_collection/logger/1.7/.rbs_meta.yaml +9 -0
  24. data/.gem_rbs_collection/logger/1.7/formatter.rbs +45 -0
  25. data/.gem_rbs_collection/logger/1.7/log_device.rbs +100 -0
  26. data/.gem_rbs_collection/logger/1.7/logger.rbs +796 -0
  27. data/.gem_rbs_collection/logger/1.7/manifest.yaml +2 -0
  28. data/.gem_rbs_collection/logger/1.7/period.rbs +17 -0
  29. data/.gem_rbs_collection/logger/1.7/severity.rbs +34 -0
  30. data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +9 -0
  31. data/.gem_rbs_collection/parallel/1.20/parallel.rbs +86 -0
  32. data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +9 -0
  33. data/.gem_rbs_collection/parser/3.2/manifest.yaml +7 -0
  34. data/.gem_rbs_collection/parser/3.2/parser.rbs +194 -0
  35. data/.gem_rbs_collection/parser/3.2/polyfill.rbs +4 -0
  36. data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +9 -0
  37. data/.gem_rbs_collection/rainbow/3.0/global.rbs +7 -0
  38. data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +209 -0
  39. data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +5 -0
  40. data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +9 -0
  41. data/.gem_rbs_collection/rake/13.0/manifest.yaml +2 -0
  42. data/.gem_rbs_collection/rake/13.0/rake.rbs +39 -0
  43. data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +9 -0
  44. data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +17 -0
  45. data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +9 -0
  46. data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +208 -0
  47. data/.gem_rbs_collection/rubocop-ast/1.46/.rbs_meta.yaml +9 -0
  48. data/.gem_rbs_collection/rubocop-ast/1.46/rubocop-ast.rbs +903 -0
  49. data/CHANGELOG.md +24 -3
  50. data/README.md +91 -17
  51. data/Rakefile +124 -89
  52. data/Steepfile +19 -0
  53. data/docs/ARCHITECTURE.md +17 -0
  54. data/docs/DEVELOPMENT.md +58 -0
  55. data/docs/QUALITY_ASSURANCE.md +26 -0
  56. data/docs/visual/VisualGallery.md +893 -938
  57. data/docs/wasm/ruby.wasm +0 -0
  58. data/lib/xlsxrb/elements/cell.rb +74 -1
  59. data/lib/xlsxrb/elements/column.rb +2 -0
  60. data/lib/xlsxrb/elements/row.rb +37 -2
  61. data/lib/xlsxrb/elements/types.rb +2 -0
  62. data/lib/xlsxrb/elements/workbook.rb +29 -0
  63. data/lib/xlsxrb/elements/worksheet.rb +98 -1
  64. data/lib/xlsxrb/elements.rb +2 -0
  65. data/lib/xlsxrb/ooxml/reader.rb +8 -6
  66. data/lib/xlsxrb/ooxml/shared_strings_parser.rb +2 -0
  67. data/lib/xlsxrb/ooxml/styles_parser.rb +2 -0
  68. data/lib/xlsxrb/ooxml/utils.rb +2 -0
  69. data/lib/xlsxrb/ooxml/workbook_parser.rb +6 -1
  70. data/lib/xlsxrb/ooxml/workbook_writer.rb +15 -4
  71. data/lib/xlsxrb/ooxml/worksheet_parser.rb +12 -0
  72. data/lib/xlsxrb/ooxml/worksheet_writer.rb +49 -9
  73. data/lib/xlsxrb/ooxml/writer.rb +217 -5
  74. data/lib/xlsxrb/ooxml/xml_builder.rb +2 -0
  75. data/lib/xlsxrb/ooxml/xml_parser.rb +2 -0
  76. data/lib/xlsxrb/ooxml/zip_generator.rb +5 -8
  77. data/lib/xlsxrb/ooxml/zip_reader.rb +88 -52
  78. data/lib/xlsxrb/ooxml/zip_writer.rb +2 -0
  79. data/lib/xlsxrb/ooxml.rb +3 -1
  80. data/lib/xlsxrb/style_builder.rb +156 -36
  81. data/lib/xlsxrb/version.rb +3 -1
  82. data/lib/xlsxrb.rb +1510 -231
  83. data/rbs_collection.lock.yaml +224 -0
  84. data/rbs_collection.yaml +19 -0
  85. data/sig/generated/xlsxrb/elements.rbs +8 -0
  86. data/sig/generated/xlsxrb/ooxml.rbs +23 -0
  87. data/sig/generated/xlsxrb/style_builder.rbs +88 -0
  88. data/sig/generated/xlsxrb/version.rbs +5 -0
  89. metadata +67 -29
  90. data/benchmark.rb +0 -399
  91. data/measure_memory.rb +0 -42
  92. data/sig/xlsxrb.rbs +0 -23
@@ -11,7 +11,6 @@ This gallery showcases `xlsxrb` DSL usage side-by-side with the visual rendering
11
11
  <tr>
12
12
  <th align="left">Feature</th>
13
13
  <th align="center">Visual Preview</th>
14
- <th align="center">Download XLSX</th>
15
14
  <th align="center">Link to Detail</th>
16
15
  </tr>
17
16
  </thead>
@@ -19,475 +18,396 @@ This gallery showcases `xlsxrb` DSL usage side-by-side with the visual rendering
19
18
  <tr>
20
19
  <td><strong>Align Horizontal</strong></td>
21
20
  <td align="center"><img src="../../test/visual/baselines/align_horizontal/page-1.png" width="160" alt="Align Horizontal"/></td>
22
- <td align="center"><a href="files/align_horizontal.xlsx">Download</a></td>
23
21
  <td align="center"><a href="#align-horizontal">View Code &amp; Detail</a></td>
24
22
  </tr>
25
23
  <tr>
26
24
  <td><strong>Align Horizontal Fill</strong></td>
27
25
  <td align="center"><img src="../../test/visual/baselines/align_horizontal_fill/page-1.png" width="160" alt="Align Horizontal Fill"/></td>
28
- <td align="center"><a href="files/align_horizontal_fill.xlsx">Download</a></td>
29
26
  <td align="center"><a href="#align-horizontal-fill">View Code &amp; Detail</a></td>
30
27
  </tr>
31
28
  <tr>
32
29
  <td><strong>Align Horizontal Justify</strong></td>
33
30
  <td align="center"><img src="../../test/visual/baselines/align_horizontal_justify/page-1.png" width="160" alt="Align Horizontal Justify"/></td>
34
- <td align="center"><a href="files/align_horizontal_justify.xlsx">Download</a></td>
35
31
  <td align="center"><a href="#align-horizontal-justify">View Code &amp; Detail</a></td>
36
32
  </tr>
37
33
  <tr>
38
34
  <td><strong>Align Indent</strong></td>
39
35
  <td align="center"><img src="../../test/visual/baselines/align_indent/page-1.png" width="160" alt="Align Indent"/></td>
40
- <td align="center"><a href="files/align_indent.xlsx">Download</a></td>
41
36
  <td align="center"><a href="#align-indent">View Code &amp; Detail</a></td>
42
37
  </tr>
43
38
  <tr>
44
39
  <td><strong>Align Text Rotation</strong></td>
45
40
  <td align="center"><img src="../../test/visual/baselines/align_text_rotation/page-1.png" width="160" alt="Align Text Rotation"/></td>
46
- <td align="center"><a href="files/align_text_rotation.xlsx">Download</a></td>
47
41
  <td align="center"><a href="#align-text-rotation">View Code &amp; Detail</a></td>
48
42
  </tr>
49
43
  <tr>
50
44
  <td><strong>Align Text Wrap</strong></td>
51
45
  <td align="center"><img src="../../test/visual/baselines/align_text_wrap/page-1.png" width="160" alt="Align Text Wrap"/></td>
52
- <td align="center"><a href="files/align_text_wrap.xlsx">Download</a></td>
53
46
  <td align="center"><a href="#align-text-wrap">View Code &amp; Detail</a></td>
54
47
  </tr>
55
48
  <tr>
56
49
  <td><strong>Align Vertical</strong></td>
57
50
  <td align="center"><img src="../../test/visual/baselines/align_vertical/page-1.png" width="160" alt="Align Vertical"/></td>
58
- <td align="center"><a href="files/align_vertical.xlsx">Download</a></td>
59
51
  <td align="center"><a href="#align-vertical">View Code &amp; Detail</a></td>
60
52
  </tr>
61
53
  <tr>
62
54
  <td><strong>Basic Data</strong></td>
63
55
  <td align="center"><img src="../../test/visual/baselines/basic_data/page-1.png" width="160" alt="Basic Data"/></td>
64
- <td align="center"><a href="files/basic_data.xlsx">Download</a></td>
65
56
  <td align="center"><a href="#basic-data">View Code &amp; Detail</a></td>
66
57
  </tr>
67
58
  <tr>
68
59
  <td><strong>Borders</strong></td>
69
60
  <td align="center"><img src="../../test/visual/baselines/borders/page-1.png" width="160" alt="Borders"/></td>
70
- <td align="center"><a href="files/borders.xlsx">Download</a></td>
71
61
  <td align="center"><a href="#borders">View Code &amp; Detail</a></td>
72
62
  </tr>
73
63
  <tr>
74
64
  <td><strong>Cell Booleans</strong></td>
75
65
  <td align="center"><img src="../../test/visual/baselines/cell_booleans/page-1.png" width="160" alt="Cell Booleans"/></td>
76
- <td align="center"><a href="files/cell_booleans.xlsx">Download</a></td>
77
66
  <td align="center"><a href="#cell-booleans">View Code &amp; Detail</a></td>
78
67
  </tr>
79
68
  <tr>
80
69
  <td><strong>Cell Dates</strong></td>
81
70
  <td align="center"><img src="../../test/visual/baselines/cell_dates/page-1.png" width="160" alt="Cell Dates"/></td>
82
- <td align="center"><a href="files/cell_dates.xlsx">Download</a></td>
83
71
  <td align="center"><a href="#cell-dates">View Code &amp; Detail</a></td>
84
72
  </tr>
85
73
  <tr>
86
74
  <td><strong>Cell Formulas</strong></td>
87
75
  <td align="center"><img src="../../test/visual/baselines/cell_formulas/page-1.png" width="160" alt="Cell Formulas"/></td>
88
- <td align="center"><a href="files/cell_formulas.xlsx">Download</a></td>
89
76
  <td align="center"><a href="#cell-formulas">View Code &amp; Detail</a></td>
90
77
  </tr>
91
78
  <tr>
92
79
  <td><strong>Cell Num Currency Jpy</strong></td>
93
80
  <td align="center"><img src="../../test/visual/baselines/cell_num_currency_jpy/page-1.png" width="160" alt="Cell Num Currency Jpy"/></td>
94
- <td align="center"><a href="files/cell_num_currency_jpy.xlsx">Download</a></td>
95
81
  <td align="center"><a href="#cell-num-currency-jpy">View Code &amp; Detail</a></td>
96
82
  </tr>
97
83
  <tr>
98
84
  <td><strong>Cell Num Custom Colors</strong></td>
99
85
  <td align="center"><img src="../../test/visual/baselines/cell_num_custom_colors/page-1.png" width="160" alt="Cell Num Custom Colors"/></td>
100
- <td align="center"><a href="files/cell_num_custom_colors.xlsx">Download</a></td>
101
86
  <td align="center"><a href="#cell-num-custom-colors">View Code &amp; Detail</a></td>
102
87
  </tr>
103
88
  <tr>
104
89
  <td><strong>Cell Num Fractions</strong></td>
105
90
  <td align="center"><img src="../../test/visual/baselines/cell_num_fractions/page-1.png" width="160" alt="Cell Num Fractions"/></td>
106
- <td align="center"><a href="files/cell_num_fractions.xlsx">Download</a></td>
107
91
  <td align="center"><a href="#cell-num-fractions">View Code &amp; Detail</a></td>
108
92
  </tr>
109
93
  <tr>
110
94
  <td><strong>Cell Num Percent Decimals</strong></td>
111
95
  <td align="center"><img src="../../test/visual/baselines/cell_num_percent_decimals/page-1.png" width="160" alt="Cell Num Percent Decimals"/></td>
112
- <td align="center"><a href="files/cell_num_percent_decimals.xlsx">Download</a></td>
113
96
  <td align="center"><a href="#cell-num-percent-decimals">View Code &amp; Detail</a></td>
114
97
  </tr>
115
98
  <tr>
116
99
  <td><strong>Cell Num Scientific</strong></td>
117
100
  <td align="center"><img src="../../test/visual/baselines/cell_num_scientific/page-1.png" width="160" alt="Cell Num Scientific"/></td>
118
- <td align="center"><a href="files/cell_num_scientific.xlsx">Download</a></td>
119
101
  <td align="center"><a href="#cell-num-scientific">View Code &amp; Detail</a></td>
120
102
  </tr>
121
103
  <tr>
122
104
  <td><strong>Cell Numbers</strong></td>
123
105
  <td align="center"><img src="../../test/visual/baselines/cell_numbers/page-1.png" width="160" alt="Cell Numbers"/></td>
124
- <td align="center"><a href="files/cell_numbers.xlsx">Download</a></td>
125
106
  <td align="center"><a href="#cell-numbers">View Code &amp; Detail</a></td>
126
107
  </tr>
127
108
  <tr>
128
109
  <td><strong>Cell Rich Text</strong></td>
129
110
  <td align="center"><img src="../../test/visual/baselines/cell_rich_text/page-1.png" width="160" alt="Cell Rich Text"/></td>
130
- <td align="center"><a href="files/cell_rich_text.xlsx">Download</a></td>
131
111
  <td align="center"><a href="#cell-rich-text">View Code &amp; Detail</a></td>
132
112
  </tr>
133
113
  <tr>
134
114
  <td><strong>Cell Times</strong></td>
135
115
  <td align="center"><img src="../../test/visual/baselines/cell_times/page-1.png" width="160" alt="Cell Times"/></td>
136
- <td align="center"><a href="files/cell_times.xlsx">Download</a></td>
137
116
  <td align="center"><a href="#cell-times">View Code &amp; Detail</a></td>
138
117
  </tr>
139
118
  <tr>
140
119
  <td><strong>Cf Begins With</strong></td>
141
120
  <td align="center"><img src="../../test/visual/baselines/cf_begins_with/page-1.png" width="160" alt="Cf Begins With"/></td>
142
- <td align="center"><a href="files/cf_begins_with.xlsx">Download</a></td>
143
121
  <td align="center"><a href="#cf-begins-with">View Code &amp; Detail</a></td>
144
122
  </tr>
145
123
  <tr>
146
124
  <td><strong>Cf Cell Between</strong></td>
147
125
  <td align="center"><img src="../../test/visual/baselines/cf_cell_between/page-1.png" width="160" alt="Cf Cell Between"/></td>
148
- <td align="center"><a href="files/cf_cell_between.xlsx">Download</a></td>
149
126
  <td align="center"><a href="#cf-cell-between">View Code &amp; Detail</a></td>
150
127
  </tr>
151
128
  <tr>
152
129
  <td><strong>Cf Cell Equal To</strong></td>
153
130
  <td align="center"><img src="../../test/visual/baselines/cf_cell_equal_to/page-1.png" width="160" alt="Cf Cell Equal To"/></td>
154
- <td align="center"><a href="files/cf_cell_equal_to.xlsx">Download</a></td>
155
131
  <td align="center"><a href="#cf-cell-equal-to">View Code &amp; Detail</a></td>
156
132
  </tr>
157
133
  <tr>
158
134
  <td><strong>Cf Cell Greater Equal</strong></td>
159
135
  <td align="center"><img src="../../test/visual/baselines/cf_cell_greater_equal/page-1.png" width="160" alt="Cf Cell Greater Equal"/></td>
160
- <td align="center"><a href="files/cf_cell_greater_equal.xlsx">Download</a></td>
161
136
  <td align="center"><a href="#cf-cell-greater-equal">View Code &amp; Detail</a></td>
162
137
  </tr>
163
138
  <tr>
164
139
  <td><strong>Cf Cell Greater Than</strong></td>
165
140
  <td align="center"><img src="../../test/visual/baselines/cf_cell_greater_than/page-1.png" width="160" alt="Cf Cell Greater Than"/></td>
166
- <td align="center"><a href="files/cf_cell_greater_than.xlsx">Download</a></td>
167
141
  <td align="center"><a href="#cf-cell-greater-than">View Code &amp; Detail</a></td>
168
142
  </tr>
169
143
  <tr>
170
144
  <td><strong>Cf Cell Less Than</strong></td>
171
145
  <td align="center"><img src="../../test/visual/baselines/cf_cell_less_than/page-1.png" width="160" alt="Cf Cell Less Than"/></td>
172
- <td align="center"><a href="files/cf_cell_less_than.xlsx">Download</a></td>
173
146
  <td align="center"><a href="#cf-cell-less-than">View Code &amp; Detail</a></td>
174
147
  </tr>
175
148
  <tr>
176
149
  <td><strong>Cf Color Scale</strong></td>
177
150
  <td align="center"><img src="../../test/visual/baselines/cf_color_scale/page-1.png" width="160" alt="Cf Color Scale"/></td>
178
- <td align="center"><a href="files/cf_color_scale.xlsx">Download</a></td>
179
151
  <td align="center"><a href="#cf-color-scale">View Code &amp; Detail</a></td>
180
152
  </tr>
181
153
  <tr>
182
154
  <td><strong>Cf Contains Text</strong></td>
183
155
  <td align="center"><img src="../../test/visual/baselines/cf_contains_text/page-1.png" width="160" alt="Cf Contains Text"/></td>
184
- <td align="center"><a href="files/cf_contains_text.xlsx">Download</a></td>
185
156
  <td align="center"><a href="#cf-contains-text">View Code &amp; Detail</a></td>
186
157
  </tr>
187
158
  <tr>
188
159
  <td><strong>Cf Data Bar</strong></td>
189
160
  <td align="center"><img src="../../test/visual/baselines/cf_data_bar/page-1.png" width="160" alt="Cf Data Bar"/></td>
190
- <td align="center"><a href="files/cf_data_bar.xlsx">Download</a></td>
191
161
  <td align="center"><a href="#cf-data-bar">View Code &amp; Detail</a></td>
192
162
  </tr>
193
163
  <tr>
194
164
  <td><strong>Cf Ends With</strong></td>
195
165
  <td align="center"><img src="../../test/visual/baselines/cf_ends_with/page-1.png" width="160" alt="Cf Ends With"/></td>
196
- <td align="center"><a href="files/cf_ends_with.xlsx">Download</a></td>
197
166
  <td align="center"><a href="#cf-ends-with">View Code &amp; Detail</a></td>
198
167
  </tr>
199
168
  <tr>
200
169
  <td><strong>Cf Expression Formula</strong></td>
201
170
  <td align="center"><img src="../../test/visual/baselines/cf_expression_formula/page-1.png" width="160" alt="Cf Expression Formula"/></td>
202
- <td align="center"><a href="files/cf_expression_formula.xlsx">Download</a></td>
203
171
  <td align="center"><a href="#cf-expression-formula">View Code &amp; Detail</a></td>
204
172
  </tr>
205
173
  <tr>
206
174
  <td><strong>Cf Icon Set</strong></td>
207
175
  <td align="center"><img src="../../test/visual/baselines/cf_icon_set/page-1.png" width="160" alt="Cf Icon Set"/></td>
208
- <td align="center"><a href="files/cf_icon_set.xlsx">Download</a></td>
209
176
  <td align="center"><a href="#cf-icon-set">View Code &amp; Detail</a></td>
210
177
  </tr>
211
178
  <tr>
212
179
  <td><strong>Chart Area</strong></td>
213
180
  <td align="center"><img src="../../test/visual/baselines/chart_area/page-1.png" width="160" alt="Chart Area"/></td>
214
- <td align="center"><a href="files/chart_area.xlsx">Download</a></td>
215
181
  <td align="center"><a href="#chart-area">View Code &amp; Detail</a></td>
216
182
  </tr>
217
183
  <tr>
218
184
  <td><strong>Chart Area Stacked</strong></td>
219
185
  <td align="center"><img src="../../test/visual/baselines/chart_area_stacked/page-1.png" width="160" alt="Chart Area Stacked"/></td>
220
- <td align="center"><a href="files/chart_area_stacked.xlsx">Download</a></td>
221
186
  <td align="center"><a href="#chart-area-stacked">View Code &amp; Detail</a></td>
222
187
  </tr>
223
188
  <tr>
224
189
  <td><strong>Chart Bar</strong></td>
225
190
  <td align="center"><img src="../../test/visual/baselines/chart_bar/page-1.png" width="160" alt="Chart Bar"/></td>
226
- <td align="center"><a href="files/chart_bar.xlsx">Download</a></td>
227
191
  <td align="center"><a href="#chart-bar">View Code &amp; Detail</a></td>
228
192
  </tr>
229
193
  <tr>
230
194
  <td><strong>Chart Bar Percent Stacked</strong></td>
231
195
  <td align="center"><img src="../../test/visual/baselines/chart_bar_percent_stacked/page-1.png" width="160" alt="Chart Bar Percent Stacked"/></td>
232
- <td align="center"><a href="files/chart_bar_percent_stacked.xlsx">Download</a></td>
233
196
  <td align="center"><a href="#chart-bar-percent-stacked">View Code &amp; Detail</a></td>
234
197
  </tr>
235
198
  <tr>
236
199
  <td><strong>Chart Bar Stacked</strong></td>
237
200
  <td align="center"><img src="../../test/visual/baselines/chart_bar_stacked/page-1.png" width="160" alt="Chart Bar Stacked"/></td>
238
- <td align="center"><a href="files/chart_bar_stacked.xlsx">Download</a></td>
239
201
  <td align="center"><a href="#chart-bar-stacked">View Code &amp; Detail</a></td>
240
202
  </tr>
241
203
  <tr>
242
204
  <td><strong>Chart Doughnut</strong></td>
243
205
  <td align="center"><img src="../../test/visual/baselines/chart_doughnut/page-1.png" width="160" alt="Chart Doughnut"/></td>
244
- <td align="center"><a href="files/chart_doughnut.xlsx">Download</a></td>
245
206
  <td align="center"><a href="#chart-doughnut">View Code &amp; Detail</a></td>
246
207
  </tr>
247
208
  <tr>
248
209
  <td><strong>Chart Line</strong></td>
249
210
  <td align="center"><img src="../../test/visual/baselines/chart_line/page-1.png" width="160" alt="Chart Line"/></td>
250
- <td align="center"><a href="files/chart_line.xlsx">Download</a></td>
251
211
  <td align="center"><a href="#chart-line">View Code &amp; Detail</a></td>
252
212
  </tr>
253
213
  <tr>
254
214
  <td><strong>Chart Line Stacked</strong></td>
255
215
  <td align="center"><img src="../../test/visual/baselines/chart_line_stacked/page-1.png" width="160" alt="Chart Line Stacked"/></td>
256
- <td align="center"><a href="files/chart_line_stacked.xlsx">Download</a></td>
257
216
  <td align="center"><a href="#chart-line-stacked">View Code &amp; Detail</a></td>
258
217
  </tr>
259
218
  <tr>
260
219
  <td><strong>Chart Pie</strong></td>
261
220
  <td align="center"><img src="../../test/visual/baselines/chart_pie/page-1.png" width="160" alt="Chart Pie"/></td>
262
- <td align="center"><a href="files/chart_pie.xlsx">Download</a></td>
263
221
  <td align="center"><a href="#chart-pie">View Code &amp; Detail</a></td>
264
222
  </tr>
265
223
  <tr>
266
224
  <td><strong>Chart Radar</strong></td>
267
225
  <td align="center"><img src="../../test/visual/baselines/chart_radar/page-1.png" width="160" alt="Chart Radar"/></td>
268
- <td align="center"><a href="files/chart_radar.xlsx">Download</a></td>
269
226
  <td align="center"><a href="#chart-radar">View Code &amp; Detail</a></td>
270
227
  </tr>
271
228
  <tr>
272
229
  <td><strong>Chart Scatter</strong></td>
273
230
  <td align="center"><img src="../../test/visual/baselines/chart_scatter/page-1.png" width="160" alt="Chart Scatter"/></td>
274
- <td align="center"><a href="files/chart_scatter.xlsx">Download</a></td>
275
231
  <td align="center"><a href="#chart-scatter">View Code &amp; Detail</a></td>
276
232
  </tr>
277
233
  <tr>
278
234
  <td><strong>Col Grouping</strong></td>
279
235
  <td align="center"><img src="../../test/visual/baselines/col_grouping/page-1.png" width="160" alt="Col Grouping"/></td>
280
- <td align="center"><a href="files/col_grouping.xlsx">Download</a></td>
281
236
  <td align="center"><a href="#col-grouping">View Code &amp; Detail</a></td>
282
237
  </tr>
283
238
  <tr>
284
239
  <td><strong>Col Width Tall</strong></td>
285
240
  <td align="center"><img src="../../test/visual/baselines/col_width_tall/page-1.png" width="160" alt="Col Width Tall"/></td>
286
- <td align="center"><a href="files/col_width_tall.xlsx">Download</a></td>
287
241
  <td align="center"><a href="#col-width-tall">View Code &amp; Detail</a></td>
288
242
  </tr>
289
243
  <tr>
290
244
  <td><strong>Col Widths</strong></td>
291
245
  <td align="center"><img src="../../test/visual/baselines/col_widths/page-1.png" width="160" alt="Col Widths"/></td>
292
- <td align="center"><a href="files/col_widths.xlsx">Download</a></td>
293
246
  <td align="center"><a href="#col-widths">View Code &amp; Detail</a></td>
294
247
  </tr>
295
248
  <tr>
296
249
  <td><strong>Conditional Formatting</strong></td>
297
250
  <td align="center"><img src="../../test/visual/baselines/conditional_formatting/page-1.png" width="160" alt="Conditional Formatting"/></td>
298
- <td align="center"><a href="files/conditional_formatting.xlsx">Download</a></td>
299
251
  <td align="center"><a href="#conditional-formatting">View Code &amp; Detail</a></td>
300
252
  </tr>
301
253
  <tr>
302
254
  <td><strong>Embedded Images</strong></td>
303
255
  <td align="center"><img src="../../test/visual/baselines/embedded_images/page-1.png" width="160" alt="Embedded Images"/></td>
304
- <td align="center"><a href="files/embedded_images.xlsx">Download</a></td>
305
256
  <td align="center"><a href="#embedded-images">View Code &amp; Detail</a></td>
306
257
  </tr>
307
258
  <tr>
308
259
  <td><strong>Fill Gradients</strong></td>
309
260
  <td align="center"><img src="../../test/visual/baselines/fill_gradients/page-1.png" width="160" alt="Fill Gradients"/></td>
310
- <td align="center"><a href="files/fill_gradients.xlsx">Download</a></td>
311
261
  <td align="center"><a href="#fill-gradients">View Code &amp; Detail</a></td>
312
262
  </tr>
313
263
  <tr>
314
264
  <td><strong>Fill Patterns</strong></td>
315
265
  <td align="center"><img src="../../test/visual/baselines/fill_patterns/page-1.png" width="160" alt="Fill Patterns"/></td>
316
- <td align="center"><a href="files/fill_patterns.xlsx">Download</a></td>
317
266
  <td align="center"><a href="#fill-patterns">View Code &amp; Detail</a></td>
318
267
  </tr>
319
268
  <tr>
320
269
  <td><strong>Fill Solid Colors</strong></td>
321
270
  <td align="center"><img src="../../test/visual/baselines/fill_solid_colors/page-1.png" width="160" alt="Fill Solid Colors"/></td>
322
- <td align="center"><a href="files/fill_solid_colors.xlsx">Download</a></td>
323
271
  <td align="center"><a href="#fill-solid-colors">View Code &amp; Detail</a></td>
324
272
  </tr>
325
273
  <tr>
326
274
  <td><strong>Fonts</strong></td>
327
275
  <td align="center"><img src="../../test/visual/baselines/fonts/page-1.png" width="160" alt="Fonts"/></td>
328
- <td align="center"><a href="files/fonts.xlsx">Download</a></td>
329
276
  <td align="center"><a href="#fonts">View Code &amp; Detail</a></td>
330
277
  </tr>
331
278
  <tr>
332
279
  <td><strong>Interactive Autofilter</strong></td>
333
280
  <td align="center"><img src="../../test/visual/baselines/interactive_autofilter/page-1.png" width="160" alt="Interactive Autofilter"/></td>
334
- <td align="center"><a href="files/interactive_autofilter.xlsx">Download</a></td>
335
281
  <td align="center"><a href="#interactive-autofilter">View Code &amp; Detail</a></td>
336
282
  </tr>
337
283
  <tr>
338
284
  <td><strong>Interactive Comments</strong></td>
339
285
  <td align="center"><img src="../../test/visual/baselines/interactive_comments/page-1.png" width="160" alt="Interactive Comments"/></td>
340
- <td align="center"><a href="files/interactive_comments.xlsx">Download</a></td>
341
286
  <td align="center"><a href="#interactive-comments">View Code &amp; Detail</a></td>
342
287
  </tr>
343
288
  <tr>
344
289
  <td><strong>Interactive Validation Custom</strong></td>
345
290
  <td align="center"><img src="../../test/visual/baselines/interactive_validation_custom/page-1.png" width="160" alt="Interactive Validation Custom"/></td>
346
- <td align="center"><a href="files/interactive_validation_custom.xlsx">Download</a></td>
347
291
  <td align="center"><a href="#interactive-validation-custom">View Code &amp; Detail</a></td>
348
292
  </tr>
349
293
  <tr>
350
294
  <td><strong>Interactive Validation Date</strong></td>
351
295
  <td align="center"><img src="../../test/visual/baselines/interactive_validation_date/page-1.png" width="160" alt="Interactive Validation Date"/></td>
352
- <td align="center"><a href="files/interactive_validation_date.xlsx">Download</a></td>
353
296
  <td align="center"><a href="#interactive-validation-date">View Code &amp; Detail</a></td>
354
297
  </tr>
355
298
  <tr>
356
299
  <td><strong>Interactive Validation List</strong></td>
357
300
  <td align="center"><img src="../../test/visual/baselines/interactive_validation_list/page-1.png" width="160" alt="Interactive Validation List"/></td>
358
- <td align="center"><a href="files/interactive_validation_list.xlsx">Download</a></td>
359
301
  <td align="center"><a href="#interactive-validation-list">View Code &amp; Detail</a></td>
360
302
  </tr>
361
303
  <tr>
362
304
  <td><strong>Interactive Validation Range</strong></td>
363
305
  <td align="center"><img src="../../test/visual/baselines/interactive_validation_range/page-1.png" width="160" alt="Interactive Validation Range"/></td>
364
- <td align="center"><a href="files/interactive_validation_range.xlsx">Download</a></td>
365
306
  <td align="center"><a href="#interactive-validation-range">View Code &amp; Detail</a></td>
366
307
  </tr>
367
308
  <tr>
368
309
  <td><strong>Interactive Validation Text Length</strong></td>
369
310
  <td align="center"><img src="../../test/visual/baselines/interactive_validation_text_length/page-1.png" width="160" alt="Interactive Validation Text Length"/></td>
370
- <td align="center"><a href="files/interactive_validation_text_length.xlsx">Download</a></td>
371
311
  <td align="center"><a href="#interactive-validation-text-length">View Code &amp; Detail</a></td>
372
312
  </tr>
373
313
  <tr>
374
314
  <td><strong>Interactive Validation Time</strong></td>
375
315
  <td align="center"><img src="../../test/visual/baselines/interactive_validation_time/page-1.png" width="160" alt="Interactive Validation Time"/></td>
376
- <td align="center"><a href="files/interactive_validation_time.xlsx">Download</a></td>
377
316
  <td align="center"><a href="#interactive-validation-time">View Code &amp; Detail</a></td>
378
317
  </tr>
379
318
  <tr>
380
319
  <td><strong>Japanese Text</strong></td>
381
320
  <td align="center"><img src="../../test/visual/baselines/japanese_text/page-1.png" width="160" alt="Japanese Text"/></td>
382
- <td align="center"><a href="files/japanese_text.xlsx">Download</a></td>
383
321
  <td align="center"><a href="#japanese-text">View Code &amp; Detail</a></td>
384
322
  </tr>
385
323
  <tr>
386
324
  <td><strong>Merge Freeze</strong></td>
387
325
  <td align="center"><img src="../../test/visual/baselines/merge_freeze/page-1.png" width="160" alt="Merge Freeze"/></td>
388
- <td align="center"><a href="files/merge_freeze.xlsx">Download</a></td>
389
326
  <td align="center"><a href="#merge-freeze">View Code &amp; Detail</a></td>
390
327
  </tr>
391
328
  <tr>
392
329
  <td><strong>Page Grid Lines Print</strong></td>
393
330
  <td align="center"><img src="../../test/visual/baselines/page_grid_lines_print/page-1.png" width="160" alt="Page Grid Lines Print"/></td>
394
- <td align="center"><a href="files/page_grid_lines_print.xlsx">Download</a></td>
395
331
  <td align="center"><a href="#page-grid-lines-print">View Code &amp; Detail</a></td>
396
332
  </tr>
397
333
  <tr>
398
334
  <td><strong>Page Header Footer</strong></td>
399
335
  <td align="center"><img src="../../test/visual/baselines/page_header_footer/page-1.png" width="160" alt="Page Header Footer"/></td>
400
- <td align="center"><a href="files/page_header_footer.xlsx">Download</a></td>
401
336
  <td align="center"><a href="#page-header-footer">View Code &amp; Detail</a></td>
402
337
  </tr>
403
338
  <tr>
404
339
  <td><strong>Page Headings Print</strong></td>
405
340
  <td align="center"><img src="../../test/visual/baselines/page_headings_print/page-1.png" width="160" alt="Page Headings Print"/></td>
406
- <td align="center"><a href="files/page_headings_print.xlsx">Download</a></td>
407
341
  <td align="center"><a href="#page-headings-print">View Code &amp; Detail</a></td>
408
342
  </tr>
409
343
  <tr>
410
344
  <td><strong>Page Margins Narrow</strong></td>
411
345
  <td align="center"><img src="../../test/visual/baselines/page_margins_narrow/page-1.png" width="160" alt="Page Margins Narrow"/></td>
412
- <td align="center"><a href="files/page_margins_narrow.xlsx">Download</a></td>
413
346
  <td align="center"><a href="#page-margins-narrow">View Code &amp; Detail</a></td>
414
347
  </tr>
415
348
  <tr>
416
349
  <td><strong>Page Margins Wide</strong></td>
417
350
  <td align="center"><img src="../../test/visual/baselines/page_margins_wide/page-1.png" width="160" alt="Page Margins Wide"/></td>
418
- <td align="center"><a href="files/page_margins_wide.xlsx">Download</a></td>
419
351
  <td align="center"><a href="#page-margins-wide">View Code &amp; Detail</a></td>
420
352
  </tr>
421
353
  <tr>
422
354
  <td><strong>Page Orientation Landscape</strong></td>
423
355
  <td align="center"><img src="../../test/visual/baselines/page_orientation_landscape/page-1.png" width="160" alt="Page Orientation Landscape"/></td>
424
- <td align="center"><a href="files/page_orientation_landscape.xlsx">Download</a></td>
425
356
  <td align="center"><a href="#page-orientation-landscape">View Code &amp; Detail</a></td>
426
357
  </tr>
427
358
  <tr>
428
359
  <td><strong>Page Paper Size A3</strong></td>
429
360
  <td align="center"><img src="../../test/visual/baselines/page_paper_size_a3/page-1.png" width="160" alt="Page Paper Size A3"/></td>
430
- <td align="center"><a href="files/page_paper_size_a3.xlsx">Download</a></td>
431
361
  <td align="center"><a href="#page-paper-size-a3">View Code &amp; Detail</a></td>
432
362
  </tr>
433
363
  <tr>
434
364
  <td><strong>Row Grouping</strong></td>
435
365
  <td align="center"><img src="../../test/visual/baselines/row_grouping/page-1.png" width="160" alt="Row Grouping"/></td>
436
- <td align="center"><a href="files/row_grouping.xlsx">Download</a></td>
437
366
  <td align="center"><a href="#row-grouping">View Code &amp; Detail</a></td>
438
367
  </tr>
439
368
  <tr>
440
369
  <td><strong>Row Height Tall</strong></td>
441
370
  <td align="center"><img src="../../test/visual/baselines/row_height_tall/page-1.png" width="160" alt="Row Height Tall"/></td>
442
- <td align="center"><a href="files/row_height_tall.xlsx">Download</a></td>
443
371
  <td align="center"><a href="#row-height-tall">View Code &amp; Detail</a></td>
444
372
  </tr>
445
373
  <tr>
446
374
  <td><strong>Row Heights</strong></td>
447
375
  <td align="center"><img src="../../test/visual/baselines/row_heights/page-1.png" width="160" alt="Row Heights"/></td>
448
- <td align="center"><a href="files/row_heights.xlsx">Download</a></td>
449
376
  <td align="center"><a href="#row-heights">View Code &amp; Detail</a></td>
450
377
  </tr>
451
378
  <tr>
452
379
  <td><strong>Sheet Tab Colors</strong></td>
453
380
  <td align="center"><img src="../../test/visual/baselines/sheet_tab_colors/page-1.png" width="160" alt="Sheet Tab Colors"/></td>
454
- <td align="center"><a href="files/sheet_tab_colors.xlsx">Download</a></td>
455
381
  <td align="center"><a href="#sheet-tab-colors">View Code &amp; Detail</a></td>
456
382
  </tr>
457
383
  <tr>
458
384
  <td><strong>Sparkline Column</strong></td>
459
385
  <td align="center"><img src="../../test/visual/baselines/sparkline_column/page-1.png" width="160" alt="Sparkline Column"/></td>
460
- <td align="center"><a href="files/sparkline_column.xlsx">Download</a></td>
461
386
  <td align="center"><a href="#sparkline-column">View Code &amp; Detail</a></td>
462
387
  </tr>
463
388
  <tr>
464
389
  <td><strong>Sparkline Line</strong></td>
465
390
  <td align="center"><img src="../../test/visual/baselines/sparkline_line/page-1.png" width="160" alt="Sparkline Line"/></td>
466
- <td align="center"><a href="files/sparkline_line.xlsx">Download</a></td>
467
391
  <td align="center"><a href="#sparkline-line">View Code &amp; Detail</a></td>
468
392
  </tr>
469
393
  <tr>
470
394
  <td><strong>Styles Fonts Fills</strong></td>
471
395
  <td align="center"><img src="../../test/visual/baselines/styles_fonts_fills/page-1.png" width="160" alt="Styles Fonts Fills"/></td>
472
- <td align="center"><a href="files/styles_fonts_fills.xlsx">Download</a></td>
473
396
  <td align="center"><a href="#styles-fonts-fills">View Code &amp; Detail</a></td>
474
397
  </tr>
475
398
  <tr>
476
399
  <td><strong>View Show Grid Lines</strong></td>
477
400
  <td align="center"><img src="../../test/visual/baselines/view_show_grid_lines/page-1.png" width="160" alt="View Show Grid Lines"/></td>
478
- <td align="center"><a href="files/view_show_grid_lines.xlsx">Download</a></td>
479
401
  <td align="center"><a href="#view-show-grid-lines">View Code &amp; Detail</a></td>
480
402
  </tr>
481
403
  <tr>
482
404
  <td><strong>View Zoom Scale</strong></td>
483
405
  <td align="center"><img src="../../test/visual/baselines/view_zoom_scale/page-1.png" width="160" alt="View Zoom Scale"/></td>
484
- <td align="center"><a href="files/view_zoom_scale.xlsx">Download</a></td>
485
406
  <td align="center"><a href="#view-zoom-scale">View Code &amp; Detail</a></td>
486
407
  </tr>
487
408
  <tr>
488
409
  <td><strong>Workbook Three Sheets</strong></td>
489
410
  <td align="center"><img src="../../test/visual/baselines/workbook_three_sheets/page-1.png" width="160" alt="Workbook Three Sheets"/></td>
490
- <td align="center"><a href="files/workbook_three_sheets.xlsx">Download</a></td>
491
411
  <td align="center"><a href="#workbook-three-sheets">View Code &amp; Detail</a></td>
492
412
  </tr>
493
413
  </tbody>
@@ -508,18 +428,19 @@ Demonstrates horizontal text alignment (left, center, right).
508
428
 
509
429
  ```ruby
510
430
  # frozen_string_literal: true
431
+
511
432
  require "xlsxrb"
512
433
  output_path = ARGV[0] || "align_horizontal.xlsx"
513
- Xlsxrb.generate(output_path) do |w|
514
- w.add_style("left") { |s| s.align_horizontal("left") }
515
- w.add_style("center") { |s| s.align_horizontal("center") }
516
- w.add_style("right") { |s| s.align_horizontal("right") }
517
- w.add_sheet("Alignment") do |s|
518
- s.set_print_option(:grid_lines, true)
519
- s.set_column(0, width: 20)
520
- s.set_column(1, width: 20)
521
- s.set_column(2, width: 20)
522
- s.add_row(["Left", "Center", "Right"], styles: { 0 => "left", 1 => "center", 2 => "right" })
434
+ Xlsxrb.generate(output_path) do |wb|
435
+ wb.style("left") { |s| s.align_horizontal("left") }
436
+ wb.style("center") { |s| s.align_horizontal("center") }
437
+ wb.style("right") { |s| s.align_horizontal("right") }
438
+ wb.sheet("Alignment") do |s|
439
+ s.print_options(:grid_lines, true)
440
+ s.column(0, width: 20)
441
+ s.column(1, width: 20)
442
+ s.column(2, width: 20)
443
+ s.row(%w[Left Center Right], styles: { 0 => "left", 1 => "center", 2 => "right" })
523
444
  end
524
445
  end
525
446
 
@@ -531,7 +452,7 @@ row = sheet.rows.first
531
452
 
532
453
  row.cells.each do |c|
533
454
  xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
534
- align_h = xf ? xf.dig(:alignment, :horizontal) : nil
455
+ align_h = xf&.dig(:alignment, :horizontal)
535
456
  puts "Cell #{c.ref} ('#{c.value}'): align_horizontal = #{align_h.inspect}"
536
457
  end
537
458
  ```
@@ -559,13 +480,14 @@ Demonstrates horizontal fill alignment (repeats value to fill cell width).
559
480
 
560
481
  ```ruby
561
482
  # frozen_string_literal: true
483
+
562
484
  require "xlsxrb"
563
485
  output_path = ARGV[0] || "align_horizontal_fill.xlsx"
564
- Xlsxrb.generate(output_path) do |w|
565
- w.add_style("fill_align") { |s| s.align_horizontal("fill") }
566
- w.add_sheet("Alignment") do |s|
567
- s.set_column(0, width: 30)
568
- s.add_row(["X "], styles: { 0 => "fill_align" })
486
+ Xlsxrb.generate(output_path) do |wb|
487
+ wb.style("fill_align") { |s| s.align_horizontal("fill") }
488
+ wb.sheet("Alignment") do |s|
489
+ s.column(0, width: 30)
490
+ s.row(["X "], styles: { 0 => "fill_align" })
569
491
  end
570
492
  end
571
493
 
@@ -576,12 +498,12 @@ sheet = workbook.sheets.first
576
498
  row = sheet.rows.first
577
499
  row.cells.each do |c|
578
500
  xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
579
- align_h = xf ? xf.dig(:alignment, :horizontal) : nil
580
- align_v = xf ? xf.dig(:alignment, :vertical) : nil
581
- wrap = xf ? xf.dig(:alignment, :wrap_text) : nil
582
- indent = xf ? xf.dig(:alignment, :indent) : nil
583
- rot = xf ? xf.dig(:alignment, :text_rotation) : nil
584
- shrink = xf ? xf.dig(:alignment, :shrink_to_fit) : nil
501
+ align_h = xf&.dig(:alignment, :horizontal)
502
+ align_v = xf&.dig(:alignment, :vertical)
503
+ wrap = xf&.dig(:alignment, :wrap_text)
504
+ indent = xf&.dig(:alignment, :indent)
505
+ rot = xf&.dig(:alignment, :text_rotation)
506
+ shrink = xf&.dig(:alignment, :shrink_to_fit)
585
507
  puts "Cell #{c.ref} ('#{c.value}'): align_h=#{align_h.inspect}, align_v=#{align_v.inspect}, wrap=#{wrap.inspect}, indent=#{indent.inspect}, rotation=#{rot.inspect}, shrink=#{shrink.inspect}"
586
508
  end
587
509
  ```
@@ -607,16 +529,17 @@ Demonstrates horizontal justify text alignment.
607
529
 
608
530
  ```ruby
609
531
  # frozen_string_literal: true
532
+
610
533
  require "xlsxrb"
611
534
  output_path = ARGV[0] || "align_horizontal_justify.xlsx"
612
- Xlsxrb.generate(output_path) do |w|
613
- w.add_style("justify_align") do |s|
535
+ Xlsxrb.generate(output_path) do |wb|
536
+ wb.style("justify_align") do |s|
614
537
  s.align_horizontal("justify")
615
538
  s.wrap_text(true)
616
539
  end
617
- w.add_sheet("Alignment") do |s|
618
- s.set_column(0, width: 25)
619
- s.add_row(["Justified alignment wraps and distributes text evenly."], styles: { 0 => "justify_align" })
540
+ wb.sheet("Alignment") do |s|
541
+ s.column(0, width: 25)
542
+ s.row(["Justified alignment wraps and distributes text evenly."], styles: { 0 => "justify_align" })
620
543
  end
621
544
  end
622
545
 
@@ -627,12 +550,12 @@ sheet = workbook.sheets.first
627
550
  row = sheet.rows.first
628
551
  row.cells.each do |c|
629
552
  xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
630
- align_h = xf ? xf.dig(:alignment, :horizontal) : nil
631
- align_v = xf ? xf.dig(:alignment, :vertical) : nil
632
- wrap = xf ? xf.dig(:alignment, :wrap_text) : nil
633
- indent = xf ? xf.dig(:alignment, :indent) : nil
634
- rot = xf ? xf.dig(:alignment, :text_rotation) : nil
635
- shrink = xf ? xf.dig(:alignment, :shrink_to_fit) : nil
553
+ align_h = xf&.dig(:alignment, :horizontal)
554
+ align_v = xf&.dig(:alignment, :vertical)
555
+ wrap = xf&.dig(:alignment, :wrap_text)
556
+ indent = xf&.dig(:alignment, :indent)
557
+ rot = xf&.dig(:alignment, :text_rotation)
558
+ shrink = xf&.dig(:alignment, :shrink_to_fit)
636
559
  puts "Cell #{c.ref} ('#{c.value}'): align_h=#{align_h.inspect}, align_v=#{align_v.inspect}, wrap=#{wrap.inspect}, indent=#{indent.inspect}, rotation=#{rot.inspect}, shrink=#{shrink.inspect}"
637
560
  end
638
561
  ```
@@ -658,18 +581,19 @@ Demonstrates text indentation inside cells.
658
581
 
659
582
  ```ruby
660
583
  # frozen_string_literal: true
584
+
661
585
  require "xlsxrb"
662
586
  output_path = ARGV[0] || "align_indent.xlsx"
663
- Xlsxrb.generate(output_path) do |w|
664
- w.add_style("indent_1") { |s| s.align_horizontal("left").indent(1) }
665
- w.add_style("indent_3") { |s| s.align_horizontal("left").indent(3) }
666
- w.add_sheet("Indent") do |s|
667
- s.set_column(0, width: 25)
668
- s.set_column(1, width: 25)
669
- s.set_print_option(:grid_lines, true)
670
- s.add_row(["No Indent"])
671
- s.add_row(["Indent 1"], styles: { 0 => "indent_1" })
672
- s.add_row(["Indent 3"], styles: { 0 => "indent_3" })
587
+ Xlsxrb.generate(output_path) do |wb|
588
+ wb.style("indent_1") { |s| s.align_horizontal("left").indent(1) }
589
+ wb.style("indent_3") { |s| s.align_horizontal("left").indent(3) }
590
+ wb.sheet("Indent") do |s|
591
+ s.column(0, width: 25)
592
+ s.column(1, width: 25)
593
+ s.print_options(:grid_lines, true)
594
+ s.row(["No Indent"])
595
+ s.row(["Indent 1"], styles: { 0 => "indent_1" })
596
+ s.row(["Indent 3"], styles: { 0 => "indent_3" })
673
597
  end
674
598
  end
675
599
 
@@ -680,12 +604,12 @@ sheet = workbook.sheets.first
680
604
  row = sheet.rows.first
681
605
  row.cells.each do |c|
682
606
  xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
683
- align_h = xf ? xf.dig(:alignment, :horizontal) : nil
684
- align_v = xf ? xf.dig(:alignment, :vertical) : nil
685
- wrap = xf ? xf.dig(:alignment, :wrap_text) : nil
686
- indent = xf ? xf.dig(:alignment, :indent) : nil
687
- rot = xf ? xf.dig(:alignment, :text_rotation) : nil
688
- shrink = xf ? xf.dig(:alignment, :shrink_to_fit) : nil
607
+ align_h = xf&.dig(:alignment, :horizontal)
608
+ align_v = xf&.dig(:alignment, :vertical)
609
+ wrap = xf&.dig(:alignment, :wrap_text)
610
+ indent = xf&.dig(:alignment, :indent)
611
+ rot = xf&.dig(:alignment, :text_rotation)
612
+ shrink = xf&.dig(:alignment, :shrink_to_fit)
689
613
  puts "Cell #{c.ref} ('#{c.value}'): align_h=#{align_h.inspect}, align_v=#{align_v.inspect}, wrap=#{wrap.inspect}, indent=#{indent.inspect}, rotation=#{rot.inspect}, shrink=#{shrink.inspect}"
690
614
  end
691
615
  ```
@@ -711,16 +635,17 @@ Demonstrates text rotated by specific angles (45, 90 degrees).
711
635
 
712
636
  ```ruby
713
637
  # frozen_string_literal: true
638
+
714
639
  require "xlsxrb"
715
640
  output_path = ARGV[0] || "align_text_rotation.xlsx"
716
- Xlsxrb.generate(output_path) do |w|
717
- w.add_style("rot_45") { |s| s.text_rotation(45) }
718
- w.add_style("rot_90") { |s| s.text_rotation(90) }
719
- w.add_sheet("Rotation") do |s|
720
- s.set_column(0, width: 25)
721
- s.set_column(1, width: 25)
722
- s.set_print_option(:grid_lines, true)
723
- s.add_row(["Rotated 45", "Rotated 90"], styles: { 0 => "rot_45", 1 => "rot_90" }, height: 50)
641
+ Xlsxrb.generate(output_path) do |wb|
642
+ wb.style("rot_45") { |s| s.text_rotation(45) }
643
+ wb.style("rot_90") { |s| s.text_rotation(90) }
644
+ wb.sheet("Rotation") do |s|
645
+ s.column(0, width: 25)
646
+ s.column(1, width: 25)
647
+ s.print_options(:grid_lines, true)
648
+ s.row(["Rotated 45", "Rotated 90"], styles: { 0 => "rot_45", 1 => "rot_90" }, height: 50)
724
649
  end
725
650
  end
726
651
 
@@ -731,12 +656,12 @@ sheet = workbook.sheets.first
731
656
  row = sheet.rows.first
732
657
  row.cells.each do |c|
733
658
  xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
734
- align_h = xf ? xf.dig(:alignment, :horizontal) : nil
735
- align_v = xf ? xf.dig(:alignment, :vertical) : nil
736
- wrap = xf ? xf.dig(:alignment, :wrap_text) : nil
737
- indent = xf ? xf.dig(:alignment, :indent) : nil
738
- rot = xf ? xf.dig(:alignment, :text_rotation) : nil
739
- shrink = xf ? xf.dig(:alignment, :shrink_to_fit) : nil
659
+ align_h = xf&.dig(:alignment, :horizontal)
660
+ align_v = xf&.dig(:alignment, :vertical)
661
+ wrap = xf&.dig(:alignment, :wrap_text)
662
+ indent = xf&.dig(:alignment, :indent)
663
+ rot = xf&.dig(:alignment, :text_rotation)
664
+ shrink = xf&.dig(:alignment, :shrink_to_fit)
740
665
  puts "Cell #{c.ref} ('#{c.value}'): align_h=#{align_h.inspect}, align_v=#{align_v.inspect}, wrap=#{wrap.inspect}, indent=#{indent.inspect}, rotation=#{rot.inspect}, shrink=#{shrink.inspect}"
741
666
  end
742
667
  ```
@@ -763,14 +688,15 @@ Demonstrates auto-wrapping multi-line text inside narrow cells.
763
688
 
764
689
  ```ruby
765
690
  # frozen_string_literal: true
691
+
766
692
  require "xlsxrb"
767
693
  output_path = ARGV[0] || "align_text_wrap.xlsx"
768
- Xlsxrb.generate(output_path) do |w|
769
- w.add_style("wrap") { |s| s.wrap_text }
770
- w.add_sheet("Text Wrap") do |s|
771
- s.set_print_option(:grid_lines, true)
772
- s.set_column(0, width: 15)
773
- s.add_row(["This is a long sentence that wraps inside the cell."], styles: { 0 => "wrap" })
694
+ Xlsxrb.generate(output_path) do |wb|
695
+ wb.style("wrap", &:wrap_text)
696
+ wb.sheet("Text Wrap") do |s|
697
+ s.print_options(:grid_lines, true)
698
+ s.column(0, width: 15)
699
+ s.row(["This is a long sentence that wraps inside the cell."], styles: { 0 => "wrap" })
774
700
  end
775
701
  end
776
702
 
@@ -781,12 +707,12 @@ sheet = workbook.sheets.first
781
707
  row = sheet.rows.first
782
708
  row.cells.each do |c|
783
709
  xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
784
- align_h = xf ? xf.dig(:alignment, :horizontal) : nil
785
- align_v = xf ? xf.dig(:alignment, :vertical) : nil
786
- wrap = xf ? xf.dig(:alignment, :wrap_text) : nil
787
- indent = xf ? xf.dig(:alignment, :indent) : nil
788
- rot = xf ? xf.dig(:alignment, :text_rotation) : nil
789
- shrink = xf ? xf.dig(:alignment, :shrink_to_fit) : nil
710
+ align_h = xf&.dig(:alignment, :horizontal)
711
+ align_v = xf&.dig(:alignment, :vertical)
712
+ wrap = xf&.dig(:alignment, :wrap_text)
713
+ indent = xf&.dig(:alignment, :indent)
714
+ rot = xf&.dig(:alignment, :text_rotation)
715
+ shrink = xf&.dig(:alignment, :shrink_to_fit)
790
716
  puts "Cell #{c.ref} ('#{c.value}'): align_h=#{align_h.inspect}, align_v=#{align_v.inspect}, wrap=#{wrap.inspect}, indent=#{indent.inspect}, rotation=#{rot.inspect}, shrink=#{shrink.inspect}"
791
717
  end
792
718
  ```
@@ -812,17 +738,18 @@ Demonstrates vertical text alignment (top, center, bottom).
812
738
 
813
739
  ```ruby
814
740
  # frozen_string_literal: true
741
+
815
742
  require "xlsxrb"
816
743
  output_path = ARGV[0] || "align_vertical.xlsx"
817
- Xlsxrb.generate(output_path) do |w|
818
- w.add_style("top") { |s| s.align_vertical("top") }
819
- w.add_style("center") { |s| s.align_vertical("center") }
820
- w.add_style("bottom") { |s| s.align_vertical("bottom") }
821
- w.add_sheet("Vertical Alignment") do |s|
822
- s.set_column(0, width: 25)
823
- s.set_column(1, width: 25)
824
- s.set_print_option(:grid_lines, true)
825
- s.add_row(["Top", "Center", "Bottom"], styles: { 0 => "top", 1 => "center", 2 => "bottom" }, height: 40)
744
+ Xlsxrb.generate(output_path) do |wb|
745
+ wb.style("top") { |s| s.align_vertical("top") }
746
+ wb.style("center") { |s| s.align_vertical("center") }
747
+ wb.style("bottom") { |s| s.align_vertical("bottom") }
748
+ wb.sheet("Vertical Alignment") do |s|
749
+ s.column(0, width: 25)
750
+ s.column(1, width: 25)
751
+ s.print_options(:grid_lines, true)
752
+ s.row(%w[Top Center Bottom], styles: { 0 => "top", 1 => "center", 2 => "bottom" }, height: 40)
826
753
  end
827
754
  end
828
755
 
@@ -833,12 +760,12 @@ sheet = workbook.sheets.first
833
760
  row = sheet.rows.first
834
761
  row.cells.each do |c|
835
762
  xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
836
- align_h = xf ? xf.dig(:alignment, :horizontal) : nil
837
- align_v = xf ? xf.dig(:alignment, :vertical) : nil
838
- wrap = xf ? xf.dig(:alignment, :wrap_text) : nil
839
- indent = xf ? xf.dig(:alignment, :indent) : nil
840
- rot = xf ? xf.dig(:alignment, :text_rotation) : nil
841
- shrink = xf ? xf.dig(:alignment, :shrink_to_fit) : nil
763
+ align_h = xf&.dig(:alignment, :horizontal)
764
+ align_v = xf&.dig(:alignment, :vertical)
765
+ wrap = xf&.dig(:alignment, :wrap_text)
766
+ indent = xf&.dig(:alignment, :indent)
767
+ rot = xf&.dig(:alignment, :text_rotation)
768
+ shrink = xf&.dig(:alignment, :shrink_to_fit)
842
769
  puts "Cell #{c.ref} ('#{c.value}'): align_h=#{align_h.inspect}, align_v=#{align_v.inspect}, wrap=#{wrap.inspect}, indent=#{indent.inspect}, rotation=#{rot.inspect}, shrink=#{shrink.inspect}"
843
770
  end
844
771
  ```
@@ -872,17 +799,17 @@ require "date"
872
799
 
873
800
  output_path = ARGV[0] || "basic_data.xlsx"
874
801
 
875
- Xlsxrb.generate(output_path) do |w|
876
- w.add_style("currency") { |style| style.number_format("$#,##0.00") }
877
- w.add_style("date") { |style| style.number_format("yyyy-mm-dd") }
878
- w.add_sheet("Basic Data") do
879
- w.set_sheet_property(:fit_to_page, true)
880
- w.set_page_setup(fit_to_width: 1, fit_to_height: 1)
881
- w.set_column(0, width: 25)
882
- w.set_column(1, width: 25)
883
- w.add_row(["Product", "Qty", "Price", "Date", "Active"])
884
- w.add_row(["Gadget A", 10, 99.99, Date.new(2026, 1, 15), true], styles: { 2 => "currency", 3 => "date" })
885
- w.add_row(["Widget B", 5, 49.50, Date.new(2026, 2, 20), false], styles: { 2 => "currency", 3 => "date" })
802
+ Xlsxrb.generate(output_path) do |wb|
803
+ wb.style("currency") { |style| style.number_format("$#,##0.00") }
804
+ wb.style("date") { |style| style.number_format("yyyy-mm-dd") }
805
+ wb.sheet("Basic Data") do |sheet|
806
+ sheet.sheet_properties(:fit_to_page, true)
807
+ sheet.page_setup(fit_to_width: 1, fit_to_height: 1)
808
+ sheet.column(0, width: 25)
809
+ sheet.column(1, width: 25)
810
+ sheet.row(%w[Product Qty Price Date Active])
811
+ sheet.row(["Gadget A", 10, 99.99, Date.new(2026, 1, 15), true], styles: { 2 => "currency", 3 => "date" })
812
+ sheet.row(["Widget B", 5, 49.50, Date.new(2026, 2, 20), false], styles: { 2 => "currency", 3 => "date" })
886
813
  end
887
814
  end
888
815
 
@@ -894,7 +821,7 @@ sheet.rows.each do |row|
894
821
  row_cells = row.cells.map do |c|
895
822
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
896
823
  end
897
- puts "Row #{row.index}: #{row_cells.join(', ')}"
824
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
898
825
  end
899
826
  ```
900
827
 
@@ -926,40 +853,40 @@ require "xlsxrb"
926
853
 
927
854
  output_path = ARGV[0] || "borders.xlsx"
928
855
 
929
- Xlsxrb.generate(output_path) do |w|
930
- w.add_style("thin") { |s| s.border_all(style: "thin", color: "FF000000") }
931
- w.add_style("medium") { |s| s.border_all(style: "medium", color: "FF000000") }
932
- w.add_style("thick") { |s| s.border_all(style: "thick", color: "FF000000") }
933
- w.add_style("hair") { |s| s.border_all(style: "hair", color: "FF000000") }
934
- w.add_style("dashed") { |s| s.border_all(style: "dashed", color: "FF000000") }
935
- w.add_style("medium_dashed") { |s| s.border_all(style: "mediumDashed", color: "FF000000") }
936
- w.add_style("dotted") { |s| s.border_all(style: "dotted", color: "FF000000") }
937
- w.add_style("double") { |s| s.border_all(style: "double", color: "FF000000") }
938
- w.add_style("dash_dot") { |s| s.border_all(style: "dashDot", color: "FF000000") }
939
- w.add_style("medium_dash_dot") { |s| s.border_all(style: "mediumDashDot", color: "FF000000") }
940
- w.add_style("dash_dot_dot") { |s| s.border_all(style: "dashDotDot", color: "FF000000") }
941
- w.add_style("slanted") { |s| s.border_all(style: "slantedDashDot", color: "FF000000") }
942
- w.add_style("diagonal") { |s| s.border_diagonal(style: "thin", color: "FF000000", up: true, down: true) }
943
-
944
- w.add_sheet("Borders") do |s|
945
- s.set_column(0, width: 25)
946
- s.set_column(1, width: 25)
947
- s.set_print_option(:grid_lines, true)
948
-
949
- s.add_row(["Border Style", "Cell Preview"])
950
- s.add_row(["Thin", "Thin Border"], styles: { 1 => "thin" })
951
- s.add_row(["Medium", "Medium Border"], styles: { 1 => "medium" })
952
- s.add_row(["Thick", "Thick Border"], styles: { 1 => "thick" })
953
- s.add_row(["Hair", "Hair Border"], styles: { 1 => "hair" })
954
- s.add_row(["Dashed", "Dashed Border"], styles: { 1 => "dashed" })
955
- s.add_row(["Medium Dashed", "Medium Dashed"], styles: { 1 => "medium_dashed" })
956
- s.add_row(["Dotted", "Dotted Border"], styles: { 1 => "dotted" })
957
- s.add_row(["Double", "Double Border"], styles: { 1 => "double" })
958
- s.add_row(["Dash-Dot", "Dash-Dot Border"], styles: { 1 => "dash_dot" })
959
- s.add_row(["Medium Dash-Dot", "Medium Dash-Dot"], styles: { 1 => "medium_dash_dot" })
960
- s.add_row(["Dash-Dot-Dot", "Dash-Dot-Dot"], styles: { 1 => "dash_dot_dot" })
961
- s.add_row(["Slanted Dash-Dot", "Slanted Border"], styles: { 1 => "slanted" })
962
- s.add_row(["Diagonal (Cross)", "Diagonal Border"], styles: { 1 => "diagonal" })
856
+ Xlsxrb.generate(output_path) do |wb|
857
+ wb.style("thin") { |s| s.border_all(style: "thin", color: "FF000000") }
858
+ wb.style("medium") { |s| s.border_all(style: "medium", color: "FF000000") }
859
+ wb.style("thick") { |s| s.border_all(style: "thick", color: "FF000000") }
860
+ wb.style("hair") { |s| s.border_all(style: "hair", color: "FF000000") }
861
+ wb.style("dashed") { |s| s.border_all(style: "dashed", color: "FF000000") }
862
+ wb.style("medium_dashed") { |s| s.border_all(style: "mediumDashed", color: "FF000000") }
863
+ wb.style("dotted") { |s| s.border_all(style: "dotted", color: "FF000000") }
864
+ wb.style("double") { |s| s.border_all(style: "double", color: "FF000000") }
865
+ wb.style("dash_dot") { |s| s.border_all(style: "dashDot", color: "FF000000") }
866
+ wb.style("medium_dash_dot") { |s| s.border_all(style: "mediumDashDot", color: "FF000000") }
867
+ wb.style("dash_dot_dot") { |s| s.border_all(style: "dashDotDot", color: "FF000000") }
868
+ wb.style("slanted") { |s| s.border_all(style: "slantedDashDot", color: "FF000000") }
869
+ wb.style("diagonal") { |s| s.border_diagonal(style: "thin", color: "FF000000", up: true, down: true) }
870
+
871
+ wb.sheet("Borders") do |s|
872
+ s.column(0, width: 25)
873
+ s.column(1, width: 25)
874
+ s.print_options(:grid_lines, true)
875
+
876
+ s.row(["Border Style", "Cell Preview"])
877
+ s.row(["Thin", "Thin Border"], styles: { 1 => "thin" })
878
+ s.row(["Medium", "Medium Border"], styles: { 1 => "medium" })
879
+ s.row(["Thick", "Thick Border"], styles: { 1 => "thick" })
880
+ s.row(["Hair", "Hair Border"], styles: { 1 => "hair" })
881
+ s.row(["Dashed", "Dashed Border"], styles: { 1 => "dashed" })
882
+ s.row(["Medium Dashed", "Medium Dashed"], styles: { 1 => "medium_dashed" })
883
+ s.row(["Dotted", "Dotted Border"], styles: { 1 => "dotted" })
884
+ s.row(["Double", "Double Border"], styles: { 1 => "double" })
885
+ s.row(["Dash-Dot", "Dash-Dot Border"], styles: { 1 => "dash_dot" })
886
+ s.row(["Medium Dash-Dot", "Medium Dash-Dot"], styles: { 1 => "medium_dash_dot" })
887
+ s.row(%w[Dash-Dot-Dot Dash-Dot-Dot], styles: { 1 => "dash_dot_dot" })
888
+ s.row(["Slanted Dash-Dot", "Slanted Border"], styles: { 1 => "slanted" })
889
+ s.row(["Diagonal (Cross)", "Diagonal Border"], styles: { 1 => "diagonal" })
963
890
  end
964
891
  end
965
892
 
@@ -973,7 +900,7 @@ sheet.rows.each do |row|
973
900
  border_id = xf ? xf[:border_id] : 0
974
901
  "#{c.ref}: #{c.value.inspect} (border_id: #{border_id})"
975
902
  end
976
- puts "Row #{row.index}: #{row_cells.join(', ')}"
903
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
977
904
  end
978
905
  ```
979
906
 
@@ -1011,15 +938,16 @@ Demonstrates boolean values serialized and rendered.
1011
938
 
1012
939
  ```ruby
1013
940
  # frozen_string_literal: true
941
+
1014
942
  require "xlsxrb"
1015
943
  output_path = ARGV[0] || "cell_booleans.xlsx"
1016
- Xlsxrb.generate(output_path) do |w|
1017
- w.add_sheet("Booleans") do |s|
1018
- s.set_column(0, width: 25)
1019
- s.set_column(1, width: 25)
1020
- s.add_row(["Label", "Boolean Value"])
1021
- s.add_row(["Is Active", true])
1022
- s.add_row(["Is Pending", false])
944
+ Xlsxrb.generate(output_path) do |wb|
945
+ wb.sheet("Booleans") do |s|
946
+ s.column(0, width: 25)
947
+ s.column(1, width: 25)
948
+ s.row(["Label", "Boolean Value"])
949
+ s.row(["Is Active", true])
950
+ s.row(["Is Pending", false])
1023
951
  end
1024
952
  end
1025
953
 
@@ -1031,7 +959,7 @@ sheet.rows.each do |row|
1031
959
  row_cells = row.cells.map do |c|
1032
960
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1033
961
  end
1034
- puts "Row #{row.index}: #{row_cells.join(', ')}"
962
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1035
963
  end
1036
964
  ```
1037
965
 
@@ -1058,17 +986,18 @@ Demonstrates dates serialized natively and formatted with standard or custom for
1058
986
 
1059
987
  ```ruby
1060
988
  # frozen_string_literal: true
989
+
1061
990
  require "xlsxrb"
1062
991
  require "date"
1063
992
  output_path = ARGV[0] || "cell_dates.xlsx"
1064
- Xlsxrb.generate(output_path) do |w|
1065
- w.add_style("custom_date") { |s| s.num_fmt("yyyy-mm-dd") }
1066
- w.add_sheet("Dates") do |s|
1067
- s.set_column(0, width: 25)
1068
- s.set_column(1, width: 25)
1069
- s.add_row(["Format", "Date Value"])
1070
- s.add_row(["Default Date", Date.new(2026, 7, 1)])
1071
- s.add_row(["Formatted Date", Date.new(2026, 12, 25)], styles: { 1 => "custom_date" })
993
+ Xlsxrb.generate(output_path) do |wb|
994
+ wb.style("custom_date") { |s| s.num_fmt("yyyy-mm-dd") }
995
+ wb.sheet("Dates") do |s|
996
+ s.column(0, width: 25)
997
+ s.column(1, width: 25)
998
+ s.row(["Format", "Date Value"])
999
+ s.row(["Default Date", Date.new(2026, 7, 1)])
1000
+ s.row(["Formatted Date", Date.new(2026, 12, 25)], styles: { 1 => "custom_date" })
1072
1001
  end
1073
1002
  end
1074
1003
 
@@ -1080,7 +1009,7 @@ sheet.rows.each do |row|
1080
1009
  row_cells = row.cells.map do |c|
1081
1010
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1082
1011
  end
1083
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1012
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1084
1013
  end
1085
1014
  ```
1086
1015
 
@@ -1107,17 +1036,18 @@ Demonstrates standard spreadsheet calculations and formulas (SUM, AVERAGE).
1107
1036
 
1108
1037
  ```ruby
1109
1038
  # frozen_string_literal: true
1039
+
1110
1040
  require "xlsxrb"
1111
1041
  output_path = ARGV[0] || "cell_formulas.xlsx"
1112
- Xlsxrb.generate(output_path) do |w|
1113
- w.add_sheet("Formulas") do |s|
1114
- s.set_column(0, width: 25)
1115
- s.set_column(1, width: 25)
1116
- s.add_row(["Item", "Value"])
1117
- s.add_row(["A", 10])
1118
- s.add_row(["B", 20])
1119
- s.add_row(["SUM", Xlsxrb::Elements::Formula.new(expression: "SUM(B2:B3)", cached_value: 30)])
1120
- s.add_row(["AVERAGE", Xlsxrb::Elements::Formula.new(expression: "AVERAGE(B2:B3)", cached_value: 15)])
1042
+ Xlsxrb.generate(output_path) do |wb|
1043
+ wb.sheet("Formulas") do |s|
1044
+ s.column(0, width: 25)
1045
+ s.column(1, width: 25)
1046
+ s.row(%w[Item Value])
1047
+ s.row(["A", 10])
1048
+ s.row(["B", 20])
1049
+ s.row(["SUM", Xlsxrb::Elements::Formula.new(expression: "SUM(B2:B3)", cached_value: 30)])
1050
+ s.row(["AVERAGE", Xlsxrb::Elements::Formula.new(expression: "AVERAGE(B2:B3)", cached_value: 15)])
1121
1051
  end
1122
1052
  end
1123
1053
 
@@ -1129,7 +1059,7 @@ sheet.rows.each do |row|
1129
1059
  row_cells = row.cells.map do |c|
1130
1060
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1131
1061
  end
1132
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1062
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1133
1063
  end
1134
1064
  ```
1135
1065
 
@@ -1158,16 +1088,17 @@ Demonstrates Yen Currency format code formatting.
1158
1088
 
1159
1089
  ```ruby
1160
1090
  # frozen_string_literal: true
1091
+
1161
1092
  require "xlsxrb"
1162
1093
  output_path = ARGV[0] || "cell_num_currency_jpy.xlsx"
1163
- Xlsxrb.generate(output_path) do |w|
1164
- w.add_style("jpy") { |s| s.num_fmt("¥#,##0;[Red]¥-#,##0") }
1165
- w.add_sheet("JPY Currency") do |s|
1166
- s.set_column(0, width: 25)
1167
- s.set_column(1, width: 25)
1168
- s.add_row(["Format", "Value"])
1169
- s.add_row(["Positive Yen", 12500], styles: { 1 => "jpy" })
1170
- s.add_row(["Negative Yen", -8000], styles: { 1 => "jpy" })
1094
+ Xlsxrb.generate(output_path) do |wb|
1095
+ wb.style("jpy") { |s| s.num_fmt("¥#,##0;[Red]¥-#,##0") }
1096
+ wb.sheet("JPY Currency") do |s|
1097
+ s.column(0, width: 25)
1098
+ s.column(1, width: 25)
1099
+ s.row(%w[Format Value])
1100
+ s.row(["Positive Yen", 12_500], styles: { 1 => "jpy" })
1101
+ s.row(["Negative Yen", -8000], styles: { 1 => "jpy" })
1171
1102
  end
1172
1103
  end
1173
1104
 
@@ -1181,7 +1112,7 @@ sheet.rows.each do |row|
1181
1112
  num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1182
1113
  "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1183
1114
  end
1184
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1115
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1185
1116
  end
1186
1117
  ```
1187
1118
 
@@ -1208,16 +1139,17 @@ Demonstrates custom colored formats for positive and negative numbers.
1208
1139
 
1209
1140
  ```ruby
1210
1141
  # frozen_string_literal: true
1142
+
1211
1143
  require "xlsxrb"
1212
1144
  output_path = ARGV[0] || "cell_num_custom_colors.xlsx"
1213
- Xlsxrb.generate(output_path) do |w|
1214
- w.add_style("custom_color") { |s| s.num_fmt("[Green]#,##0;[Red]-#,##0") }
1215
- w.add_sheet("Custom Colors") do |s|
1216
- s.set_column(0, width: 25)
1217
- s.set_column(1, width: 25)
1218
- s.add_row(["Format", "Value"])
1219
- s.add_row(["Positive (Green)", 5000], styles: { 1 => "custom_color" })
1220
- s.add_row(["Negative (Red)", -2500], styles: { 1 => "custom_color" })
1145
+ Xlsxrb.generate(output_path) do |wb|
1146
+ wb.style("custom_color") { |s| s.num_fmt("[Green]#,##0;[Red]-#,##0") }
1147
+ wb.sheet("Custom Colors") do |s|
1148
+ s.column(0, width: 25)
1149
+ s.column(1, width: 25)
1150
+ s.row(%w[Format Value])
1151
+ s.row(["Positive (Green)", 5000], styles: { 1 => "custom_color" })
1152
+ s.row(["Negative (Red)", -2500], styles: { 1 => "custom_color" })
1221
1153
  end
1222
1154
  end
1223
1155
 
@@ -1231,7 +1163,7 @@ sheet.rows.each do |row|
1231
1163
  num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1232
1164
  "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1233
1165
  end
1234
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1166
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1235
1167
  end
1236
1168
  ```
1237
1169
 
@@ -1258,17 +1190,18 @@ Demonstrates fraction number formats (# ?/?).
1258
1190
 
1259
1191
  ```ruby
1260
1192
  # frozen_string_literal: true
1193
+
1261
1194
  require "xlsxrb"
1262
1195
  output_path = ARGV[0] || "cell_num_fractions.xlsx"
1263
- Xlsxrb.generate(output_path) do |w|
1264
- w.add_style("frac") { |s| s.num_fmt("# ?/?") }
1265
- w.add_sheet("Fractions") do |s|
1266
- s.set_column(0, width: 25)
1267
- s.set_column(1, width: 25)
1268
- s.add_row(["Format", "Value"])
1269
- s.add_row(["Half", 0.5], styles: { 1 => "frac" })
1270
- s.add_row(["Third", 0.3333], styles: { 1 => "frac" })
1271
- s.add_row(["Quarter", 0.75], styles: { 1 => "frac" })
1196
+ Xlsxrb.generate(output_path) do |wb|
1197
+ wb.style("frac") { |s| s.num_fmt("# ?/?") }
1198
+ wb.sheet("Fractions") do |s|
1199
+ s.column(0, width: 25)
1200
+ s.column(1, width: 25)
1201
+ s.row(%w[Format Value])
1202
+ s.row(["Half", 0.5], styles: { 1 => "frac" })
1203
+ s.row(["Third", 0.3333], styles: { 1 => "frac" })
1204
+ s.row(["Quarter", 0.75], styles: { 1 => "frac" })
1272
1205
  end
1273
1206
  end
1274
1207
 
@@ -1282,7 +1215,7 @@ sheet.rows.each do |row|
1282
1215
  num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1283
1216
  "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1284
1217
  end
1285
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1218
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1286
1219
  end
1287
1220
  ```
1288
1221
 
@@ -1310,15 +1243,16 @@ Demonstrates percentages with two decimal places (0.00%).
1310
1243
 
1311
1244
  ```ruby
1312
1245
  # frozen_string_literal: true
1246
+
1313
1247
  require "xlsxrb"
1314
1248
  output_path = ARGV[0] || "cell_num_percent_decimals.xlsx"
1315
- Xlsxrb.generate(output_path) do |w|
1316
- w.add_style("pct2") { |s| s.num_fmt("0.00%") }
1317
- w.add_sheet("Percents") do |s|
1318
- s.set_column(0, width: 25)
1319
- s.set_column(1, width: 25)
1320
- s.add_row(["Format", "Value"])
1321
- s.add_row(["Percent with 2 Decimals", 0.12345], styles: { 1 => "pct2" })
1249
+ Xlsxrb.generate(output_path) do |wb|
1250
+ wb.style("pct2") { |s| s.num_fmt("0.00%") }
1251
+ wb.sheet("Percents") do |s|
1252
+ s.column(0, width: 25)
1253
+ s.column(1, width: 25)
1254
+ s.row(%w[Format Value])
1255
+ s.row(["Percent with 2 Decimals", 0.12345], styles: { 1 => "pct2" })
1322
1256
  end
1323
1257
  end
1324
1258
 
@@ -1332,7 +1266,7 @@ sheet.rows.each do |row|
1332
1266
  num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1333
1267
  "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1334
1268
  end
1335
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1269
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1336
1270
  end
1337
1271
  ```
1338
1272
 
@@ -1358,16 +1292,17 @@ Demonstrates scientific number formats (0.00E+00).
1358
1292
 
1359
1293
  ```ruby
1360
1294
  # frozen_string_literal: true
1295
+
1361
1296
  require "xlsxrb"
1362
1297
  output_path = ARGV[0] || "cell_num_scientific.xlsx"
1363
- Xlsxrb.generate(output_path) do |w|
1364
- w.add_style("sci") { |s| s.num_fmt("0.00E+00") }
1365
- w.add_sheet("Scientific") do |s|
1366
- s.set_column(0, width: 25)
1367
- s.set_column(1, width: 25)
1368
- s.add_row(["Format", "Value"])
1369
- s.add_row(["Scientific", 123456789.0], styles: { 1 => "sci" })
1370
- s.add_row(["Small Scientific", 0.00001234], styles: { 1 => "sci" })
1298
+ Xlsxrb.generate(output_path) do |wb|
1299
+ wb.style("sci") { |s| s.num_fmt("0.00E+00") }
1300
+ wb.sheet("Scientific") do |s|
1301
+ s.column(0, width: 25)
1302
+ s.column(1, width: 25)
1303
+ s.row(%w[Format Value])
1304
+ s.row(["Scientific", 123_456_789.0], styles: { 1 => "sci" })
1305
+ s.row(["Small Scientific", 0.00001234], styles: { 1 => "sci" })
1371
1306
  end
1372
1307
  end
1373
1308
 
@@ -1381,7 +1316,7 @@ sheet.rows.each do |row|
1381
1316
  num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1382
1317
  "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1383
1318
  end
1384
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1319
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1385
1320
  end
1386
1321
  ```
1387
1322
 
@@ -1408,19 +1343,20 @@ Demonstrates custom formatting for integers, floating point numbers, currencies,
1408
1343
 
1409
1344
  ```ruby
1410
1345
  # frozen_string_literal: true
1346
+
1411
1347
  require "xlsxrb"
1412
1348
  output_path = ARGV[0] || "cell_numbers.xlsx"
1413
- Xlsxrb.generate(output_path) do |w|
1414
- w.add_style("currency") { |s| s.num_fmt("$#,##0.00") }
1415
- w.add_style("percent") { |s| s.num_fmt("0.0%") }
1416
- w.add_sheet("Numbers") do |s|
1417
- s.set_column(0, width: 25)
1418
- s.set_column(1, width: 25)
1419
- s.add_row(["Format", "Value"])
1420
- s.add_row(["Integer", 12345])
1421
- s.add_row(["Float", 123.456])
1422
- s.add_row(["Currency", 1234.5], styles: { 1 => "currency" })
1423
- s.add_row(["Percentage", 0.85], styles: { 1 => "percent" })
1349
+ Xlsxrb.generate(output_path) do |wb|
1350
+ wb.style("currency") { |s| s.num_fmt("$#,##0.00") }
1351
+ wb.style("percent") { |s| s.num_fmt("0.0%") }
1352
+ wb.sheet("Numbers") do |s|
1353
+ s.column(0, width: 25)
1354
+ s.column(1, width: 25)
1355
+ s.row(%w[Format Value])
1356
+ s.row(["Integer", 12_345])
1357
+ s.row(["Float", 123.456])
1358
+ s.row(["Currency", 1234.5], styles: { 1 => "currency" })
1359
+ s.row(["Percentage", 0.85], styles: { 1 => "percent" })
1424
1360
  end
1425
1361
  end
1426
1362
 
@@ -1432,7 +1368,7 @@ sheet.rows.each do |row|
1432
1368
  row_cells = row.cells.map do |c|
1433
1369
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1434
1370
  end
1435
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1371
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1436
1372
  end
1437
1373
  ```
1438
1374
 
@@ -1461,19 +1397,20 @@ Demonstrates Rich Text cells with multiple font weights, styles, and colors in a
1461
1397
 
1462
1398
  ```ruby
1463
1399
  # frozen_string_literal: true
1400
+
1464
1401
  require "xlsxrb"
1465
1402
  output_path = ARGV[0] || "cell_rich_text.xlsx"
1466
- Xlsxrb.generate(output_path) do |w|
1467
- rt = Xlsxrb::Elements::RichText.new(runs: [
1403
+ Xlsxrb.generate(output_path) do |wb|
1404
+ rt = Xlsxrb.rich_text(
1468
1405
  { text: "Normal " },
1469
1406
  { text: "BOLD RED ", font: { bold: true, color: "FFC00000", sz: 16 } },
1470
- { text: "ITALIC BLUE", font: { italic: true, color: "FF0000FF", sz: 20 } }
1471
- ])
1472
- w.add_sheet("Rich Text") do |s|
1473
- s.set_column(0, width: 25)
1474
- s.set_column(1, width: 25)
1475
- s.add_row(["Format", "Value"])
1476
- s.add_row(["Rich Text Cell", rt])
1407
+ { text: "ITALIC BLUE", font: { italic: true, color: :blue, sz: 20 } }
1408
+ )
1409
+ wb.sheet("Rich Text") do |s|
1410
+ s.column(0, width: 25)
1411
+ s.column(1, width: 25)
1412
+ s.row(%w[Format Value])
1413
+ s.row(["Rich Text Cell", rt])
1477
1414
  end
1478
1415
  end
1479
1416
 
@@ -1485,18 +1422,10 @@ sheet.rows.each do |row|
1485
1422
  row_cells = row.cells.map do |c|
1486
1423
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1487
1424
  end
1488
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1425
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1489
1426
  end
1490
1427
  ```
1491
1428
 
1492
- ### Console Output
1493
-
1494
- ```text
1495
- === Read Validation ===
1496
- Row 0: A1: "Format" (String), B1: "Value" (String)
1497
- Row 1: A2: "Rich Text Cell" (String), B2: "Normal BOLD RED ITALIC BLUE" (String)
1498
- ```
1499
-
1500
1429
  <hr/>
1501
1430
 
1502
1431
  ## Cell Times
@@ -1511,17 +1440,18 @@ Demonstrates timestamp values serialized natively and formatted showing hours, m
1511
1440
 
1512
1441
  ```ruby
1513
1442
  # frozen_string_literal: true
1443
+
1514
1444
  require "xlsxrb"
1515
1445
  require "time"
1516
1446
  output_path = ARGV[0] || "cell_times.xlsx"
1517
- Xlsxrb.generate(output_path) do |w|
1518
- w.add_style("time_fmt") { |s| s.num_fmt("hh:mm:ss") }
1519
- w.add_sheet("Times") do |s|
1520
- s.set_column(0, width: 25)
1521
- s.set_column(1, width: 25)
1522
- s.add_row(["Format", "Time Value"])
1523
- s.add_row(["DateTime", Time.new(2026, 7, 1, 12, 34, 56)])
1524
- s.add_row(["Time Only", Time.new(2026, 7, 1, 9, 15, 0)], styles: { 1 => "time_fmt" })
1447
+ Xlsxrb.generate(output_path) do |wb|
1448
+ wb.style("time_fmt") { |s| s.num_fmt("hh:mm:ss") }
1449
+ wb.sheet("Times") do |s|
1450
+ s.column(0, width: 25)
1451
+ s.column(1, width: 25)
1452
+ s.row(["Format", "Time Value"])
1453
+ s.row(["DateTime", Time.new(2026, 7, 1, 12, 34, 56)])
1454
+ s.row(["Time Only", Time.new(2026, 7, 1, 9, 15, 0)], styles: { 1 => "time_fmt" })
1525
1455
  end
1526
1456
  end
1527
1457
 
@@ -1533,7 +1463,7 @@ sheet.rows.each do |row|
1533
1463
  row_cells = row.cells.map do |c|
1534
1464
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1535
1465
  end
1536
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1466
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1537
1467
  end
1538
1468
  ```
1539
1469
 
@@ -1560,17 +1490,18 @@ Demonstrates conditional formatting highlighting cells starting with specific te
1560
1490
 
1561
1491
  ```ruby
1562
1492
  # frozen_string_literal: true
1493
+
1563
1494
  require "xlsxrb"
1564
1495
  output_path = ARGV[0] || "cf_begins_with.xlsx"
1565
- Xlsxrb.generate(output_path) do |w|
1566
- w.add_sheet("CF Begins") do |s|
1567
- s.set_column(0, width: 25)
1568
- s.set_column(1, width: 25)
1569
- s.add_row(["Code"])
1570
- s.add_row(["A-100"])
1571
- s.add_row(["B-200"])
1572
- s.add_row(["A-300"])
1573
- s.add_conditional_format("A2:A4", type: "beginsWith", operator: "beginsWith", text: "A", formula: 'LEFT(A2,1)="A"', fill_color: "FFFFC7CE")
1496
+ Xlsxrb.generate(output_path) do |wb|
1497
+ wb.sheet("CF Begins") do |s|
1498
+ s.column(0, width: 25)
1499
+ s.column(1, width: 25)
1500
+ s.row(["Code"])
1501
+ s.row(["A-100"])
1502
+ s.row(["B-200"])
1503
+ s.row(["A-300"])
1504
+ s.conditional_format("A2:A4", type: "beginsWith", operator: "beginsWith", text: "A", formula: 'LEFT(A2,1)="A"', fill_color: "FFFFC7CE")
1574
1505
  end
1575
1506
  end
1576
1507
 
@@ -1580,7 +1511,7 @@ workbook = Xlsxrb.read(output_path)
1580
1511
  sheet = workbook.sheets.first
1581
1512
  sheet.rows.first(5).each do |row|
1582
1513
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1583
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1514
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1584
1515
  end
1585
1516
  ```
1586
1517
 
@@ -1608,18 +1539,19 @@ Demonstrates conditional formatting highlighting cells within a range.
1608
1539
 
1609
1540
  ```ruby
1610
1541
  # frozen_string_literal: true
1542
+
1611
1543
  require "xlsxrb"
1612
1544
  output_path = ARGV[0] || "cf_cell_between.xlsx"
1613
- Xlsxrb.generate(output_path) do |w|
1614
- w.add_style("center") { |style| style.align_horizontal("center") }
1615
- w.add_sheet("CF Between") do |s|
1616
- s.set_column(0, width: 25)
1617
- s.set_column(1, width: 25)
1618
- s.add_row(["Values"])
1619
- s.add_row([15], styles: ["center"])
1620
- s.add_row([25], styles: ["center"])
1621
- s.add_row([5], styles: ["center"])
1622
- s.add_conditional_format("A2:A4", type: "cellIs", operator: "between", formulas: ["10", "20"], fill_color: "FF00FF00")
1545
+ Xlsxrb.generate(output_path) do |wb|
1546
+ wb.style("center") { |style| style.align_horizontal("center") }
1547
+ wb.sheet("CF Between") do |s|
1548
+ s.column(0, width: 25)
1549
+ s.column(1, width: 25)
1550
+ s.row(["Values"])
1551
+ s.row([15], styles: "center")
1552
+ s.row([25], styles: "center")
1553
+ s.row([5], styles: "center")
1554
+ s.conditional_format("A2:A4", type: "cellIs", operator: "between", formulas: %w[10 20], fill_color: :green)
1623
1555
  end
1624
1556
  end
1625
1557
 
@@ -1629,7 +1561,7 @@ workbook = Xlsxrb.read(output_path)
1629
1561
  sheet = workbook.sheets.first
1630
1562
  sheet.rows.first(5).each do |row|
1631
1563
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1632
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1564
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1633
1565
  end
1634
1566
  ```
1635
1567
 
@@ -1657,18 +1589,19 @@ Demonstrates conditional formatting highlighting cells equal to a target value.
1657
1589
 
1658
1590
  ```ruby
1659
1591
  # frozen_string_literal: true
1592
+
1660
1593
  require "xlsxrb"
1661
1594
  output_path = ARGV[0] || "cf_cell_equal_to.xlsx"
1662
- Xlsxrb.generate(output_path) do |w|
1663
- w.add_style("center") { |style| style.align_horizontal("center") }
1664
- w.add_sheet("CF Equal") do |s|
1665
- s.set_column(0, width: 25)
1666
- s.set_column(1, width: 25)
1667
- s.add_row(["Values"])
1668
- s.add_row([10], styles: ["center"])
1669
- s.add_row([20], styles: ["center"])
1670
- s.add_row([10], styles: ["center"])
1671
- s.add_conditional_format("A2:A4", type: "cellIs", operator: "equal", formula: "10", fill_color: "FFFFC7CE")
1595
+ Xlsxrb.generate(output_path) do |wb|
1596
+ wb.style("center") { |style| style.align_horizontal("center") }
1597
+ wb.sheet("CF Equal") do |s|
1598
+ s.column(0, width: 25)
1599
+ s.column(1, width: 25)
1600
+ s.row(["Values"])
1601
+ s.row([10], styles: "center")
1602
+ s.row([20], styles: "center")
1603
+ s.row([10], styles: "center")
1604
+ s.conditional_format("A2:A4", type: "cellIs", operator: "equal", formula: "10", fill_color: "FFFFC7CE")
1672
1605
  end
1673
1606
  end
1674
1607
 
@@ -1678,7 +1611,7 @@ workbook = Xlsxrb.read(output_path)
1678
1611
  sheet = workbook.sheets.first
1679
1612
  sheet.rows.first(5).each do |row|
1680
1613
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1681
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1614
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1682
1615
  end
1683
1616
  ```
1684
1617
 
@@ -1706,18 +1639,19 @@ Demonstrates conditional formatting highlighting cells greater than or equal to
1706
1639
 
1707
1640
  ```ruby
1708
1641
  # frozen_string_literal: true
1642
+
1709
1643
  require "xlsxrb"
1710
1644
  output_path = ARGV[0] || "cf_cell_greater_equal.xlsx"
1711
- Xlsxrb.generate(output_path) do |w|
1712
- w.add_style("center") { |style| style.align_horizontal("center") }
1713
- w.add_sheet("CF Greater Equal") do |s|
1714
- s.set_column(0, width: 25)
1715
- s.set_column(1, width: 25)
1716
- s.add_row(["Values"])
1717
- s.add_row([10], styles: ["center"])
1718
- s.add_row([50], styles: ["center"])
1719
- s.add_row([100], styles: ["center"])
1720
- s.add_conditional_format("A2:A4", type: "cellIs", operator: "greaterThanOrEqual", formula: "50", fill_color: "FFFFC7CE")
1645
+ Xlsxrb.generate(output_path) do |wb|
1646
+ wb.style("center") { |style| style.align_horizontal("center") }
1647
+ wb.sheet("CF Greater Equal") do |s|
1648
+ s.column(0, width: 25)
1649
+ s.column(1, width: 25)
1650
+ s.row(["Values"])
1651
+ s.row([10], styles: "center")
1652
+ s.row([50], styles: "center")
1653
+ s.row([100], styles: "center")
1654
+ s.conditional_format("A2:A4", type: "cellIs", operator: "greaterThanOrEqual", formula: "50", fill_color: "FFFFC7CE")
1721
1655
  end
1722
1656
  end
1723
1657
 
@@ -1727,7 +1661,7 @@ workbook = Xlsxrb.read(output_path)
1727
1661
  sheet = workbook.sheets.first
1728
1662
  sheet.rows.first(5).each do |row|
1729
1663
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1730
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1664
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1731
1665
  end
1732
1666
  ```
1733
1667
 
@@ -1755,18 +1689,19 @@ Demonstrates conditional formatting highlighting cells greater than a threshold.
1755
1689
 
1756
1690
  ```ruby
1757
1691
  # frozen_string_literal: true
1692
+
1758
1693
  require "xlsxrb"
1759
1694
  output_path = ARGV[0] || "cf_cell_greater_than.xlsx"
1760
- Xlsxrb.generate(output_path) do |w|
1761
- w.add_style("center") { |style| style.align_horizontal("center") }
1762
- w.add_sheet("CF Greater") do |s|
1763
- s.set_column(0, width: 25)
1764
- s.set_column(1, width: 25)
1765
- s.add_row(["Values"])
1766
- s.add_row([25], styles: ["center"])
1767
- s.add_row([75], styles: ["center"])
1768
- s.add_row([10], styles: ["center"])
1769
- s.add_conditional_format("A2:A4", type: "cellIs", operator: "greaterThan", formula: "50", fill_color: "FFFFC7CE")
1695
+ Xlsxrb.generate(output_path) do |wb|
1696
+ wb.style("center") { |style| style.align_horizontal("center") }
1697
+ wb.sheet("CF Greater") do |s|
1698
+ s.column(0, width: 25)
1699
+ s.column(1, width: 25)
1700
+ s.row(["Values"])
1701
+ s.row([25], styles: "center")
1702
+ s.row([75], styles: "center")
1703
+ s.row([10], styles: "center")
1704
+ s.conditional_format("A2:A4", type: "cellIs", operator: "greaterThan", formula: "50", fill_color: "FFFFC7CE")
1770
1705
  end
1771
1706
  end
1772
1707
 
@@ -1776,7 +1711,7 @@ workbook = Xlsxrb.read(output_path)
1776
1711
  sheet = workbook.sheets.first
1777
1712
  sheet.rows.first(5).each do |row|
1778
1713
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1779
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1714
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1780
1715
  end
1781
1716
  ```
1782
1717
 
@@ -1804,18 +1739,19 @@ Demonstrates conditional formatting highlighting cells less than a threshold.
1804
1739
 
1805
1740
  ```ruby
1806
1741
  # frozen_string_literal: true
1742
+
1807
1743
  require "xlsxrb"
1808
1744
  output_path = ARGV[0] || "cf_cell_less_than.xlsx"
1809
- Xlsxrb.generate(output_path) do |w|
1810
- w.add_style("center") { |style| style.align_horizontal("center") }
1811
- w.add_sheet("CF Less") do |s|
1812
- s.set_column(0, width: 25)
1813
- s.set_column(1, width: 25)
1814
- s.add_row(["Values"])
1815
- s.add_row([25], styles: ["center"])
1816
- s.add_row([75], styles: ["center"])
1817
- s.add_row([10], styles: ["center"])
1818
- s.add_conditional_format("A2:A4", type: "cellIs", operator: "lessThan", formula: "20", fill_color: "FFFFC7CE")
1745
+ Xlsxrb.generate(output_path) do |wb|
1746
+ wb.style("center") { |style| style.align_horizontal("center") }
1747
+ wb.sheet("CF Less") do |s|
1748
+ s.column(0, width: 25)
1749
+ s.column(1, width: 25)
1750
+ s.row(["Values"])
1751
+ s.row([25], styles: "center")
1752
+ s.row([75], styles: "center")
1753
+ s.row([10], styles: "center")
1754
+ s.conditional_format("A2:A4", type: "cellIs", operator: "lessThan", formula: "20", fill_color: "FFFFC7CE")
1819
1755
  end
1820
1756
  end
1821
1757
 
@@ -1825,7 +1761,7 @@ workbook = Xlsxrb.read(output_path)
1825
1761
  sheet = workbook.sheets.first
1826
1762
  sheet.rows.first(5).each do |row|
1827
1763
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1828
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1764
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1829
1765
  end
1830
1766
  ```
1831
1767
 
@@ -1853,17 +1789,18 @@ Demonstrates color scale/heatmap conditional formatting.
1853
1789
 
1854
1790
  ```ruby
1855
1791
  # frozen_string_literal: true
1792
+
1856
1793
  require "xlsxrb"
1857
1794
  output_path = ARGV[0] || "cf_color_scale.xlsx"
1858
- Xlsxrb.generate(output_path) do |w|
1859
- w.add_style("center") { |style| style.align_horizontal("center") }
1860
- w.add_sheet("Colors") do |s|
1861
- s.set_column(0, width: 25)
1862
- s.set_column(1, width: 25)
1863
- s.add_row([10], styles: ["center"])
1864
- s.add_row([50], styles: ["center"])
1865
- s.add_row([90], styles: ["center"])
1866
- s.add_conditional_format("A1:A3", type: :colorScale, priority: 1)
1795
+ Xlsxrb.generate(output_path) do |wb|
1796
+ wb.style("center") { |style| style.align_horizontal("center") }
1797
+ wb.sheet("Colors") do |s|
1798
+ s.column(0, width: 25)
1799
+ s.column(1, width: 25)
1800
+ s.row([10], styles: "center")
1801
+ s.row([50], styles: "center")
1802
+ s.row([90], styles: "center")
1803
+ s.conditional_format("A1:A3", type: :colorScale, priority: 1)
1867
1804
  end
1868
1805
  end
1869
1806
 
@@ -1873,7 +1810,7 @@ workbook = Xlsxrb.read(output_path)
1873
1810
  sheet = workbook.sheets.first
1874
1811
  sheet.rows.first(5).each do |row|
1875
1812
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1876
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1813
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1877
1814
  end
1878
1815
  ```
1879
1816
 
@@ -1900,17 +1837,18 @@ Demonstrates conditional formatting highlighting cells containing specific text.
1900
1837
 
1901
1838
  ```ruby
1902
1839
  # frozen_string_literal: true
1840
+
1903
1841
  require "xlsxrb"
1904
1842
  output_path = ARGV[0] || "cf_contains_text.xlsx"
1905
- Xlsxrb.generate(output_path) do |w|
1906
- w.add_sheet("CF Contains") do |s|
1907
- s.set_column(0, width: 25)
1908
- s.set_column(1, width: 25)
1909
- s.add_row(["Status"])
1910
- s.add_row(["Error"])
1911
- s.add_row(["Success"])
1912
- s.add_row(["Pending"])
1913
- s.add_conditional_format("A2:A4", type: "containsText", operator: "containsText", text: "Error", formula: 'NOT(ISERROR(SEARCH("Error",A2)))', fill_color: "FFFF0000")
1843
+ Xlsxrb.generate(output_path) do |wb|
1844
+ wb.sheet("CF Contains") do |s|
1845
+ s.column(0, width: 25)
1846
+ s.column(1, width: 25)
1847
+ s.row(["Status"])
1848
+ s.row(["Error"])
1849
+ s.row(["Success"])
1850
+ s.row(["Pending"])
1851
+ s.conditional_format("A2:A4", type: "containsText", operator: "containsText", text: "Error", formula: 'NOT(ISERROR(SEARCH("Error",A2)))', fill_color: :red)
1914
1852
  end
1915
1853
  end
1916
1854
 
@@ -1920,7 +1858,7 @@ workbook = Xlsxrb.read(output_path)
1920
1858
  sheet = workbook.sheets.first
1921
1859
  sheet.rows.first(5).each do |row|
1922
1860
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1923
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1861
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1924
1862
  end
1925
1863
  ```
1926
1864
 
@@ -1948,17 +1886,18 @@ Demonstrates data bar visual conditional formatting indicators.
1948
1886
 
1949
1887
  ```ruby
1950
1888
  # frozen_string_literal: true
1889
+
1951
1890
  require "xlsxrb"
1952
1891
  output_path = ARGV[0] || "cf_data_bar.xlsx"
1953
- Xlsxrb.generate(output_path) do |w|
1954
- w.add_style("center") { |style| style.align_horizontal("center") }
1955
- w.add_sheet("Data Bars") do |s|
1956
- s.set_column(0, width: 25)
1957
- s.set_column(1, width: 25)
1958
- s.add_row([20], styles: ["center"])
1959
- s.add_row([60], styles: ["center"])
1960
- s.add_row([100], styles: ["center"])
1961
- s.add_conditional_format("A1:A3", type: :dataBar, priority: 1, color: "FF0070C0")
1892
+ Xlsxrb.generate(output_path) do |wb|
1893
+ wb.style("center") { |style| style.align_horizontal("center") }
1894
+ wb.sheet("Data Bars") do |s|
1895
+ s.column(0, width: 25)
1896
+ s.column(1, width: 25)
1897
+ s.row([20], styles: "center")
1898
+ s.row([60], styles: "center")
1899
+ s.row([100], styles: "center")
1900
+ s.conditional_format("A1:A3", type: :dataBar, priority: 1, color: "FF0070C0")
1962
1901
  end
1963
1902
  end
1964
1903
 
@@ -1968,7 +1907,7 @@ workbook = Xlsxrb.read(output_path)
1968
1907
  sheet = workbook.sheets.first
1969
1908
  sheet.rows.first(5).each do |row|
1970
1909
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1971
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1910
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
1972
1911
  end
1973
1912
  ```
1974
1913
 
@@ -1995,17 +1934,18 @@ Demonstrates conditional formatting highlighting cells ending with specific text
1995
1934
 
1996
1935
  ```ruby
1997
1936
  # frozen_string_literal: true
1937
+
1998
1938
  require "xlsxrb"
1999
1939
  output_path = ARGV[0] || "cf_ends_with.xlsx"
2000
- Xlsxrb.generate(output_path) do |w|
2001
- w.add_sheet("CF Ends") do |s|
2002
- s.set_column(0, width: 25)
2003
- s.set_column(1, width: 25)
2004
- s.add_row(["Code"])
2005
- s.add_row(["100-Z"])
2006
- s.add_row(["200-Y"])
2007
- s.add_row(["300-Z"])
2008
- s.add_conditional_format("A2:A4", type: "endsWith", operator: "endsWith", text: "Z", formula: 'RIGHT(A2,1)="Z"', fill_color: "FFFFC7CE")
1940
+ Xlsxrb.generate(output_path) do |wb|
1941
+ wb.sheet("CF Ends") do |s|
1942
+ s.column(0, width: 25)
1943
+ s.column(1, width: 25)
1944
+ s.row(["Code"])
1945
+ s.row(["100-Z"])
1946
+ s.row(["200-Y"])
1947
+ s.row(["300-Z"])
1948
+ s.conditional_format("A2:A4", type: "endsWith", operator: "endsWith", text: "Z", formula: 'RIGHT(A2,1)="Z"', fill_color: "FFFFC7CE")
2009
1949
  end
2010
1950
  end
2011
1951
 
@@ -2015,7 +1955,7 @@ workbook = Xlsxrb.read(output_path)
2015
1955
  sheet = workbook.sheets.first
2016
1956
  sheet.rows.first(5).each do |row|
2017
1957
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2018
- puts "Row #{row.index}: #{row_cells.join(', ')}"
1958
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
2019
1959
  end
2020
1960
  ```
2021
1961
 
@@ -2043,19 +1983,20 @@ Demonstrates conditional formatting using a custom formula expression.
2043
1983
 
2044
1984
  ```ruby
2045
1985
  # frozen_string_literal: true
1986
+
2046
1987
  require "xlsxrb"
2047
1988
  output_path = ARGV[0] || "cf_expression_formula.xlsx"
2048
- Xlsxrb.generate(output_path) do |w|
2049
- w.add_style("center") { |style| style.align_horizontal("center") }
2050
- w.add_sheet("CF Expression") do |s|
2051
- s.set_column(0, width: 25)
2052
- s.set_column(1, width: 25)
2053
- s.add_row(["Values"])
2054
- s.add_row([10], styles: ["center"])
2055
- s.add_row([20], styles: ["center"])
2056
- s.add_row([30], styles: ["center"])
2057
- s.add_row([100], styles: ["center"]) # Average is 40. 100 is above average.
2058
- s.add_conditional_format("A2:A5", type: "expression", formula: "A2>AVERAGE($A$2:$A$5)", fill_color: "FFFFC7CE")
1989
+ Xlsxrb.generate(output_path) do |wb|
1990
+ wb.style("center") { |style| style.align_horizontal("center") }
1991
+ wb.sheet("CF Expression") do |s|
1992
+ s.column(0, width: 25)
1993
+ s.column(1, width: 25)
1994
+ s.row(["Values"])
1995
+ s.row([10], styles: "center")
1996
+ s.row([20], styles: "center")
1997
+ s.row([30], styles: "center")
1998
+ s.row([100], styles: "center") # Average is 40. 100 is above average.
1999
+ s.conditional_format("A2:A5", type: "expression", formula: "A2>AVERAGE($A$2:$A$5)", fill_color: "FFFFC7CE")
2059
2000
  end
2060
2001
  end
2061
2002
 
@@ -2065,7 +2006,7 @@ workbook = Xlsxrb.read(output_path)
2065
2006
  sheet = workbook.sheets.first
2066
2007
  sheet.rows.first(5).each do |row|
2067
2008
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2068
- puts "Row #{row.index}: #{row_cells.join(', ')}"
2009
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
2069
2010
  end
2070
2011
  ```
2071
2012
 
@@ -2094,17 +2035,18 @@ Demonstrates icon set indicators (red/yellow/green arrows).
2094
2035
 
2095
2036
  ```ruby
2096
2037
  # frozen_string_literal: true
2038
+
2097
2039
  require "xlsxrb"
2098
2040
  output_path = ARGV[0] || "cf_icon_set.xlsx"
2099
- Xlsxrb.generate(output_path) do |w|
2100
- w.add_style("center") { |style| style.align_horizontal("center") }
2101
- w.add_sheet("Icons") do |s|
2102
- s.set_column(0, width: 25)
2103
- s.set_column(1, width: 25)
2104
- s.add_row([25], styles: ["center"])
2105
- s.add_row([50], styles: ["center"])
2106
- s.add_row([75], styles: ["center"])
2107
- s.add_conditional_format("A1:A3", type: :iconSet, icon_style: "3Arrows", priority: 1)
2041
+ Xlsxrb.generate(output_path) do |wb|
2042
+ wb.style("center") { |style| style.align_horizontal("center") }
2043
+ wb.sheet("Icons") do |s|
2044
+ s.column(0, width: 25)
2045
+ s.column(1, width: 25)
2046
+ s.row([25], styles: "center")
2047
+ s.row([50], styles: "center")
2048
+ s.row([75], styles: "center")
2049
+ s.conditional_format("A1:A3", type: :iconSet, icon_style: "3Arrows", priority: 1)
2108
2050
  end
2109
2051
  end
2110
2052
 
@@ -2114,7 +2056,7 @@ workbook = Xlsxrb.read(output_path)
2114
2056
  sheet = workbook.sheets.first
2115
2057
  sheet.rows.first(5).each do |row|
2116
2058
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2117
- puts "Row #{row.index}: #{row_cells.join(', ')}"
2059
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
2118
2060
  end
2119
2061
  ```
2120
2062
 
@@ -2141,18 +2083,19 @@ Demonstrates embedding a standard 2D Area Chart.
2141
2083
 
2142
2084
  ```ruby
2143
2085
  # frozen_string_literal: true
2086
+
2144
2087
  require "xlsxrb"
2145
2088
  output_path = ARGV[0] || "chart_area.xlsx"
2146
- Xlsxrb.generate(output_path) do |w|
2147
- w.add_sheet("Data") do |s|
2148
- s.set_sheet_property(:fit_to_page, true)
2149
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2150
- s.set_column(0, width: 25)
2151
- s.set_column(1, width: 25)
2152
- s.add_row(["Day", "Value"])
2153
- s.add_row(["Mon", 10])
2154
- s.add_row(["Tue", 15])
2155
- s.add_chart(
2089
+ Xlsxrb.generate(output_path) do |wb|
2090
+ wb.sheet("Data") do |s|
2091
+ s.sheet_properties(:fit_to_page, true)
2092
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2093
+ s.column(0, width: 25)
2094
+ s.column(1, width: 25)
2095
+ s.row(%w[Day Value])
2096
+ s.row(["Mon", 10])
2097
+ s.row(["Tue", 15])
2098
+ s.chart(
2156
2099
  type: :area,
2157
2100
  title: "Daily Area",
2158
2101
  from_col: 3, from_row: 0, to_col: 8, to_row: 12,
@@ -2189,19 +2132,20 @@ Demonstrates embedding a stacked 2D Area Chart.
2189
2132
 
2190
2133
  ```ruby
2191
2134
  # frozen_string_literal: true
2135
+
2192
2136
  require "xlsxrb"
2193
2137
  output_path = ARGV[0] || "chart_area_stacked.xlsx"
2194
- Xlsxrb.generate(output_path) do |w|
2195
- w.add_sheet("Data") do |s|
2196
- s.set_column(0, width: 25)
2197
- s.set_column(1, width: 25)
2198
- s.add_row(["Year", "Sales A", "Sales B"])
2199
- s.add_row([2024, 100, 150])
2200
- s.add_row([2025, 120, 180])
2201
- s.add_row([2026, 140, 210])
2202
- s.set_sheet_property(:fit_to_page, true)
2203
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2204
- s.add_chart(
2138
+ Xlsxrb.generate(output_path) do |wb|
2139
+ wb.sheet("Data") do |s|
2140
+ s.column(0, width: 25)
2141
+ s.column(1, width: 25)
2142
+ s.row(["Year", "Sales A", "Sales B"])
2143
+ s.row([2024, 100, 150])
2144
+ s.row([2025, 120, 180])
2145
+ s.row([2026, 140, 210])
2146
+ s.sheet_properties(:fit_to_page, true)
2147
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2148
+ s.chart(
2205
2149
  type: :area,
2206
2150
  grouping: :stacked,
2207
2151
  title: "Stacked Area Chart",
@@ -2247,17 +2191,17 @@ require "xlsxrb"
2247
2191
 
2248
2192
  output_path = ARGV[0] || "chart_bar.xlsx"
2249
2193
 
2250
- Xlsxrb.generate(output_path) do |w|
2251
- w.add_sheet("Sales Data") do |s|
2252
- s.set_sheet_property(:fit_to_page, true)
2253
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2254
- s.set_column(0, width: 25)
2255
- s.set_column(1, width: 25)
2256
- s.add_row(["Month", "Value"])
2257
- s.add_row(["Jan", 100])
2258
- s.add_row(["Feb", 200])
2259
-
2260
- s.add_chart(
2194
+ Xlsxrb.generate(output_path) do |wb|
2195
+ wb.sheet("Sales Data") do |s|
2196
+ s.sheet_properties(:fit_to_page, true)
2197
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2198
+ s.column(0, width: 25)
2199
+ s.column(1, width: 25)
2200
+ s.row(%w[Month Value])
2201
+ s.row(["Jan", 100])
2202
+ s.row(["Feb", 200])
2203
+
2204
+ s.chart(
2261
2205
  type: :bar,
2262
2206
  title: "Monthly Sales",
2263
2207
  from_col: 3,
@@ -2299,19 +2243,20 @@ Demonstrates embedding a 100% stacked 2D Bar Chart.
2299
2243
 
2300
2244
  ```ruby
2301
2245
  # frozen_string_literal: true
2246
+
2302
2247
  require "xlsxrb"
2303
2248
  output_path = ARGV[0] || "chart_bar_percent_stacked.xlsx"
2304
- Xlsxrb.generate(output_path) do |w|
2305
- w.add_sheet("Data") do |s|
2306
- s.set_column(0, width: 25)
2307
- s.set_column(1, width: 25)
2308
- s.add_row(["Year", "Sales A", "Sales B"])
2309
- s.add_row([2024, 100, 150])
2310
- s.add_row([2025, 120, 180])
2311
- s.add_row([2026, 140, 210])
2312
- s.set_sheet_property(:fit_to_page, true)
2313
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2314
- s.add_chart(
2249
+ Xlsxrb.generate(output_path) do |wb|
2250
+ wb.sheet("Data") do |s|
2251
+ s.column(0, width: 25)
2252
+ s.column(1, width: 25)
2253
+ s.row(["Year", "Sales A", "Sales B"])
2254
+ s.row([2024, 100, 150])
2255
+ s.row([2025, 120, 180])
2256
+ s.row([2026, 140, 210])
2257
+ s.sheet_properties(:fit_to_page, true)
2258
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2259
+ s.chart(
2315
2260
  type: :bar,
2316
2261
  grouping: :percentStacked,
2317
2262
  title: "100% Stacked Bar Chart",
@@ -2352,19 +2297,20 @@ Demonstrates embedding a stacked 2D Bar Chart.
2352
2297
 
2353
2298
  ```ruby
2354
2299
  # frozen_string_literal: true
2300
+
2355
2301
  require "xlsxrb"
2356
2302
  output_path = ARGV[0] || "chart_bar_stacked.xlsx"
2357
- Xlsxrb.generate(output_path) do |w|
2358
- w.add_sheet("Data") do |s|
2359
- s.set_column(0, width: 25)
2360
- s.set_column(1, width: 25)
2361
- s.add_row(["Year", "Sales A", "Sales B"])
2362
- s.add_row([2024, 100, 150])
2363
- s.add_row([2025, 120, 180])
2364
- s.add_row([2026, 140, 210])
2365
- s.set_sheet_property(:fit_to_page, true)
2366
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2367
- s.add_chart(
2303
+ Xlsxrb.generate(output_path) do |wb|
2304
+ wb.sheet("Data") do |s|
2305
+ s.column(0, width: 25)
2306
+ s.column(1, width: 25)
2307
+ s.row(["Year", "Sales A", "Sales B"])
2308
+ s.row([2024, 100, 150])
2309
+ s.row([2025, 120, 180])
2310
+ s.row([2026, 140, 210])
2311
+ s.sheet_properties(:fit_to_page, true)
2312
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2313
+ s.chart(
2368
2314
  type: :bar,
2369
2315
  grouping: :stacked,
2370
2316
  title: "Stacked Bar Chart",
@@ -2405,18 +2351,19 @@ Demonstrates embedding a standard 2D Doughnut Chart.
2405
2351
 
2406
2352
  ```ruby
2407
2353
  # frozen_string_literal: true
2354
+
2408
2355
  require "xlsxrb"
2409
2356
  output_path = ARGV[0] || "chart_doughnut.xlsx"
2410
- Xlsxrb.generate(output_path) do |w|
2411
- w.add_sheet("Data") do |s|
2412
- s.set_sheet_property(:fit_to_page, true)
2413
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2414
- s.set_column(0, width: 25)
2415
- s.set_column(1, width: 25)
2416
- s.add_row(["Label", "Percent"])
2417
- s.add_row(["A", 40])
2418
- s.add_row(["B", 60])
2419
- s.add_chart(
2357
+ Xlsxrb.generate(output_path) do |wb|
2358
+ wb.sheet("Data") do |s|
2359
+ s.sheet_properties(:fit_to_page, true)
2360
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2361
+ s.column(0, width: 25)
2362
+ s.column(1, width: 25)
2363
+ s.row(%w[Label Percent])
2364
+ s.row(["A", 40])
2365
+ s.row(["B", 60])
2366
+ s.chart(
2420
2367
  type: :doughnut,
2421
2368
  title: "Ratio",
2422
2369
  from_col: 3, from_row: 0, to_col: 8, to_row: 12,
@@ -2460,19 +2407,20 @@ Demonstrates embedding a standard 2D Line Chart.
2460
2407
 
2461
2408
  ```ruby
2462
2409
  # frozen_string_literal: true
2410
+
2463
2411
  require "xlsxrb"
2464
2412
  output_path = ARGV[0] || "chart_line.xlsx"
2465
- Xlsxrb.generate(output_path) do |w|
2466
- w.add_sheet("Data") do |s|
2467
- s.set_sheet_property(:fit_to_page, true)
2468
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2469
- s.set_column(0, width: 25)
2470
- s.set_column(1, width: 25)
2471
- s.add_row(["Day", "Value"])
2472
- s.add_row(["Mon", 10])
2473
- s.add_row(["Tue", 15])
2474
- s.add_row(["Wed", 12])
2475
- s.add_chart(
2413
+ Xlsxrb.generate(output_path) do |wb|
2414
+ wb.sheet("Data") do |s|
2415
+ s.sheet_properties(:fit_to_page, true)
2416
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2417
+ s.column(0, width: 25)
2418
+ s.column(1, width: 25)
2419
+ s.row(%w[Day Value])
2420
+ s.row(["Mon", 10])
2421
+ s.row(["Tue", 15])
2422
+ s.row(["Wed", 12])
2423
+ s.chart(
2476
2424
  type: :line,
2477
2425
  title: "Daily Value",
2478
2426
  from_col: 3, from_row: 0, to_col: 8, to_row: 12,
@@ -2509,19 +2457,20 @@ Demonstrates embedding a stacked 2D Line Chart.
2509
2457
 
2510
2458
  ```ruby
2511
2459
  # frozen_string_literal: true
2460
+
2512
2461
  require "xlsxrb"
2513
2462
  output_path = ARGV[0] || "chart_line_stacked.xlsx"
2514
- Xlsxrb.generate(output_path) do |w|
2515
- w.add_sheet("Data") do |s|
2516
- s.set_column(0, width: 25)
2517
- s.set_column(1, width: 25)
2518
- s.add_row(["Year", "Sales A", "Sales B"])
2519
- s.add_row([2024, 100, 150])
2520
- s.add_row([2025, 120, 180])
2521
- s.add_row([2026, 140, 210])
2522
- s.set_sheet_property(:fit_to_page, true)
2523
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2524
- s.add_chart(
2463
+ Xlsxrb.generate(output_path) do |wb|
2464
+ wb.sheet("Data") do |s|
2465
+ s.column(0, width: 25)
2466
+ s.column(1, width: 25)
2467
+ s.row(["Year", "Sales A", "Sales B"])
2468
+ s.row([2024, 100, 150])
2469
+ s.row([2025, 120, 180])
2470
+ s.row([2026, 140, 210])
2471
+ s.sheet_properties(:fit_to_page, true)
2472
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2473
+ s.chart(
2525
2474
  type: :line,
2526
2475
  grouping: :stacked,
2527
2476
  title: "Stacked Line Chart",
@@ -2562,18 +2511,19 @@ Demonstrates embedding a standard 2D Pie Chart.
2562
2511
 
2563
2512
  ```ruby
2564
2513
  # frozen_string_literal: true
2514
+
2565
2515
  require "xlsxrb"
2566
2516
  output_path = ARGV[0] || "chart_pie.xlsx"
2567
- Xlsxrb.generate(output_path) do |w|
2568
- w.add_sheet("Data") do |s|
2569
- s.set_sheet_property(:fit_to_page, true)
2570
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2571
- s.set_column(0, width: 25)
2572
- s.set_column(1, width: 25)
2573
- s.add_row(["Label", "Percent"])
2574
- s.add_row(["Yes", 70])
2575
- s.add_row(["No", 30])
2576
- s.add_chart(
2517
+ Xlsxrb.generate(output_path) do |wb|
2518
+ wb.sheet("Data") do |s|
2519
+ s.sheet_properties(:fit_to_page, true)
2520
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2521
+ s.column(0, width: 25)
2522
+ s.column(1, width: 25)
2523
+ s.row(%w[Label Percent])
2524
+ s.row(["Yes", 70])
2525
+ s.row(["No", 30])
2526
+ s.chart(
2577
2527
  type: :pie,
2578
2528
  title: "Responses",
2579
2529
  from_col: 3, from_row: 0, to_col: 8, to_row: 12,
@@ -2617,18 +2567,19 @@ Demonstrates embedding a standard 2D Radar Chart.
2617
2567
 
2618
2568
  ```ruby
2619
2569
  # frozen_string_literal: true
2570
+
2620
2571
  require "xlsxrb"
2621
2572
  output_path = ARGV[0] || "chart_radar.xlsx"
2622
- Xlsxrb.generate(output_path) do |w|
2623
- w.add_sheet("Data") do |s|
2624
- s.set_sheet_property(:fit_to_page, true)
2625
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2626
- s.set_column(0, width: 25)
2627
- s.set_column(1, width: 25)
2628
- s.add_row(["Stat", "Value"])
2629
- s.add_row(["Atk", 80])
2630
- s.add_row(["Def", 60])
2631
- s.add_chart(
2573
+ Xlsxrb.generate(output_path) do |wb|
2574
+ wb.sheet("Data") do |s|
2575
+ s.sheet_properties(:fit_to_page, true)
2576
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2577
+ s.column(0, width: 25)
2578
+ s.column(1, width: 25)
2579
+ s.row(%w[Stat Value])
2580
+ s.row(["Atk", 80])
2581
+ s.row(["Def", 60])
2582
+ s.chart(
2632
2583
  type: :radar,
2633
2584
  title: "Stats",
2634
2585
  from_col: 3, from_row: 0, to_col: 8, to_row: 12,
@@ -2665,18 +2616,19 @@ Demonstrates embedding a standard 2D Scatter Plot.
2665
2616
 
2666
2617
  ```ruby
2667
2618
  # frozen_string_literal: true
2619
+
2668
2620
  require "xlsxrb"
2669
2621
  output_path = ARGV[0] || "chart_scatter.xlsx"
2670
- Xlsxrb.generate(output_path) do |w|
2671
- w.add_sheet("Data") do |s|
2672
- s.set_sheet_property(:fit_to_page, true)
2673
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2674
- s.set_column(0, width: 25)
2675
- s.set_column(1, width: 25)
2676
- s.add_row(["X", "Y"])
2677
- s.add_row([1, 10])
2678
- s.add_row([2, 15])
2679
- s.add_chart(
2622
+ Xlsxrb.generate(output_path) do |wb|
2623
+ wb.sheet("Data") do |s|
2624
+ s.sheet_properties(:fit_to_page, true)
2625
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2626
+ s.column(0, width: 25)
2627
+ s.column(1, width: 25)
2628
+ s.row(%w[X Y])
2629
+ s.row([1, 10])
2630
+ s.row([2, 15])
2631
+ s.chart(
2680
2632
  type: :scatter,
2681
2633
  title: "Scatter Plot",
2682
2634
  from_col: 3, from_row: 0, to_col: 8, to_row: 12,
@@ -2713,17 +2665,18 @@ Demonstrates outline grouping for columns.
2713
2665
 
2714
2666
  ```ruby
2715
2667
  # frozen_string_literal: true
2668
+
2716
2669
  require "xlsxrb"
2717
2670
  output_path = ARGV[0] || "col_grouping.xlsx"
2718
- Xlsxrb.generate(output_path) do |w|
2719
- w.add_style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2720
- w.add_sheet("Col Grouping") do |s|
2721
- s.set_sheet_property(:fit_to_page, true)
2722
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
2723
- s.set_column(0, width: 25, outline_level: 0)
2724
- s.set_column(1, width: 25, outline_level: 1)
2725
- s.set_column(2, width: 25, outline_level: 1)
2726
- s.add_row(["Col A", "Col B (Grouped)", "Col C (Grouped)"], styles: ["border", "border", "border"])
2671
+ Xlsxrb.generate(output_path) do |wb|
2672
+ wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2673
+ wb.sheet("Col Grouping") do |s|
2674
+ s.sheet_properties(:fit_to_page, true)
2675
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
2676
+ s.column(0, width: 25, outline_level: 0)
2677
+ s.column(1, width: 25, outline_level: 1)
2678
+ s.column(2, width: 25, outline_level: 1)
2679
+ s.row(["Col A", "Col B (Grouped)", "Col C (Grouped)"], styles: %w[border border border])
2727
2680
  end
2728
2681
  end
2729
2682
 
@@ -2759,14 +2712,15 @@ Demonstrates setting very wide column widths.
2759
2712
 
2760
2713
  ```ruby
2761
2714
  # frozen_string_literal: true
2715
+
2762
2716
  require "xlsxrb"
2763
2717
  output_path = ARGV[0] || "col_width_tall.xlsx"
2764
- Xlsxrb.generate(output_path) do |w|
2765
- w.add_style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2766
- w.add_sheet("Col Width") do |s|
2767
- s.set_column(0, width: 50)
2768
- s.set_column(1, width: 10)
2769
- s.add_row(["Very Wide Column (Width 50)", "Normal (10)"], styles: ["border", "border"])
2718
+ Xlsxrb.generate(output_path) do |wb|
2719
+ wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2720
+ wb.sheet("Col Width") do |s|
2721
+ s.column(0, width: 50)
2722
+ s.column(1, width: 10)
2723
+ s.row(["Very Wide Column (Width 50)", "Normal (10)"], styles: %w[border border])
2770
2724
  end
2771
2725
  end
2772
2726
 
@@ -2801,14 +2755,15 @@ Demonstrates setting custom column widths.
2801
2755
 
2802
2756
  ```ruby
2803
2757
  # frozen_string_literal: true
2758
+
2804
2759
  require "xlsxrb"
2805
2760
  output_path = ARGV[0] || "col_widths.xlsx"
2806
- Xlsxrb.generate(output_path) do |w|
2807
- w.add_style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2808
- w.add_sheet("Widths") do |s|
2809
- s.set_column(0, width: 30)
2810
- s.set_column(1, width: 10)
2811
- s.add_row(["Wide Column A", "Narrow B"], styles: ["border", "border"])
2761
+ Xlsxrb.generate(output_path) do |wb|
2762
+ wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2763
+ wb.sheet("Widths") do |s|
2764
+ s.column(0, width: 30)
2765
+ s.column(1, width: 10)
2766
+ s.row(["Wide Column A", "Narrow B"], styles: %w[border border])
2812
2767
  end
2813
2768
  end
2814
2769
 
@@ -2848,17 +2803,17 @@ require "xlsxrb"
2848
2803
 
2849
2804
  output_path = ARGV[0] || "conditional_formatting.xlsx"
2850
2805
 
2851
- Xlsxrb.generate(output_path) do |w|
2852
- w.add_style("center") { |style| style.align_horizontal("center") }
2853
- w.add_sheet("Scores") do |s|
2854
- s.set_column(0, width: 25)
2855
- s.set_column(1, width: 25)
2856
- s.add_row([90, 45, 72, 88], styles: ["center", "center", "center", "center"])
2857
-
2858
- s.add_conditional_format("A1:D1",
2859
- type: :cell_is, operator: :greaterThan,
2860
- formula: "80", priority: 1,
2861
- fill_color: "FFFFC7CE")
2806
+ Xlsxrb.generate(output_path) do |wb|
2807
+ wb.style("center") { |style| style.align_horizontal("center") }
2808
+ wb.sheet("Scores") do |s|
2809
+ s.column(0, width: 25)
2810
+ s.column(1, width: 25)
2811
+ s.row([90, 45, 72, 88], styles: %w[center center center center])
2812
+
2813
+ s.conditional_format("A1:D1",
2814
+ type: :cell_is, operator: :greaterThan,
2815
+ formula: "80", priority: 1,
2816
+ fill_color: "FFFFC7CE")
2862
2817
  end
2863
2818
  end
2864
2819
 
@@ -2868,7 +2823,7 @@ workbook = Xlsxrb.read(output_path)
2868
2823
  sheet = workbook.sheets.first
2869
2824
  sheet.rows.first(5).each do |row|
2870
2825
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2871
- puts "Row #{row.index}: #{row_cells.join(', ')}"
2826
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
2872
2827
  end
2873
2828
  ```
2874
2829
 
@@ -2893,6 +2848,7 @@ Demonstrates embedding raster PNG images in cell ranges.
2893
2848
 
2894
2849
  ```ruby
2895
2850
  # frozen_string_literal: true
2851
+
2896
2852
  require "xlsxrb"
2897
2853
  output_path = ARGV[0] || "embedded_images.xlsx"
2898
2854
 
@@ -2904,7 +2860,7 @@ def make_png(width, height, red, green, blue)
2904
2860
  ihdr_chunk = "IHDR".dup.force_encoding("BINARY") + ihdr_data
2905
2861
  ihdr_crc = Zlib.crc32(ihdr_chunk)
2906
2862
  png << [ihdr_data.bytesize].pack("N") << ihdr_chunk << [ihdr_crc].pack("N")
2907
- raw_data = Array.new(height) { "\x00".dup.force_encoding("BINARY") + [red, green, blue].pack("C3") * width }.join
2863
+ raw_data = Array.new(height) { "\x00".dup.force_encoding("BINARY") + ([red, green, blue].pack("C3") * width) }.join
2908
2864
  compressed = Zlib.deflate(raw_data)
2909
2865
  idat_chunk = "IDAT".dup.force_encoding("BINARY") + compressed
2910
2866
  idat_crc = Zlib.crc32(idat_chunk)
@@ -2917,19 +2873,19 @@ end
2917
2873
 
2918
2874
  dummy_png = make_png(100, 100, 255, 0, 0)
2919
2875
 
2920
- Xlsxrb.generate(output_path) do |w|
2921
- w.add_style("center") { |st| st.align_horizontal(:center) }
2922
- w.add_sheet("Images") do |s|
2923
- s.add_row(["Logo Target cell:", "", "", "Boundary"], styles: ["left", "center", "center", "center"])
2924
- s.add_row(["", "", "", ""])
2925
- s.add_row(["", "", "", ""])
2926
- s.add_row(["", "", "", ""])
2927
- s.add_row(["", "", "", "Boundary End"], styles: ["left", "center", "center", "center"])
2928
- s.add_image(dummy_png, ext: "png", from_col: 1, from_row: 1, to_col: 3, to_row: 5)
2929
- s.set_column(0, width: 20)
2930
- s.set_column(1, width: 15)
2931
- s.set_column(2, width: 15)
2932
- s.set_column(3, width: 15)
2876
+ Xlsxrb.generate(output_path) do |wb|
2877
+ wb.style("center") { |st| st.align_horizontal(:center) }
2878
+ wb.sheet("Images") do |s|
2879
+ s.row(["Logo Target cell:", "", "", "Boundary"], styles: %w[left center center center])
2880
+ s.row(["", "", "", ""])
2881
+ s.row(["", "", "", ""])
2882
+ s.row(["", "", "", ""])
2883
+ s.row(["", "", "", "Boundary End"], styles: %w[left center center center])
2884
+ s.image(dummy_png, ext: "png", from_col: 1, from_row: 1, to_col: 3, to_row: 5)
2885
+ s.column(0, width: 20)
2886
+ s.column(1, width: 15)
2887
+ s.column(2, width: 15)
2888
+ s.column(3, width: 15)
2933
2889
  end
2934
2890
  end
2935
2891
 
@@ -2940,7 +2896,7 @@ workbook = Xlsxrb.read(output_path)
2940
2896
  sheet = workbook.sheets.first
2941
2897
  sheet.rows.first(5).each do |row|
2942
2898
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2943
- puts "Row #{row.index}: #{row_cells.join(', ')}"
2899
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
2944
2900
  end
2945
2901
  images = reader.images(sheet: sheet.name)
2946
2902
  images.each_with_index do |img, idx|
@@ -2977,19 +2933,20 @@ Demonstrates linear gradients inside cell backgrounds.
2977
2933
 
2978
2934
  ```ruby
2979
2935
  # frozen_string_literal: true
2936
+
2980
2937
  require "xlsxrb"
2981
2938
  output_path = ARGV[0] || "fill_gradients.xlsx"
2982
- Xlsxrb.generate(output_path) do |w|
2983
- w.add_style("gradient") do |style|
2939
+ Xlsxrb.generate(output_path) do |wb|
2940
+ wb.style("gradient") do |style|
2984
2941
  style.fill_gradient(type: "linear", degree: 45, stops: [
2985
- { position: 0, color: "FFFFFFFF" },
2986
- { position: 1, color: "FF4F81BD" }
2987
- ])
2942
+ { position: 0, color: "FFFFFFFF" },
2943
+ { position: 1, color: "FF4F81BD" }
2944
+ ])
2988
2945
  end
2989
- w.add_sheet("Gradients") do |s|
2990
- s.set_column(0, width: 25)
2991
- s.set_column(1, width: 25)
2992
- s.add_row(["Normal Cell", "Gradient Cell"], styles: { 1 => "gradient" })
2946
+ wb.sheet("Gradients") do |s|
2947
+ s.column(0, width: 25)
2948
+ s.column(1, width: 25)
2949
+ s.row(["Normal Cell", "Gradient Cell"], styles: { 1 => "gradient" })
2993
2950
  end
2994
2951
  end
2995
2952
 
@@ -3027,17 +2984,18 @@ Demonstrates standard pattern fills (darkGray, darkGrid) in cell backgrounds.
3027
2984
 
3028
2985
  ```ruby
3029
2986
  # frozen_string_literal: true
2987
+
3030
2988
  require "xlsxrb"
3031
2989
  output_path = ARGV[0] || "fill_patterns.xlsx"
3032
- Xlsxrb.generate(output_path) do |w|
3033
- w.add_style("dark_gray") { |s| s.fill(pattern: "darkGray", fg_color: "FFC0C0C0", bg_color: "FFFFFFFF") }
3034
- w.add_style("grid_fill") { |s| s.fill(pattern: "darkGrid", fg_color: "FFC0C0C0", bg_color: "FFFFFFFF") }
3035
- w.add_sheet("Patterns") do |s|
3036
- s.set_column(0, width: 25)
3037
- s.set_column(1, width: 25)
3038
- s.add_row(["Pattern", "Preview"])
3039
- s.add_row(["Dark Gray", "Pattern Fill"], styles: { 1 => "dark_gray" })
3040
- s.add_row(["Dark Grid", "Grid Fill"], styles: { 1 => "grid_fill" })
2990
+ Xlsxrb.generate(output_path) do |wb|
2991
+ wb.style("dark_gray") { |s| s.fill(pattern: "darkGray", fg_color: "FFC0C0C0", bg_color: "FFFFFFFF") }
2992
+ wb.style("grid_fill") { |s| s.fill(pattern: "darkGrid", fg_color: "FFC0C0C0", bg_color: "FFFFFFFF") }
2993
+ wb.sheet("Patterns") do |s|
2994
+ s.column(0, width: 25)
2995
+ s.column(1, width: 25)
2996
+ s.row(%w[Pattern Preview])
2997
+ s.row(["Dark Gray", "Pattern Fill"], styles: { 1 => "dark_gray" })
2998
+ s.row(["Dark Grid", "Grid Fill"], styles: { 1 => "grid_fill" })
3041
2999
  end
3042
3000
  end
3043
3001
 
@@ -3075,17 +3033,18 @@ Demonstrates solid cell background fill colors.
3075
3033
 
3076
3034
  ```ruby
3077
3035
  # frozen_string_literal: true
3036
+
3078
3037
  require "xlsxrb"
3079
3038
  output_path = ARGV[0] || "fill_solid_colors.xlsx"
3080
- Xlsxrb.generate(output_path) do |w|
3081
- w.add_style("red_fill") { |s| s.fill_color("FFFFC7CE") }
3082
- w.add_style("green_fill") { |s| s.fill_color("FFC6EFCE") }
3083
- w.add_sheet("Fills") do |s|
3084
- s.set_column(0, width: 25)
3085
- s.set_column(1, width: 25)
3086
- s.add_row(["Color", "Preview"])
3087
- s.add_row(["Red", "Red Fill"], styles: { 1 => "red_fill" })
3088
- s.add_row(["Green", "Green Fill"], styles: { 1 => "green_fill" })
3039
+ Xlsxrb.generate(output_path) do |wb|
3040
+ wb.style("red_fill") { |s| s.fill_color("FFFFC7CE") }
3041
+ wb.style("green_fill") { |s| s.fill_color("FFC6EFCE") }
3042
+ wb.sheet("Fills") do |s|
3043
+ s.column(0, width: 25)
3044
+ s.column(1, width: 25)
3045
+ s.row(%w[Color Preview])
3046
+ s.row(["Red", "Red Fill"], styles: { 1 => "red_fill" })
3047
+ s.row(["Green", "Green Fill"], styles: { 1 => "green_fill" })
3089
3048
  end
3090
3049
  end
3091
3050
 
@@ -3128,103 +3087,75 @@ require "xlsxrb"
3128
3087
 
3129
3088
  output_path = ARGV[0] || "fonts.xlsx"
3130
3089
 
3131
- Xlsxrb.generate(output_path) do |w|
3132
- # Font Families
3133
- w.add_style("f_arial") { |s| s.font_name("Arial") }
3134
- w.add_style("f_times") { |s| s.font_name("Times New Roman") }
3135
- w.add_style("f_courier") { |s| s.font_name("Courier New") }
3136
- w.add_style("f_georgia") { |s| s.font_name("Georgia") }
3137
- w.add_style("f_tahoma") { |s| s.font_name("Tahoma") }
3090
+ Xlsxrb.generate(output_path) do |wb|
3091
+ # Font Families (using nested hash options)
3092
+ wb.style("f_arial", font: { name: "Arial" })
3093
+ wb.style("f_times", font: { name: "Times New Roman" })
3094
+ wb.style("f_courier", font: { name: "Courier New" })
3095
+ wb.style("f_georgia", font: { name: "Georgia" })
3096
+ wb.style("f_tahoma", font: { name: "Tahoma" })
3138
3097
 
3139
3098
  # Font Sizes
3140
- w.add_style("sz_10") { |s| s.size(10) }
3141
- w.add_style("sz_16") { |s| s.size(16) }
3142
- w.add_style("sz_24") { |s| s.size(24) }
3099
+ wb.style("sz_10", font: { size: 10 })
3100
+ wb.style("sz_16", font: { size: 16 })
3101
+ wb.style("sz_24", font: { size: 24 })
3143
3102
 
3144
3103
  # Font Colors
3145
- w.add_style("c_red") { |s| s.font_color("FFC00000") }
3146
- w.add_style("c_green") { |s| s.font_color("FF008000") }
3147
- w.add_style("c_blue") { |s| s.font_color("FF0000FF") }
3104
+ wb.style("c_red", font: { color: "FFC00000" })
3105
+ wb.style("c_green", font: { color: "FF008000" })
3106
+ wb.style("c_blue", font: { color: :blue })
3148
3107
 
3149
3108
  # Font Styles
3150
- w.add_style("st_bold") { |s| s.bold }
3151
- w.add_style("st_italic") { |s| s.italic }
3152
- w.add_style("st_underline") { |s| s.underline("single") }
3153
- w.add_style("st_double_u") { |s| s.underline("double") }
3154
- w.add_style("st_strike") { |s| s.strike }
3155
-
3156
- # Vertical Alignments (Superscript/Subscript)
3157
- w.add_style("v_super") { |s| s.vert_align("superscript") }
3158
- w.add_style("v_sub") { |s| s.vert_align("subscript") }
3159
-
3160
- w.add_sheet("Fonts") do |s|
3161
- s.set_column(0, width: 25)
3162
- s.set_column(1, width: 25)
3163
- s.set_print_option(:grid_lines, true)
3164
-
3165
- s.add_row(["Font Feature", "Text Preview"])
3166
- s.add_row(["Family: Arial", "Arial Text"], styles: { 1 => "f_arial" })
3167
- s.add_row(["Family: Times New Roman", "Times New Roman"], styles: { 1 => "f_times" })
3168
- s.add_row(["Family: Courier New", "Courier New Text"], styles: { 1 => "f_courier" })
3169
- s.add_row(["Family: Georgia", "Georgia Text"], styles: { 1 => "f_georgia" })
3170
- s.add_row(["Family: Tahoma", "Tahoma Text"], styles: { 1 => "f_tahoma" })
3171
-
3172
- s.add_row(["Size: 10pt", "10pt Font Size"], styles: { 1 => "sz_10" })
3173
- s.add_row(["Size: 16pt", "16pt Font Size"], styles: { 1 => "sz_16" })
3174
- s.add_row(["Size: 24pt", "24pt Font Size"], styles: { 1 => "sz_24" })
3175
-
3176
- s.add_row(["Color: Red", "Red Text"], styles: { 1 => "c_red" })
3177
- s.add_row(["Color: Green", "Green Text"], styles: { 1 => "c_green" })
3178
- s.add_row(["Color: Blue", "Blue Text"], styles: { 1 => "c_blue" })
3179
-
3180
- s.add_row(["Style: Bold", "Bold Text"], styles: { 1 => "st_bold" })
3181
- s.add_row(["Style: Italic", "Italic Text"], styles: { 1 => "st_italic" })
3182
- s.add_row(["Style: Underline", "Underline Text"], styles: { 1 => "st_underline" })
3183
- s.add_row(["Style: Double Underline", "Double Underline"], styles: { 1 => "st_double_u" })
3184
- s.add_row(["Style: Strike-through", "Strike-through Text"], styles: { 1 => "st_strike" })
3185
-
3186
- s.add_row(["Align: Superscript", "x2 (2 is super)"], styles: { 1 => "v_super" })
3187
- s.add_row(["Align: Subscript", "H2O (2 is sub)"], styles: { 1 => "v_sub" })
3188
- end
3189
- end
3190
-
3191
- # Read check
3192
- puts "=== Read Validation ==="
3193
- workbook = Xlsxrb.read(output_path)
3194
- sheet = workbook.sheets.first
3195
- sheet.rows.each do |row|
3196
- row_cells = row.cells.map do |c|
3197
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
3198
- font_id = xf ? xf[:font_id] : 0
3199
- "#{c.ref}: #{c.value.inspect} (font_id: #{font_id})"
3109
+ wb.style("bold", font: { bold: true })
3110
+ wb.style("italic", font: { italic: true })
3111
+ wb.style("underline", font: { underline: true })
3112
+ wb.style("double_underline", font: { underline: "double" })
3113
+ wb.style("strike", font: { strike: true })
3114
+
3115
+ # Vertical Alignment (Subscript / Superscript)
3116
+ wb.style("superscript", font: { vert_align: "superscript" })
3117
+ wb.style("subscript", font: { vert_align: "subscript" })
3118
+
3119
+ wb.style("header", font: { bold: true, color: :white }, fill: { color: "FF4F81BD" })
3120
+ wb.style("bg_light", fill: { color: "FFDCE6F1" })
3121
+
3122
+ wb.sheet("Fonts") do |s|
3123
+ s.column(0, width: 25)
3124
+ s.column(1, width: 35)
3125
+
3126
+ s.row(["Font Feature", "Text Preview"], styles: "header")
3127
+
3128
+ s.row(["Family: Arial", "Arial Text"], styles: %w[bg_light f_arial])
3129
+ s.row(["Family: Times New Roman", "Times New Roman"], styles: [nil, "f_times"])
3130
+ s.row(["Family: Courier New", "Courier New Text"], styles: %w[bg_light f_courier])
3131
+ s.row(["Family: Georgia", "Georgia Text"], styles: [nil, "f_georgia"])
3132
+ s.row(["Family: Tahoma", "Tahoma Text"], styles: %w[bg_light f_tahoma])
3133
+
3134
+ s.row(["Size: 10pt", "10pt Font Size"], styles: [nil, "sz_10"])
3135
+ s.row(["Size: 16pt", "16pt Font Size"], styles: %w[bg_light sz_16])
3136
+ s.row(["Size: 24pt", "24pt Font Size"], styles: [nil, "sz_24"])
3137
+
3138
+ s.row(["Color: Red", "Red Text"], styles: %w[bg_light c_red])
3139
+ s.row(["Color: Green", "Green Text"], styles: [nil, "c_green"])
3140
+ s.row(["Color: Blue", "Blue Text"], styles: %w[bg_light c_blue])
3141
+
3142
+ s.row(["Style: Bold", "Bold Text"], styles: [nil, "bold"])
3143
+ s.row(["Style: Italic", "Italic Text"], styles: %w[bg_light italic])
3144
+ s.row(["Style: Underline", "Underline Text"], styles: [nil, "underline"])
3145
+ s.row(["Style: Double Underline", "Double Underline"], styles: %w[bg_light double_underline])
3146
+ s.row(["Style: Strike-through", "Strike-through Text"], styles: [nil, "strike"])
3147
+
3148
+ s.row(["Align: Superscript", "x2 (2 is super)"], styles: %w[bg_light superscript])
3149
+ s.row(["Align: Subscript", "H2O (2 is sub)"], styles: [nil, "subscript"])
3200
3150
  end
3201
- puts "Row #{row.index}: #{row_cells.join(', ')}"
3202
3151
  end
3152
+ puts "Created #{output_path}"
3203
3153
  ```
3204
3154
 
3205
3155
  ### Console Output
3206
3156
 
3207
3157
  ```text
3208
- === Read Validation ===
3209
- Row 0: A1: "Font Feature" (font_id: 0), B1: "Text Preview" (font_id: 0)
3210
- Row 1: A2: "Family: Arial" (font_id: 0), B2: "Arial Text" (font_id: 1)
3211
- Row 2: A3: "Family: Times New Roman" (font_id: 0), B3: "Times New Roman" (font_id: 2)
3212
- Row 3: A4: "Family: Courier New" (font_id: 0), B4: "Courier New Text" (font_id: 3)
3213
- Row 4: A5: "Family: Georgia" (font_id: 0), B5: "Georgia Text" (font_id: 4)
3214
- Row 5: A6: "Family: Tahoma" (font_id: 0), B6: "Tahoma Text" (font_id: 5)
3215
- Row 6: A7: "Size: 10pt" (font_id: 0), B7: "10pt Font Size" (font_id: 6)
3216
- Row 7: A8: "Size: 16pt" (font_id: 0), B8: "16pt Font Size" (font_id: 7)
3217
- Row 8: A9: "Size: 24pt" (font_id: 0), B9: "24pt Font Size" (font_id: 8)
3218
- Row 9: A10: "Color: Red" (font_id: 0), B10: "Red Text" (font_id: 9)
3219
- Row 10: A11: "Color: Green" (font_id: 0), B11: "Green Text" (font_id: 10)
3220
- Row 11: A12: "Color: Blue" (font_id: 0), B12: "Blue Text" (font_id: 11)
3221
- Row 12: A13: "Style: Bold" (font_id: 0), B13: "Bold Text" (font_id: 12)
3222
- Row 13: A14: "Style: Italic" (font_id: 0), B14: "Italic Text" (font_id: 13)
3223
- Row 14: A15: "Style: Underline" (font_id: 0), B15: "Underline Text" (font_id: 14)
3224
- Row 15: A16: "Style: Double Underline" (font_id: 0), B16: "Double Underline" (font_id: 15)
3225
- Row 16: A17: "Style: Strike-through" (font_id: 0), B17: "Strike-through Text" (font_id: 16)
3226
- Row 17: A18: "Align: Superscript" (font_id: 0), B18: "x2 (2 is super)" (font_id: 17)
3227
- Row 18: A19: "Align: Subscript" (font_id: 0), B19: "H2O (2 is sub)" (font_id: 18)
3158
+ Created /workspaces/xlsxrb/docs/visual/files/fonts.xlsx
3228
3159
  ```
3229
3160
 
3230
3161
  <hr/>
@@ -3232,7 +3163,7 @@ Row 18: A19: "Align: Subscript" (font_id: 0), B19: "H2O (2 is sub)" (font_id: 18
3232
3163
  ## Interactive Autofilter
3233
3164
 
3234
3165
  > [!TIP]
3235
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_autofilter.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3166
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3236
3167
 
3237
3168
  Demonstrates enabling auto-filter sorting headers on tables. Download the sheet to interactively filter and sort columns.
3238
3169
 
@@ -3246,18 +3177,19 @@ Demonstrates enabling auto-filter sorting headers on tables. Download the sheet
3246
3177
 
3247
3178
  ```ruby
3248
3179
  # frozen_string_literal: true
3180
+
3249
3181
  require "xlsxrb"
3250
3182
  output_path = ARGV[0] || "interactive_autofilter.xlsx"
3251
- Xlsxrb.generate(output_path) do |w|
3252
- w.add_sheet("Filter") do |s|
3253
- s.set_column(0, width: 25)
3254
- s.set_column(1, width: 25)
3255
- s.add_row(["Name", "Department"])
3256
- s.add_row(["Alice", "HR"])
3257
- s.add_row(["Bob", "Eng"])
3258
- s.set_auto_filter("A1:B3")
3183
+ Xlsxrb.generate(output_path) do |wb|
3184
+ wb.sheet("Filter") do |s|
3185
+ s.column(0, width: 25)
3186
+ s.column(1, width: 25)
3187
+ s.row(%w[Name Department])
3188
+ s.row(%w[Alice HR])
3189
+ s.row(%w[Bob Eng])
3190
+ s.auto_filter("A1:B3")
3259
3191
  end
3260
- w.add_defined_name("_xlnm._FilterDatabase", "Filter!$A$1:$B$3", sheet: "Filter", hidden: true)
3192
+ wb.defined_name("_xlnm._FilterDatabase", "Filter!$A$1:$B$3", sheet: "Filter", hidden: true)
3261
3193
  end
3262
3194
 
3263
3195
  # 2. Read the generated sheet and print cell values
@@ -3266,7 +3198,7 @@ workbook = Xlsxrb.read(output_path)
3266
3198
  sheet = workbook.sheets.first
3267
3199
  sheet.rows.first(5).each do |row|
3268
3200
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
3269
- puts "Row #{row.index}: #{row_cells.join(', ')}"
3201
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
3270
3202
  end
3271
3203
  ```
3272
3204
 
@@ -3284,7 +3216,7 @@ Row 2: A3: "Bob", B3: "Eng"
3284
3216
  ## Interactive Comments
3285
3217
 
3286
3218
  > [!TIP]
3287
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_comments.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3219
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3288
3220
 
3289
3221
  Demonstrates cell pop-up comments. Open the sheet in Excel and hover your mouse over the cell with the red triangle to view the comment.
3290
3222
 
@@ -3298,14 +3230,15 @@ Demonstrates cell pop-up comments. Open the sheet in Excel and hover your mouse
3298
3230
 
3299
3231
  ```ruby
3300
3232
  # frozen_string_literal: true
3233
+
3301
3234
  require "xlsxrb"
3302
3235
  output_path = ARGV[0] || "interactive_comments.xlsx"
3303
- Xlsxrb.generate(output_path) do |w|
3304
- w.add_sheet("Comments") do |s|
3305
- s.set_column(0, width: 25)
3306
- s.set_column(1, width: 25)
3307
- s.add_row(["Item A", "Item B"])
3308
- s.add_comment("A1", "This is an important comment.", author: "System")
3236
+ Xlsxrb.generate(output_path) do |wb|
3237
+ wb.sheet("Comments") do |s|
3238
+ s.column(0, width: 25)
3239
+ s.column(1, width: 25)
3240
+ s.row(["Item A", "Item B"])
3241
+ s.comment("A1", "This is an important comment.", author: "System")
3309
3242
  end
3310
3243
  end
3311
3244
 
@@ -3315,7 +3248,7 @@ workbook = Xlsxrb.read(output_path)
3315
3248
  sheet = workbook.sheets.first
3316
3249
  sheet.rows.first(5).each do |row|
3317
3250
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
3318
- puts "Row #{row.index}: #{row_cells.join(', ')}"
3251
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
3319
3252
  end
3320
3253
  ```
3321
3254
 
@@ -3331,7 +3264,7 @@ Row 0: A1: "Item A", B1: "Item B"
3331
3264
  ## Interactive Validation Custom
3332
3265
 
3333
3266
  > [!TIP]
3334
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_validation_custom.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3267
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3335
3268
 
3336
3269
  Demonstrates interactive custom formula validation rules.
3337
3270
 
@@ -3345,15 +3278,16 @@ Demonstrates interactive custom formula validation rules.
3345
3278
 
3346
3279
  ```ruby
3347
3280
  # frozen_string_literal: true
3281
+
3348
3282
  require "xlsxrb"
3349
3283
  output_path = ARGV[0] || "interactive_validation_custom.xlsx"
3350
- Xlsxrb.generate(output_path) do |w|
3351
- w.add_sheet("Custom Rule") do |s|
3352
- s.set_column(0, width: 25)
3353
- s.set_column(1, width: 25)
3354
- s.add_row(["Number A", "Number B (Must be larger A)"])
3355
- s.add_row([10, ""])
3356
- s.add_data_validation("B2", type: "custom", formula1: "B2>A2", show_error_message: true, error_title: "Validation Error", error: "Number B must be greater than Number A")
3284
+ Xlsxrb.generate(output_path) do |wb|
3285
+ wb.sheet("Custom Rule") do |s|
3286
+ s.column(0, width: 25)
3287
+ s.column(1, width: 25)
3288
+ s.row(["Number A", "Number B (Must be larger A)"])
3289
+ s.row([10, ""])
3290
+ s.validate_data("B2", type: "custom", formula1: "B2>A2", show_error_message: true, error_title: "Validation Error", error: "Number B must be greater than Number A")
3357
3291
  end
3358
3292
  end
3359
3293
 
@@ -3380,7 +3314,7 @@ Validation range B2: type=custom, formula1=B2>A2, formula2=
3380
3314
  ## Interactive Validation Date
3381
3315
 
3382
3316
  > [!TIP]
3383
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_validation_date.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3317
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3384
3318
 
3385
3319
  Demonstrates interactive date range constraints validation rules.
3386
3320
 
@@ -3394,14 +3328,15 @@ Demonstrates interactive date range constraints validation rules.
3394
3328
 
3395
3329
  ```ruby
3396
3330
  # frozen_string_literal: true
3331
+
3397
3332
  require "xlsxrb"
3398
3333
  output_path = ARGV[0] || "interactive_validation_date.xlsx"
3399
- Xlsxrb.generate(output_path) do |w|
3400
- w.add_sheet("Date Validation") do |s|
3401
- s.set_column(0, width: 25)
3402
- s.set_column(1, width: 25)
3403
- s.add_row(["Date Range", "Enter Date (2026):"])
3404
- s.add_data_validation("B2", type: "date", operator: "between", formula1: "Date(2026,1,1)", formula2: "Date(2026,12,31)", show_error_message: true, error_title: "Invalid Date", error: "Must be a date in 2026")
3334
+ Xlsxrb.generate(output_path) do |wb|
3335
+ wb.sheet("Date Validation") do |s|
3336
+ s.column(0, width: 25)
3337
+ s.column(1, width: 25)
3338
+ s.row(["Date Range", "Enter Date (2026):"])
3339
+ s.validate_data("B2", type: "date", operator: "between", formula1: "Date(2026,1,1)", formula2: "Date(2026,12,31)", show_error_message: true, error_title: "Invalid Date", error: "Must be a date in 2026")
3405
3340
  end
3406
3341
  end
3407
3342
 
@@ -3428,7 +3363,7 @@ Validation range B2: type=date, formula1=Date(2026,1,1), formula2=Date(2026,12,3
3428
3363
  ## Interactive Validation List
3429
3364
 
3430
3365
  > [!TIP]
3431
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_validation_list.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3366
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3432
3367
 
3433
3368
  Demonstrates dropdown list data validations. Open the sheet in Excel and select cell A1/A2 to see the dropdown list in action.
3434
3369
 
@@ -3442,14 +3377,15 @@ Demonstrates dropdown list data validations. Open the sheet in Excel and select
3442
3377
 
3443
3378
  ```ruby
3444
3379
  # frozen_string_literal: true
3380
+
3445
3381
  require "xlsxrb"
3446
3382
  output_path = ARGV[0] || "interactive_validation_list.xlsx"
3447
- Xlsxrb.generate(output_path) do |w|
3448
- w.add_sheet("List Validation") do |s|
3449
- s.set_column(0, width: 25)
3450
- s.set_column(1, width: 25)
3451
- s.add_row(["Department", "Select:"])
3452
- s.add_data_validation("B2", type: "list", formula1: '"HR,Sales,Engineering"')
3383
+ Xlsxrb.generate(output_path) do |wb|
3384
+ wb.sheet("List Validation") do |s|
3385
+ s.column(0, width: 25)
3386
+ s.column(1, width: 25)
3387
+ s.row(["Department", "Select:"])
3388
+ s.validate_data("B2", in: %w[HR Sales Engineering])
3453
3389
  end
3454
3390
  end
3455
3391
 
@@ -3476,7 +3412,7 @@ Validation range B2: type=list, formula1="HR,Sales,Engineering", formula2=
3476
3412
  ## Interactive Validation Range
3477
3413
 
3478
3414
  > [!TIP]
3479
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_validation_range.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3415
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3480
3416
 
3481
3417
  Demonstrates range constraints for whole number validations. Open the sheet in Excel and try entering a value outside 10-100 to trigger the warning.
3482
3418
 
@@ -3490,14 +3426,15 @@ Demonstrates range constraints for whole number validations. Open the sheet in E
3490
3426
 
3491
3427
  ```ruby
3492
3428
  # frozen_string_literal: true
3429
+
3493
3430
  require "xlsxrb"
3494
3431
  output_path = ARGV[0] || "interactive_validation_range.xlsx"
3495
- Xlsxrb.generate(output_path) do |w|
3496
- w.add_sheet("Range Validation") do |s|
3497
- s.set_column(0, width: 25)
3498
- s.set_column(1, width: 25)
3499
- s.add_row(["Age", "Enter (18-99):"])
3500
- s.add_data_validation("B2", type: "whole", operator: "between", formula1: "18", formula2: "99", show_error_message: true, error_title: "Invalid Age", error: "Age must be between 18 and 99!")
3432
+ Xlsxrb.generate(output_path) do |wb|
3433
+ wb.sheet("Range Validation") do |s|
3434
+ s.column(0, width: 25)
3435
+ s.column(1, width: 25)
3436
+ s.row(["Age", "Enter (18-99):"])
3437
+ s.validate_data("B2", type: "whole", operator: "between", formula1: "18", formula2: "99", show_error_message: true, error_title: "Invalid Age", error: "Age must be between 18 and 99!")
3501
3438
  end
3502
3439
  end
3503
3440
 
@@ -3524,7 +3461,7 @@ Validation range B2: type=whole, formula1=18, formula2=99
3524
3461
  ## Interactive Validation Text Length
3525
3462
 
3526
3463
  > [!TIP]
3527
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_validation_text_length.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3464
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3528
3465
 
3529
3466
  Demonstrates interactive text length validation rules.
3530
3467
 
@@ -3538,14 +3475,15 @@ Demonstrates interactive text length validation rules.
3538
3475
 
3539
3476
  ```ruby
3540
3477
  # frozen_string_literal: true
3478
+
3541
3479
  require "xlsxrb"
3542
3480
  output_path = ARGV[0] || "interactive_validation_text_length.xlsx"
3543
- Xlsxrb.generate(output_path) do |w|
3544
- w.add_sheet("Text Length") do |s|
3545
- s.set_column(0, width: 25)
3546
- s.set_column(1, width: 25)
3547
- s.add_row(["Username", "Enter (< 10 chars):"])
3548
- s.add_data_validation("B2", type: "textLength", operator: "lessThan", formula1: "10", show_error_message: true, error_title: "Too Long", error: "Username must be under 10 characters")
3481
+ Xlsxrb.generate(output_path) do |wb|
3482
+ wb.sheet("Text Length") do |s|
3483
+ s.column(0, width: 25)
3484
+ s.column(1, width: 25)
3485
+ s.row(["Username", "Enter (< 10 chars):"])
3486
+ s.validate_data("B2", type: "textLength", operator: "lessThan", formula1: "10", show_error_message: true, error_title: "Too Long", error: "Username must be under 10 characters")
3549
3487
  end
3550
3488
  end
3551
3489
 
@@ -3572,7 +3510,7 @@ Validation range B2: type=textLength, formula1=10, formula2=
3572
3510
  ## Interactive Validation Time
3573
3511
 
3574
3512
  > [!TIP]
3575
- > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please **[Download the .xlsx file](files/interactive_validation_time.xlsx)** and open it in Microsoft Excel, LibreOffice Calc, or Apple Numbers to interact with it!
3513
+ > **Interactive Feature**: This example uses interactive Excel behaviors (such as validation dropdowns, comments, or autofilters). Since the static visual preview below represents a printed page layout, please use the **Live Preview** to interact with it!
3576
3514
 
3577
3515
  Demonstrates interactive time validation rules.
3578
3516
 
@@ -3586,14 +3524,15 @@ Demonstrates interactive time validation rules.
3586
3524
 
3587
3525
  ```ruby
3588
3526
  # frozen_string_literal: true
3527
+
3589
3528
  require "xlsxrb"
3590
3529
  output_path = ARGV[0] || "interactive_validation_time.xlsx"
3591
- Xlsxrb.generate(output_path) do |w|
3592
- w.add_sheet("Time Validation") do |s|
3593
- s.set_column(0, width: 25)
3594
- s.set_column(1, width: 25)
3595
- s.add_row(["Schedule", "Enter Time (after 08:00):"])
3596
- s.add_data_validation("B2", type: "time", operator: "greaterThan", formula1: "0.33333", show_error_message: true, error_title: "Too Early", error: "Time must be after 08:00 AM")
3530
+ Xlsxrb.generate(output_path) do |wb|
3531
+ wb.sheet("Time Validation") do |s|
3532
+ s.column(0, width: 25)
3533
+ s.column(1, width: 25)
3534
+ s.row(["Schedule", "Enter Time (after 08:00):"])
3535
+ s.validate_data("B2", type: "time", operator: "greaterThan", formula1: "0.33333", show_error_message: true, error_title: "Too Early", error: "Time must be after 08:00 AM")
3597
3536
  end
3598
3537
  end
3599
3538
 
@@ -3634,16 +3573,16 @@ require "xlsxrb"
3634
3573
 
3635
3574
  output_path = ARGV[0] || "japanese_text.xlsx"
3636
3575
 
3637
- Xlsxrb.generate(output_path) do |w|
3638
- w.add_style("ja_font") do |style|
3576
+ Xlsxrb.generate(output_path) do |wb|
3577
+ wb.style("ja_font") do |style|
3639
3578
  style.font_name("Noto Sans CJK JP").size(12)
3640
3579
  end
3641
3580
 
3642
- w.add_sheet("Japanese") do |s|
3643
- s.set_column(0, width: 25)
3644
- s.set_column(1, width: 25)
3645
- s.add_row(["日本語ラベル", "値"], styles: { 0 => "ja_font", 1 => "ja_font" })
3646
- s.add_row(["売上", 12500], styles: { 0 => "ja_font" })
3581
+ wb.sheet("Japanese") do |s|
3582
+ s.column(0, width: 25)
3583
+ s.column(1, width: 25)
3584
+ s.row(%w[日本語ラベル 値], styles: { 0 => "ja_font", 1 => "ja_font" })
3585
+ s.row(["売上", 12_500], styles: { 0 => "ja_font" })
3647
3586
  end
3648
3587
  end
3649
3588
 
@@ -3655,7 +3594,7 @@ sheet.rows.each do |row|
3655
3594
  row_cells = row.cells.map do |c|
3656
3595
  "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
3657
3596
  end
3658
- puts "Row #{row.index}: #{row_cells.join(', ')}"
3597
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
3659
3598
  end
3660
3599
  ```
3661
3600
 
@@ -3686,22 +3625,22 @@ require "xlsxrb"
3686
3625
 
3687
3626
  output_path = ARGV[0] || "merge_freeze.xlsx"
3688
3627
 
3689
- Xlsxrb.generate(output_path) do |w|
3690
- w.add_style("title") { |style| style.border_all(style: "thin", color: "FF000000").align_horizontal("center") }
3691
- w.add_style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
3692
- w.add_sheet("Merge & Freeze") do |s|
3693
- s.set_sheet_property(:fit_to_page, true)
3694
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
3695
- s.set_column(0, width: 25)
3696
- s.set_column(1, width: 25)
3697
- s.set_column(2, width: 25)
3698
- s.add_row(["Merged Title Row", nil, nil], styles: ["title", "title", "title"])
3699
- s.add_row(["Header A", "Header B", "Header C"], styles: ["border", "border", "border"])
3700
- s.add_row(["Row 1 Col A", "Row 1 Col B", "Row 1 Col C"], styles: ["border", "border", "border"])
3701
- s.add_row(["Row 2 Col A", "Row 2 Col B", "Row 2 Col C"], styles: ["border", "border", "border"])
3702
-
3703
- s.merge_cells("A1:C1")
3704
- s.set_freeze_pane(row: 2, col: 0)
3628
+ Xlsxrb.generate(output_path) do |wb|
3629
+ wb.style("title") { |style| style.border_all(style: "thin", color: "FF000000").align_horizontal("center") }
3630
+ wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
3631
+ wb.sheet("Merge & Freeze") do |s|
3632
+ s.sheet_properties(:fit_to_page, true)
3633
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
3634
+ s.column(0, width: 25)
3635
+ s.column(1, width: 25)
3636
+ s.column(2, width: 25)
3637
+ s.row(["Merged Title Row", nil, nil], styles: %w[title title title])
3638
+ s.row(["Header A", "Header B", "Header C"], styles: %w[border border border])
3639
+ s.row(["Row 1 Col A", "Row 1 Col B", "Row 1 Col C"], styles: %w[border border border])
3640
+ s.row(["Row 2 Col A", "Row 2 Col B", "Row 2 Col C"], styles: %w[border border border])
3641
+
3642
+ s.merge(row: 0, col_start: 0, col_end: 2)
3643
+ s.freeze_pane(row: 2, col: 0)
3705
3644
  end
3706
3645
  end
3707
3646
 
@@ -3711,7 +3650,7 @@ workbook = Xlsxrb.read(output_path)
3711
3650
  sheet = workbook.sheets.first
3712
3651
  sheet.rows.first(5).each do |row|
3713
3652
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
3714
- puts "Row #{row.index}: #{row_cells.join(', ')}"
3653
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
3715
3654
  end
3716
3655
  ```
3717
3656
 
@@ -3739,14 +3678,15 @@ Demonstrates enabling printing of grid lines.
3739
3678
 
3740
3679
  ```ruby
3741
3680
  # frozen_string_literal: true
3681
+
3742
3682
  require "xlsxrb"
3743
3683
  output_path = ARGV[0] || "page_grid_lines_print.xlsx"
3744
- Xlsxrb.generate(output_path) do |w|
3745
- w.add_sheet("Print Grid Lines") do |s|
3746
- s.set_column(0, width: 25)
3747
- s.set_column(1, width: 25)
3748
- s.set_print_option(:grid_lines, true)
3749
- s.add_row(["Grid Lines Printed sheet"])
3684
+ Xlsxrb.generate(output_path) do |wb|
3685
+ wb.sheet("Print Grid Lines") do |s|
3686
+ s.column(0, width: 25)
3687
+ s.column(1, width: 25)
3688
+ s.print_options(:grid_lines, true)
3689
+ s.row(["Grid Lines Printed sheet"])
3750
3690
  end
3751
3691
  end
3752
3692
 
@@ -3786,14 +3726,15 @@ Demonstrates setting odd page headers and footers.
3786
3726
 
3787
3727
  ```ruby
3788
3728
  # frozen_string_literal: true
3729
+
3789
3730
  require "xlsxrb"
3790
3731
  output_path = ARGV[0] || "page_header_footer.xlsx"
3791
- Xlsxrb.generate(output_path) do |w|
3792
- w.add_sheet("Header Footer") do |s|
3793
- s.set_column(0, width: 25)
3794
- s.set_column(1, width: 25)
3795
- s.set_header_footer(odd_header: "&LMy Company&RPage &P", odd_footer: "&CConfidential")
3796
- s.add_row(["Header Footer sheet"])
3732
+ Xlsxrb.generate(output_path) do |wb|
3733
+ wb.sheet("Header Footer") do |s|
3734
+ s.column(0, width: 25)
3735
+ s.column(1, width: 25)
3736
+ s.header_footer(odd_header: "&LMy Company&RPage &P", odd_footer: "&CConfidential")
3737
+ s.row(["Header Footer sheet"])
3797
3738
  end
3798
3739
  end
3799
3740
 
@@ -3833,14 +3774,15 @@ Demonstrates enabling printing of row and column headings.
3833
3774
 
3834
3775
  ```ruby
3835
3776
  # frozen_string_literal: true
3777
+
3836
3778
  require "xlsxrb"
3837
3779
  output_path = ARGV[0] || "page_headings_print.xlsx"
3838
- Xlsxrb.generate(output_path) do |w|
3839
- w.add_sheet("Print Headings") do |s|
3840
- s.set_column(0, width: 25)
3841
- s.set_column(1, width: 25)
3842
- s.set_print_option(:headings, true)
3843
- s.add_row(["Row/Col Headings Printed sheet"])
3780
+ Xlsxrb.generate(output_path) do |wb|
3781
+ wb.sheet("Print Headings") do |s|
3782
+ s.column(0, width: 25)
3783
+ s.column(1, width: 25)
3784
+ s.print_options(:headings, true)
3785
+ s.row(["Row/Col Headings Printed sheet"])
3844
3786
  end
3845
3787
  end
3846
3788
 
@@ -3880,14 +3822,15 @@ Demonstrates setting narrow page margins.
3880
3822
 
3881
3823
  ```ruby
3882
3824
  # frozen_string_literal: true
3825
+
3883
3826
  require "xlsxrb"
3884
3827
  output_path = ARGV[0] || "page_margins_narrow.xlsx"
3885
- Xlsxrb.generate(output_path) do |w|
3886
- w.add_sheet("Narrow Margins") do |s|
3887
- s.set_column(0, width: 25)
3888
- s.set_column(1, width: 25)
3889
- s.set_page_margins(top: 0.25, bottom: 0.25, left: 0.25, right: 0.25, header: 0.1, footer: 0.1)
3890
- s.add_row(["Narrow Margins sheet"])
3828
+ Xlsxrb.generate(output_path) do |wb|
3829
+ wb.sheet("Narrow Margins") do |s|
3830
+ s.column(0, width: 25)
3831
+ s.column(1, width: 25)
3832
+ s.page_margins(top: 0.25, bottom: 0.25, left: 0.25, right: 0.25, header: 0.1, footer: 0.1)
3833
+ s.row(["Narrow Margins sheet"])
3891
3834
  end
3892
3835
  end
3893
3836
 
@@ -3927,14 +3870,15 @@ Demonstrates setting wide page margins.
3927
3870
 
3928
3871
  ```ruby
3929
3872
  # frozen_string_literal: true
3873
+
3930
3874
  require "xlsxrb"
3931
3875
  output_path = ARGV[0] || "page_margins_wide.xlsx"
3932
- Xlsxrb.generate(output_path) do |w|
3933
- w.add_sheet("Wide Margins") do |s|
3934
- s.set_column(0, width: 25)
3935
- s.set_column(1, width: 25)
3936
- s.set_page_margins(top: 1.0, bottom: 1.0, left: 1.0, right: 1.0, header: 0.5, footer: 0.5)
3937
- s.add_row(["Wide Margins sheet"])
3876
+ Xlsxrb.generate(output_path) do |wb|
3877
+ wb.sheet("Wide Margins") do |s|
3878
+ s.column(0, width: 25)
3879
+ s.column(1, width: 25)
3880
+ s.page_margins(top: 1.0, bottom: 1.0, left: 1.0, right: 1.0, header: 0.5, footer: 0.5)
3881
+ s.row(["Wide Margins sheet"])
3938
3882
  end
3939
3883
  end
3940
3884
 
@@ -3974,14 +3918,15 @@ Demonstrates landscape page setup for printing.
3974
3918
 
3975
3919
  ```ruby
3976
3920
  # frozen_string_literal: true
3921
+
3977
3922
  require "xlsxrb"
3978
3923
  output_path = ARGV[0] || "page_orientation_landscape.xlsx"
3979
- Xlsxrb.generate(output_path) do |w|
3980
- w.add_sheet("Landscape") do |s|
3981
- s.set_column(0, width: 25)
3982
- s.set_column(1, width: 25)
3983
- s.set_page_setup(orientation: :landscape)
3984
- s.add_row(["Landscape Orientation sheet"])
3924
+ Xlsxrb.generate(output_path) do |wb|
3925
+ wb.sheet("Landscape") do |s|
3926
+ s.column(0, width: 25)
3927
+ s.column(1, width: 25)
3928
+ s.page_setup(orientation: :landscape)
3929
+ s.row(["Landscape Orientation sheet"])
3985
3930
  end
3986
3931
  end
3987
3932
 
@@ -4021,14 +3966,15 @@ Demonstrates setting paper size to A3 (paper size 8).
4021
3966
 
4022
3967
  ```ruby
4023
3968
  # frozen_string_literal: true
3969
+
4024
3970
  require "xlsxrb"
4025
3971
  output_path = ARGV[0] || "page_paper_size_a3.xlsx"
4026
- Xlsxrb.generate(output_path) do |w|
4027
- w.add_sheet("A3 Sheet") do |s|
4028
- s.set_column(0, width: 25)
4029
- s.set_column(1, width: 25)
4030
- s.set_page_setup(paper_size: 8) # ISO A3 is paperSize="8"
4031
- s.add_row(["ISO A3 Paper Size sheet"])
3972
+ Xlsxrb.generate(output_path) do |wb|
3973
+ wb.sheet("A3 Sheet") do |s|
3974
+ s.column(0, width: 25)
3975
+ s.column(1, width: 25)
3976
+ s.page_setup(paper_size: 8) # ISO A3 is paperSize="8"
3977
+ s.row(["ISO A3 Paper Size sheet"])
4032
3978
  end
4033
3979
  end
4034
3980
 
@@ -4068,17 +4014,18 @@ Demonstrates outline grouping for rows.
4068
4014
 
4069
4015
  ```ruby
4070
4016
  # frozen_string_literal: true
4017
+
4071
4018
  require "xlsxrb"
4072
4019
  output_path = ARGV[0] || "row_grouping.xlsx"
4073
- Xlsxrb.generate(output_path) do |w|
4074
- w.add_style("parent") { |style| style.border_all(style: "thin", color: "FF000000").bold }
4075
- w.add_style("child") { |style| style.border_all(style: "thin", color: "FF000000").align_horizontal("left").indent(2) }
4076
- w.add_sheet("Row Grouping") do |s|
4077
- s.set_column(0, width: 25)
4078
- s.set_column(1, width: 25)
4079
- s.add_row(["Parent Row 1", ""], styles: ["parent", "parent"])
4080
- s.add_row(["Child Row 1.1", ""], outline_level: 1, styles: ["child", "child"])
4081
- s.add_row(["Child Row 1.2", ""], outline_level: 1, styles: ["child", "child"])
4020
+ Xlsxrb.generate(output_path) do |wb|
4021
+ wb.style("parent") { |style| style.border_all(style: "thin", color: "FF000000").bold }
4022
+ wb.style("child") { |style| style.border_all(style: "thin", color: "FF000000").align_horizontal("left").indent(2) }
4023
+ wb.sheet("Row Grouping") do |s|
4024
+ s.column(0, width: 25)
4025
+ s.column(1, width: 25)
4026
+ s.row(["Parent Row 1", ""], styles: %w[parent parent])
4027
+ s.row(["Child Row 1.1", ""], outline_level: 1, styles: %w[child child])
4028
+ s.row(["Child Row 1.2", ""], outline_level: 1, styles: %w[child child])
4082
4029
  end
4083
4030
  end
4084
4031
 
@@ -4114,15 +4061,16 @@ Demonstrates setting very tall row heights.
4114
4061
 
4115
4062
  ```ruby
4116
4063
  # frozen_string_literal: true
4064
+
4117
4065
  require "xlsxrb"
4118
4066
  output_path = ARGV[0] || "row_height_tall.xlsx"
4119
- Xlsxrb.generate(output_path) do |w|
4120
- w.add_style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
4121
- w.add_sheet("Row Height") do |s|
4122
- s.set_column(0, width: 25)
4123
- s.set_column(1, width: 25)
4124
- s.add_row(["Very Tall Row (Height 60)", ""], height: 60, styles: ["border", "border"])
4125
- s.add_row(["Normal Row", ""], styles: ["border", "border"])
4067
+ Xlsxrb.generate(output_path) do |wb|
4068
+ wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
4069
+ wb.sheet("Row Height") do |s|
4070
+ s.column(0, width: 25)
4071
+ s.column(1, width: 25)
4072
+ s.row(["Very Tall Row (Height 60)", ""], height: 60, styles: %w[border border])
4073
+ s.row(["Normal Row", ""], styles: %w[border border])
4126
4074
  end
4127
4075
  end
4128
4076
 
@@ -4157,15 +4105,16 @@ Demonstrates setting custom row heights.
4157
4105
 
4158
4106
  ```ruby
4159
4107
  # frozen_string_literal: true
4108
+
4160
4109
  require "xlsxrb"
4161
4110
  output_path = ARGV[0] || "row_heights.xlsx"
4162
- Xlsxrb.generate(output_path) do |w|
4163
- w.add_style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
4164
- w.add_sheet("Heights") do |s|
4165
- s.set_column(0, width: 25)
4166
- s.set_column(1, width: 25)
4167
- s.add_row(["Normal Row", ""], styles: ["border", "border"])
4168
- s.add_row(["Tall Row", ""], height: 40, styles: ["border", "border"])
4111
+ Xlsxrb.generate(output_path) do |wb|
4112
+ wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
4113
+ wb.sheet("Heights") do |s|
4114
+ s.column(0, width: 25)
4115
+ s.column(1, width: 25)
4116
+ s.row(["Normal Row", ""], styles: %w[border border])
4117
+ s.row(["Tall Row", ""], height: 40, styles: %w[border border])
4169
4118
  end
4170
4119
  end
4171
4120
 
@@ -4204,18 +4153,19 @@ Demonstrates customizing tab colors of individual worksheets.
4204
4153
 
4205
4154
  ```ruby
4206
4155
  # frozen_string_literal: true
4156
+
4207
4157
  require "xlsxrb"
4208
4158
  output_path = ARGV[0] || "sheet_tab_colors.xlsx"
4209
- Xlsxrb.generate(output_path) do |w|
4210
- w.add_sheet("Red Tab") do |s|
4211
- s.set_column(0, width: 25)
4212
- s.set_column(1, width: 25)
4213
- s.set_sheet_property(:tab_color, "FFFF0000")
4214
- s.add_row(["Red tab sheet"])
4159
+ Xlsxrb.generate(output_path) do |wb|
4160
+ wb.sheet("Red Tab") do |s|
4161
+ s.column(0, width: 25)
4162
+ s.column(1, width: 25)
4163
+ s.sheet_properties(:tab_color, :red)
4164
+ s.row(["Red tab sheet"])
4215
4165
  end
4216
- w.add_sheet("Green Tab") do |s|
4217
- s.set_sheet_property(:tab_color, "FF00FF00")
4218
- s.add_row(["Green tab sheet"])
4166
+ wb.sheet("Green Tab") do |s|
4167
+ s.sheet_properties(:tab_color, :green)
4168
+ s.row(["Green tab sheet"])
4219
4169
  end
4220
4170
  end
4221
4171
 
@@ -4233,8 +4183,8 @@ end
4233
4183
 
4234
4184
  ```text
4235
4185
  === Read Validation ===
4236
- Sheet: Red Tab, tab color: "FFFF0000"
4237
- Sheet: Green Tab, tab color: "FF00FF00"
4186
+ Sheet: Red Tab, tab color: "red"
4187
+ Sheet: Green Tab, tab color: "green"
4238
4188
  ```
4239
4189
 
4240
4190
  <hr/>
@@ -4251,16 +4201,17 @@ Demonstrates embedded column sparklines in cell ranges.
4251
4201
 
4252
4202
  ```ruby
4253
4203
  # frozen_string_literal: true
4204
+
4254
4205
  require "xlsxrb"
4255
4206
  output_path = ARGV[0] || "sparkline_column.xlsx"
4256
- Xlsxrb.generate(output_path) do |w|
4257
- w.add_sheet("Sparkline") do |s|
4258
- s.set_sheet_property(:fit_to_page, true)
4259
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
4260
- s.set_column(0, width: 25)
4261
- s.set_column(1, width: 25)
4262
- s.add_row([5, 12, 8, 15, nil])
4263
- s.add_sparkline_group(
4207
+ Xlsxrb.generate(output_path) do |wb|
4208
+ wb.sheet("Sparkline") do |s|
4209
+ s.sheet_properties(:fit_to_page, true)
4210
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
4211
+ s.column(0, width: 25)
4212
+ s.column(1, width: 25)
4213
+ s.row([5, 12, 8, 15, nil])
4214
+ s.sparkline_group(
4264
4215
  type: :column,
4265
4216
  sparklines: [{ location_ref: "E1", data_ref: "Sparkline!A1:D1" }]
4266
4217
  )
@@ -4273,7 +4224,7 @@ workbook = Xlsxrb.read(output_path)
4273
4224
  sheet = workbook.sheets.first
4274
4225
  sheet.rows.first(3).each do |row|
4275
4226
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
4276
- puts "Row #{row.index}: #{row_cells.join(', ')}"
4227
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
4277
4228
  end
4278
4229
  ```
4279
4230
 
@@ -4300,20 +4251,21 @@ Demonstrates embedded line sparklines in cell ranges.
4300
4251
 
4301
4252
  ```ruby
4302
4253
  # frozen_string_literal: true
4254
+
4303
4255
  require "xlsxrb"
4304
4256
  output_path = ARGV[0] || "sparkline_line.xlsx"
4305
- Xlsxrb.generate(output_path) do |w|
4306
- w.add_sheet("Sparkline") do |s|
4307
- s.set_sheet_property(:fit_to_page, true)
4308
- s.set_page_setup(fit_to_width: 1, fit_to_height: 1)
4309
- s.set_column(0, width: 25)
4310
- s.set_column(1, width: 25)
4311
- s.add_row([10, 20, 15, 30, nil])
4312
- s.add_sparkline_group(
4257
+ Xlsxrb.generate(output_path) do |wb|
4258
+ wb.sheet("Sparkline") do |s|
4259
+ s.sheet_properties(:fit_to_page, true)
4260
+ s.page_setup(fit_to_width: 1, fit_to_height: 1)
4261
+ s.column(0, width: 25)
4262
+ s.column(1, width: 25)
4263
+ s.row([10, 20, 15, 30, nil])
4264
+ s.sparkline_group(
4313
4265
  type: :line,
4314
4266
  markers: true,
4315
4267
  color_series: "FF000000",
4316
- color_markers: "FFFF0000",
4268
+ color_markers: :red,
4317
4269
  sparklines: [{ location_ref: "E1", data_ref: "Sparkline!A1:D1" }]
4318
4270
  )
4319
4271
  end
@@ -4325,7 +4277,7 @@ workbook = Xlsxrb.read(output_path)
4325
4277
  sheet = workbook.sheets.first
4326
4278
  sheet.rows.first(3).each do |row|
4327
4279
  row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
4328
- puts "Row #{row.index}: #{row_cells.join(', ')}"
4280
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
4329
4281
  end
4330
4282
  ```
4331
4283
 
@@ -4355,20 +4307,20 @@ require "xlsxrb"
4355
4307
 
4356
4308
  output_path = ARGV[0] || "styles_fonts_fills.xlsx"
4357
4309
 
4358
- Xlsxrb.generate(output_path) do |w|
4359
- w.add_style("header") do |style|
4310
+ Xlsxrb.generate(output_path) do |wb|
4311
+ wb.style("header") do |style|
4360
4312
  style.bold.size(14).font_color("FFFFFFFF").fill_color("FF4F81BD")
4361
4313
  end
4362
4314
 
4363
- w.add_style("highlight") do |style|
4315
+ wb.style("highlight") do |style|
4364
4316
  style.italic.font_color("FFC00000").fill_color("FFFFFF00")
4365
4317
  end
4366
4318
 
4367
- w.add_sheet("Styles") do
4368
- w.set_column(0, width: 25)
4369
- w.set_column(1, width: 25)
4370
- w.add_row(["Header 1", "Header 2"], styles: { 0 => "header", 1 => "header" })
4371
- w.add_row(["Normal Text", "Highlighted Text"], styles: { 1 => "highlight" })
4319
+ wb.sheet("Styles") do |sheet|
4320
+ sheet.column(0, width: 25)
4321
+ sheet.column(1, width: 25)
4322
+ sheet.row(["Header 1", "Header 2"], styles: { 0 => "header", 1 => "header" })
4323
+ sheet.row(["Normal Text", "Highlighted Text"], styles: { 1 => "highlight" })
4372
4324
  end
4373
4325
  end
4374
4326
 
@@ -4383,7 +4335,7 @@ sheet.rows.first(4).each do |row|
4383
4335
  fill = xf ? workbook.styles[:fills][xf[:fill_id]] : nil
4384
4336
  "#{c.ref}: #{c.value.inspect} (font=#{font&.[](:name)}, fill=#{fill&.[](:fg_color)&.[](:rgb)})"
4385
4337
  end
4386
- puts "Row #{row.index}: #{row_cells.join(', ')}"
4338
+ puts "Row #{row.index}: #{row_cells.join(", ")}"
4387
4339
  end
4388
4340
  ```
4389
4341
 
@@ -4411,14 +4363,15 @@ Demonstrates disabling visible grid lines in spreadsheet view.
4411
4363
 
4412
4364
  ```ruby
4413
4365
  # frozen_string_literal: true
4366
+
4414
4367
  require "xlsxrb"
4415
4368
  output_path = ARGV[0] || "view_show_grid_lines.xlsx"
4416
- Xlsxrb.generate(output_path) do |w|
4417
- w.add_sheet("Hide Grid Lines") do |s|
4418
- s.set_column(0, width: 25)
4419
- s.set_column(1, width: 25)
4420
- s.set_sheet_view(:show_grid_lines, false)
4421
- s.add_row(["No Grid Lines displayed"])
4369
+ Xlsxrb.generate(output_path) do |wb|
4370
+ wb.sheet("Hide Grid Lines") do |s|
4371
+ s.column(0, width: 25)
4372
+ s.column(1, width: 25)
4373
+ s.sheet_view(:show_grid_lines, false)
4374
+ s.row(["No Grid Lines displayed"])
4422
4375
  end
4423
4376
  end
4424
4377
 
@@ -4455,14 +4408,15 @@ Demonstrates setting custom zoom scale in sheet view (e.g. 150%).
4455
4408
 
4456
4409
  ```ruby
4457
4410
  # frozen_string_literal: true
4411
+
4458
4412
  require "xlsxrb"
4459
4413
  output_path = ARGV[0] || "view_zoom_scale.xlsx"
4460
- Xlsxrb.generate(output_path) do |w|
4461
- w.add_sheet("Zoom 150") do |s|
4462
- s.set_column(0, width: 25)
4463
- s.set_column(1, width: 25)
4464
- s.set_sheet_view(:zoom_scale, 150)
4465
- s.add_row(["Zoom scale is set to 150%"])
4414
+ Xlsxrb.generate(output_path) do |wb|
4415
+ wb.sheet("Zoom 150") do |s|
4416
+ s.column(0, width: 25)
4417
+ s.column(1, width: 25)
4418
+ s.sheet_view(:zoom_scale, 150)
4419
+ s.row(["Zoom scale is set to 150%"])
4466
4420
  end
4467
4421
  end
4468
4422
 
@@ -4501,18 +4455,19 @@ Demonstrates creating workbooks with multiple worksheets.
4501
4455
 
4502
4456
  ```ruby
4503
4457
  # frozen_string_literal: true
4458
+
4504
4459
  require "xlsxrb"
4505
4460
  output_path = ARGV[0] || "workbook_three_sheets.xlsx"
4506
- Xlsxrb.generate(output_path) do |w|
4507
- w.add_sheet("First Sheet") { |s| s.add_row(["First Sheet Data"]) }
4508
- w.add_sheet("Second Sheet") { |s| s.add_row(["Second Sheet Data"]) }
4509
- w.add_sheet("Third Sheet") { |s| s.add_row(["Third Sheet Data"]) }
4461
+ Xlsxrb.generate(output_path) do |wb|
4462
+ wb.sheet("First Sheet") { |s| s.row(["First Sheet Data"]) }
4463
+ wb.sheet("Second Sheet") { |s| s.row(["Second Sheet Data"]) }
4464
+ wb.sheet("Third Sheet") { |s| s.row(["Third Sheet Data"]) }
4510
4465
  end
4511
4466
 
4512
4467
  # 2. Read the generated sheet and print the sheets structure
4513
4468
  puts "=== Read Validation ==="
4514
4469
  workbook = Xlsxrb.read(output_path)
4515
- puts "Workbook sheets: #{workbook.sheet_names.join(', ')}"
4470
+ puts "Workbook sheets: #{workbook.sheet_names.join(", ")}"
4516
4471
  ```
4517
4472
 
4518
4473
  ### Console Output