xlsxrb 0.1.12 → 0.1.13

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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -42
  3. data/README.md +26 -22
  4. data/lib/xlsxrb/dsl_helpers.rb +59 -0
  5. data/lib/xlsxrb/elements/workbook.rb +11 -0
  6. data/lib/xlsxrb/ooxml/shared_strings_parser.rb +3 -5
  7. data/lib/xlsxrb/ooxml/workbook_writer.rb +5 -7
  8. data/lib/xlsxrb/ooxml/worksheet_parser.rb +172 -9
  9. data/lib/xlsxrb/ooxml/writer.rb +2 -1
  10. data/lib/xlsxrb/ooxml/xml_builder.rb +20 -0
  11. data/lib/xlsxrb/ooxml/zip_reader.rb +364 -78
  12. data/lib/xlsxrb/ooxml/zip_writer.rb +32 -5
  13. data/lib/xlsxrb/stream_sheet.rb +94 -6
  14. data/lib/xlsxrb/stream_writer.rb +33 -66
  15. data/lib/xlsxrb/version.rb +1 -1
  16. data/lib/xlsxrb/workbook_builder.rb +1 -1
  17. data/lib/xlsxrb/worksheet_builder.rb +3 -31
  18. data/lib/xlsxrb.rb +448 -171
  19. data/sig/generated/xlsxrb/dsl_helpers.rbs +32 -0
  20. data/sig/generated/xlsxrb/elements/workbook.rbs +7 -0
  21. data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +0 -2
  22. data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +5 -4
  23. data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +11 -0
  24. data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +96 -8
  25. data/sig/generated/xlsxrb/ooxml/zip_writer.rbs +5 -1
  26. data/sig/generated/xlsxrb/stream_sheet.rbs +43 -3
  27. data/sig/generated/xlsxrb.rbs +18 -11
  28. metadata +6 -146
  29. data/.devcontainer/Dockerfile +0 -65
  30. data/.devcontainer/devcontainer.json +0 -17
  31. data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +0 -9
  32. data/.gem_rbs_collection/ast/2.4/ast.rbs +0 -73
  33. data/.gem_rbs_collection/concurrent-ruby/1.1/.rbs_meta.yaml +0 -9
  34. data/.gem_rbs_collection/concurrent-ruby/1.1/array.rbs +0 -4
  35. data/.gem_rbs_collection/concurrent-ruby/1.1/atomic_reference.rbs +0 -16
  36. data/.gem_rbs_collection/concurrent-ruby/1.1/executor.rbs +0 -96
  37. data/.gem_rbs_collection/concurrent-ruby/1.1/hash.rbs +0 -4
  38. data/.gem_rbs_collection/concurrent-ruby/1.1/map.rbs +0 -68
  39. data/.gem_rbs_collection/concurrent-ruby/1.1/promises.rbs +0 -249
  40. data/.gem_rbs_collection/concurrent-ruby/1.1/set.rbs +0 -4
  41. data/.gem_rbs_collection/concurrent-ruby/1.1/timer_task.rbs +0 -47
  42. data/.gem_rbs_collection/concurrent-ruby/1.1/utility/processor_counter.rbs +0 -5
  43. data/.gem_rbs_collection/csv/3.3/.rbs_meta.yaml +0 -9
  44. data/.gem_rbs_collection/csv/3.3/csv.rbs +0 -3871
  45. data/.gem_rbs_collection/csv/3.3/manifest.yaml +0 -3
  46. data/.gem_rbs_collection/lint_roller/1.1/.rbs_meta.yaml +0 -9
  47. data/.gem_rbs_collection/lint_roller/1.1/lint_roller.rbs +0 -48
  48. data/.gem_rbs_collection/listen/3.9/.rbs_meta.yaml +0 -9
  49. data/.gem_rbs_collection/listen/3.9/listen.rbs +0 -25
  50. data/.gem_rbs_collection/listen/3.9/listener.rbs +0 -24
  51. data/.gem_rbs_collection/logger/1.7/.rbs_meta.yaml +0 -9
  52. data/.gem_rbs_collection/logger/1.7/formatter.rbs +0 -45
  53. data/.gem_rbs_collection/logger/1.7/log_device.rbs +0 -100
  54. data/.gem_rbs_collection/logger/1.7/logger.rbs +0 -796
  55. data/.gem_rbs_collection/logger/1.7/manifest.yaml +0 -2
  56. data/.gem_rbs_collection/logger/1.7/period.rbs +0 -17
  57. data/.gem_rbs_collection/logger/1.7/severity.rbs +0 -34
  58. data/.gem_rbs_collection/nokogiri/1.11/.rbs_meta.yaml +0 -9
  59. data/.gem_rbs_collection/nokogiri/1.11/nokogiri.rbs +0 -2332
  60. data/.gem_rbs_collection/nokogiri/1.11/patch.rbs +0 -4
  61. data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +0 -9
  62. data/.gem_rbs_collection/parallel/1.20/parallel.rbs +0 -86
  63. data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +0 -9
  64. data/.gem_rbs_collection/parser/3.2/manifest.yaml +0 -7
  65. data/.gem_rbs_collection/parser/3.2/parser.rbs +0 -194
  66. data/.gem_rbs_collection/parser/3.2/polyfill.rbs +0 -4
  67. data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +0 -9
  68. data/.gem_rbs_collection/rainbow/3.0/global.rbs +0 -7
  69. data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +0 -209
  70. data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +0 -5
  71. data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +0 -9
  72. data/.gem_rbs_collection/rake/13.0/manifest.yaml +0 -2
  73. data/.gem_rbs_collection/rake/13.0/rake.rbs +0 -39
  74. data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +0 -9
  75. data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +0 -17
  76. data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +0 -9
  77. data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +0 -208
  78. data/.gem_rbs_collection/rubocop-ast/1.46/.rbs_meta.yaml +0 -9
  79. data/.gem_rbs_collection/rubocop-ast/1.46/rubocop-ast.rbs +0 -903
  80. data/.gem_rbs_collection/rubyzip/3.2/.rbs_meta.yaml +0 -9
  81. data/.gem_rbs_collection/rubyzip/3.2/manifest.yaml +0 -8
  82. data/.gem_rbs_collection/rubyzip/3.2/zip/central_directory.rbs +0 -42
  83. data/.gem_rbs_collection/rubyzip/3.2/zip/compressor.rbs +0 -5
  84. data/.gem_rbs_collection/rubyzip/3.2/zip/constants.rbs +0 -47
  85. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/aes_encryption.rbs +0 -30
  86. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/decrypted_io.rbs +0 -9
  87. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/encryption.rbs +0 -7
  88. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/null_encryption.rbs +0 -19
  89. data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/traditional_encryption.rbs +0 -31
  90. data/.gem_rbs_collection/rubyzip/3.2/zip/decompressor.rbs +0 -18
  91. data/.gem_rbs_collection/rubyzip/3.2/zip/deflater.rbs +0 -12
  92. data/.gem_rbs_collection/rubyzip/3.2/zip/dirtyable.rbs +0 -11
  93. data/.gem_rbs_collection/rubyzip/3.2/zip/dos_time.rbs +0 -13
  94. data/.gem_rbs_collection/rubyzip/3.2/zip/entry.rbs +0 -95
  95. data/.gem_rbs_collection/rubyzip/3.2/zip/entry_set.rbs +0 -31
  96. data/.gem_rbs_collection/rubyzip/3.2/zip/errors.rbs +0 -58
  97. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/aes.rbs +0 -24
  98. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/generic.rbs +0 -17
  99. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/ntfs.rbs +0 -23
  100. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/old_unix.rbs +0 -22
  101. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/universal_time.rbs +0 -30
  102. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unix.rbs +0 -20
  103. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unknown.rbs +0 -15
  104. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/zip64.rbs +0 -26
  105. data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field.rbs +0 -21
  106. data/.gem_rbs_collection/rubyzip/3.2/zip/file.rbs +0 -131
  107. data/.gem_rbs_collection/rubyzip/3.2/zip/file_split.rbs +0 -14
  108. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/dir.rbs +0 -33
  109. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/directory_iterator.rbs +0 -21
  110. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file.rbs +0 -63
  111. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file_stat.rbs +0 -55
  112. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/zip_file_name_mapper.rbs +0 -35
  113. data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem.rbs +0 -7
  114. data/.gem_rbs_collection/rubyzip/3.2/zip/inflater.rbs +0 -10
  115. data/.gem_rbs_collection/rubyzip/3.2/zip/input_stream.rbs +0 -22
  116. data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_input_stream.rbs +0 -29
  117. data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_output_stream.rbs +0 -17
  118. data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras.rbs +0 -13
  119. data/.gem_rbs_collection/rubyzip/3.2/zip/null_compressor.rbs +0 -10
  120. data/.gem_rbs_collection/rubyzip/3.2/zip/null_decompressor.rbs +0 -8
  121. data/.gem_rbs_collection/rubyzip/3.2/zip/null_input_stream.rbs +0 -6
  122. data/.gem_rbs_collection/rubyzip/3.2/zip/output_stream.rbs +0 -30
  123. data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_compressor.rbs +0 -10
  124. data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_decompressor.rbs +0 -10
  125. data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_directory.rbs +0 -5
  126. data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_stream.rbs +0 -15
  127. data/.gem_rbs_collection/rubyzip/3.2/zip/version.rbs +0 -3
  128. data/.gem_rbs_collection/rubyzip/3.2/zip.rbs +0 -40
  129. data/.mutant.yml +0 -8
  130. data/Rakefile +0 -633
  131. data/Steepfile +0 -18
  132. data/benchmark.rb +0 -406
  133. data/docs/ARCHITECTURE.md +0 -514
  134. data/docs/DEVELOPMENT.md +0 -137
  135. data/docs/MUTATION_TESTING.md +0 -52
  136. data/docs/PEER_LIBRARIES.md +0 -121
  137. data/docs/QUALITY_ASSURANCE.md +0 -26
  138. data/docs/SPEC_SOURCES.md +0 -48
  139. data/docs/assets/benchmark_results.svg +0 -144
  140. data/docs/assets/lsp_autocompletion.png +0 -0
  141. data/docs/assets/playground_preview.png +0 -0
  142. data/docs/coi-serviceworker.js +0 -82
  143. data/docs/office_thread.js +0 -77
  144. data/docs/preview.html +0 -719
  145. data/docs/visual/VisualGallery.md +0 -4683
  146. data/docs/wasm/ruby.wasm +0 -0
  147. data/docs/wasm/wasm_doc_helper.css +0 -351
  148. data/docs/wasm/wasm_doc_helper.js +0 -439
  149. data/docs/zeta.js +0 -1107
  150. data/rbs_collection.lock.yaml +0 -252
  151. data/rbs_collection.yaml +0 -19
  152. data/vendor/sdk_runner/Program.cs +0 -93
  153. data/vendor/sdk_runner/sdk_runner.csproj +0 -13
@@ -1,4683 +0,0 @@
1
- # Visual Examples Gallery
2
-
3
- This gallery showcases `xlsxrb` DSL usage side-by-side with the visual rendering in LibreOffice Calc.
4
-
5
- [◄ Back to README](../../README.md)
6
-
7
- ## Capability Overview
8
-
9
- <table>
10
- <thead>
11
- <tr>
12
- <th align="left">Feature</th>
13
- <th align="center">Visual Preview</th>
14
- <th align="center">Link to Detail</th>
15
- </tr>
16
- </thead>
17
- <tbody>
18
- <tr>
19
- <td><strong>Align Horizontal</strong></td>
20
- <td align="center"><img src="../../test/visual/baselines/align_horizontal/page-1.png" width="160" alt="Align Horizontal"/></td>
21
- <td align="center"><a href="#align-horizontal">View Code &amp; Detail</a></td>
22
- </tr>
23
- <tr>
24
- <td><strong>Align Horizontal Fill</strong></td>
25
- <td align="center"><img src="../../test/visual/baselines/align_horizontal_fill/page-1.png" width="160" alt="Align Horizontal Fill"/></td>
26
- <td align="center"><a href="#align-horizontal-fill">View Code &amp; Detail</a></td>
27
- </tr>
28
- <tr>
29
- <td><strong>Align Horizontal Justify</strong></td>
30
- <td align="center"><img src="../../test/visual/baselines/align_horizontal_justify/page-1.png" width="160" alt="Align Horizontal Justify"/></td>
31
- <td align="center"><a href="#align-horizontal-justify">View Code &amp; Detail</a></td>
32
- </tr>
33
- <tr>
34
- <td><strong>Align Indent</strong></td>
35
- <td align="center"><img src="../../test/visual/baselines/align_indent/page-1.png" width="160" alt="Align Indent"/></td>
36
- <td align="center"><a href="#align-indent">View Code &amp; Detail</a></td>
37
- </tr>
38
- <tr>
39
- <td><strong>Align Text Rotation</strong></td>
40
- <td align="center"><img src="../../test/visual/baselines/align_text_rotation/page-1.png" width="160" alt="Align Text Rotation"/></td>
41
- <td align="center"><a href="#align-text-rotation">View Code &amp; Detail</a></td>
42
- </tr>
43
- <tr>
44
- <td><strong>Align Text Wrap</strong></td>
45
- <td align="center"><img src="../../test/visual/baselines/align_text_wrap/page-1.png" width="160" alt="Align Text Wrap"/></td>
46
- <td align="center"><a href="#align-text-wrap">View Code &amp; Detail</a></td>
47
- </tr>
48
- <tr>
49
- <td><strong>Align Vertical</strong></td>
50
- <td align="center"><img src="../../test/visual/baselines/align_vertical/page-1.png" width="160" alt="Align Vertical"/></td>
51
- <td align="center"><a href="#align-vertical">View Code &amp; Detail</a></td>
52
- </tr>
53
- <tr>
54
- <td><strong>Basic Data</strong></td>
55
- <td align="center"><img src="../../test/visual/baselines/basic_data/page-1.png" width="160" alt="Basic Data"/></td>
56
- <td align="center"><a href="#basic-data">View Code &amp; Detail</a></td>
57
- </tr>
58
- <tr>
59
- <td><strong>Borders</strong></td>
60
- <td align="center"><img src="../../test/visual/baselines/borders/page-1.png" width="160" alt="Borders"/></td>
61
- <td align="center"><a href="#borders">View Code &amp; Detail</a></td>
62
- </tr>
63
- <tr>
64
- <td><strong>Cell Booleans</strong></td>
65
- <td align="center"><img src="../../test/visual/baselines/cell_booleans/page-1.png" width="160" alt="Cell Booleans"/></td>
66
- <td align="center"><a href="#cell-booleans">View Code &amp; Detail</a></td>
67
- </tr>
68
- <tr>
69
- <td><strong>Cell Dates</strong></td>
70
- <td align="center"><img src="../../test/visual/baselines/cell_dates/page-1.png" width="160" alt="Cell Dates"/></td>
71
- <td align="center"><a href="#cell-dates">View Code &amp; Detail</a></td>
72
- </tr>
73
- <tr>
74
- <td><strong>Cell Formulas</strong></td>
75
- <td align="center"><img src="../../test/visual/baselines/cell_formulas/page-1.png" width="160" alt="Cell Formulas"/></td>
76
- <td align="center"><a href="#cell-formulas">View Code &amp; Detail</a></td>
77
- </tr>
78
- <tr>
79
- <td><strong>Cell Num Currency Jpy</strong></td>
80
- <td align="center"><img src="../../test/visual/baselines/cell_num_currency_jpy/page-1.png" width="160" alt="Cell Num Currency Jpy"/></td>
81
- <td align="center"><a href="#cell-num-currency-jpy">View Code &amp; Detail</a></td>
82
- </tr>
83
- <tr>
84
- <td><strong>Cell Num Custom Colors</strong></td>
85
- <td align="center"><img src="../../test/visual/baselines/cell_num_custom_colors/page-1.png" width="160" alt="Cell Num Custom Colors"/></td>
86
- <td align="center"><a href="#cell-num-custom-colors">View Code &amp; Detail</a></td>
87
- </tr>
88
- <tr>
89
- <td><strong>Cell Num Fractions</strong></td>
90
- <td align="center"><img src="../../test/visual/baselines/cell_num_fractions/page-1.png" width="160" alt="Cell Num Fractions"/></td>
91
- <td align="center"><a href="#cell-num-fractions">View Code &amp; Detail</a></td>
92
- </tr>
93
- <tr>
94
- <td><strong>Cell Num Percent Decimals</strong></td>
95
- <td align="center"><img src="../../test/visual/baselines/cell_num_percent_decimals/page-1.png" width="160" alt="Cell Num Percent Decimals"/></td>
96
- <td align="center"><a href="#cell-num-percent-decimals">View Code &amp; Detail</a></td>
97
- </tr>
98
- <tr>
99
- <td><strong>Cell Num Scientific</strong></td>
100
- <td align="center"><img src="../../test/visual/baselines/cell_num_scientific/page-1.png" width="160" alt="Cell Num Scientific"/></td>
101
- <td align="center"><a href="#cell-num-scientific">View Code &amp; Detail</a></td>
102
- </tr>
103
- <tr>
104
- <td><strong>Cell Numbers</strong></td>
105
- <td align="center"><img src="../../test/visual/baselines/cell_numbers/page-1.png" width="160" alt="Cell Numbers"/></td>
106
- <td align="center"><a href="#cell-numbers">View Code &amp; Detail</a></td>
107
- </tr>
108
- <tr>
109
- <td><strong>Cell Rich Text</strong></td>
110
- <td align="center"><img src="../../test/visual/baselines/cell_rich_text/page-1.png" width="160" alt="Cell Rich Text"/></td>
111
- <td align="center"><a href="#cell-rich-text">View Code &amp; Detail</a></td>
112
- </tr>
113
- <tr>
114
- <td><strong>Cell Times</strong></td>
115
- <td align="center"><img src="../../test/visual/baselines/cell_times/page-1.png" width="160" alt="Cell Times"/></td>
116
- <td align="center"><a href="#cell-times">View Code &amp; Detail</a></td>
117
- </tr>
118
- <tr>
119
- <td><strong>Cf Begins With</strong></td>
120
- <td align="center"><img src="../../test/visual/baselines/cf_begins_with/page-1.png" width="160" alt="Cf Begins With"/></td>
121
- <td align="center"><a href="#cf-begins-with">View Code &amp; Detail</a></td>
122
- </tr>
123
- <tr>
124
- <td><strong>Cf Cell Between</strong></td>
125
- <td align="center"><img src="../../test/visual/baselines/cf_cell_between/page-1.png" width="160" alt="Cf Cell Between"/></td>
126
- <td align="center"><a href="#cf-cell-between">View Code &amp; Detail</a></td>
127
- </tr>
128
- <tr>
129
- <td><strong>Cf Cell Equal To</strong></td>
130
- <td align="center"><img src="../../test/visual/baselines/cf_cell_equal_to/page-1.png" width="160" alt="Cf Cell Equal To"/></td>
131
- <td align="center"><a href="#cf-cell-equal-to">View Code &amp; Detail</a></td>
132
- </tr>
133
- <tr>
134
- <td><strong>Cf Cell Greater Equal</strong></td>
135
- <td align="center"><img src="../../test/visual/baselines/cf_cell_greater_equal/page-1.png" width="160" alt="Cf Cell Greater Equal"/></td>
136
- <td align="center"><a href="#cf-cell-greater-equal">View Code &amp; Detail</a></td>
137
- </tr>
138
- <tr>
139
- <td><strong>Cf Cell Greater Than</strong></td>
140
- <td align="center"><img src="../../test/visual/baselines/cf_cell_greater_than/page-1.png" width="160" alt="Cf Cell Greater Than"/></td>
141
- <td align="center"><a href="#cf-cell-greater-than">View Code &amp; Detail</a></td>
142
- </tr>
143
- <tr>
144
- <td><strong>Cf Cell Less Than</strong></td>
145
- <td align="center"><img src="../../test/visual/baselines/cf_cell_less_than/page-1.png" width="160" alt="Cf Cell Less Than"/></td>
146
- <td align="center"><a href="#cf-cell-less-than">View Code &amp; Detail</a></td>
147
- </tr>
148
- <tr>
149
- <td><strong>Cf Color Scale</strong></td>
150
- <td align="center"><img src="../../test/visual/baselines/cf_color_scale/page-1.png" width="160" alt="Cf Color Scale"/></td>
151
- <td align="center"><a href="#cf-color-scale">View Code &amp; Detail</a></td>
152
- </tr>
153
- <tr>
154
- <td><strong>Cf Contains Text</strong></td>
155
- <td align="center"><img src="../../test/visual/baselines/cf_contains_text/page-1.png" width="160" alt="Cf Contains Text"/></td>
156
- <td align="center"><a href="#cf-contains-text">View Code &amp; Detail</a></td>
157
- </tr>
158
- <tr>
159
- <td><strong>Cf Data Bar</strong></td>
160
- <td align="center"><img src="../../test/visual/baselines/cf_data_bar/page-1.png" width="160" alt="Cf Data Bar"/></td>
161
- <td align="center"><a href="#cf-data-bar">View Code &amp; Detail</a></td>
162
- </tr>
163
- <tr>
164
- <td><strong>Cf Ends With</strong></td>
165
- <td align="center"><img src="../../test/visual/baselines/cf_ends_with/page-1.png" width="160" alt="Cf Ends With"/></td>
166
- <td align="center"><a href="#cf-ends-with">View Code &amp; Detail</a></td>
167
- </tr>
168
- <tr>
169
- <td><strong>Cf Expression Formula</strong></td>
170
- <td align="center"><img src="../../test/visual/baselines/cf_expression_formula/page-1.png" width="160" alt="Cf Expression Formula"/></td>
171
- <td align="center"><a href="#cf-expression-formula">View Code &amp; Detail</a></td>
172
- </tr>
173
- <tr>
174
- <td><strong>Cf Icon Set</strong></td>
175
- <td align="center"><img src="../../test/visual/baselines/cf_icon_set/page-1.png" width="160" alt="Cf Icon Set"/></td>
176
- <td align="center"><a href="#cf-icon-set">View Code &amp; Detail</a></td>
177
- </tr>
178
- <tr>
179
- <td><strong>Chart Area</strong></td>
180
- <td align="center"><img src="../../test/visual/baselines/chart_area/page-1.png" width="160" alt="Chart Area"/></td>
181
- <td align="center"><a href="#chart-area">View Code &amp; Detail</a></td>
182
- </tr>
183
- <tr>
184
- <td><strong>Chart Area Stacked</strong></td>
185
- <td align="center"><img src="../../test/visual/baselines/chart_area_stacked/page-1.png" width="160" alt="Chart Area Stacked"/></td>
186
- <td align="center"><a href="#chart-area-stacked">View Code &amp; Detail</a></td>
187
- </tr>
188
- <tr>
189
- <td><strong>Chart Bar</strong></td>
190
- <td align="center"><img src="../../test/visual/baselines/chart_bar/page-1.png" width="160" alt="Chart Bar"/></td>
191
- <td align="center"><a href="#chart-bar">View Code &amp; Detail</a></td>
192
- </tr>
193
- <tr>
194
- <td><strong>Chart Bar Percent Stacked</strong></td>
195
- <td align="center"><img src="../../test/visual/baselines/chart_bar_percent_stacked/page-1.png" width="160" alt="Chart Bar Percent Stacked"/></td>
196
- <td align="center"><a href="#chart-bar-percent-stacked">View Code &amp; Detail</a></td>
197
- </tr>
198
- <tr>
199
- <td><strong>Chart Bar Stacked</strong></td>
200
- <td align="center"><img src="../../test/visual/baselines/chart_bar_stacked/page-1.png" width="160" alt="Chart Bar Stacked"/></td>
201
- <td align="center"><a href="#chart-bar-stacked">View Code &amp; Detail</a></td>
202
- </tr>
203
- <tr>
204
- <td><strong>Chart Doughnut</strong></td>
205
- <td align="center"><img src="../../test/visual/baselines/chart_doughnut/page-1.png" width="160" alt="Chart Doughnut"/></td>
206
- <td align="center"><a href="#chart-doughnut">View Code &amp; Detail</a></td>
207
- </tr>
208
- <tr>
209
- <td><strong>Chart Line</strong></td>
210
- <td align="center"><img src="../../test/visual/baselines/chart_line/page-1.png" width="160" alt="Chart Line"/></td>
211
- <td align="center"><a href="#chart-line">View Code &amp; Detail</a></td>
212
- </tr>
213
- <tr>
214
- <td><strong>Chart Line Stacked</strong></td>
215
- <td align="center"><img src="../../test/visual/baselines/chart_line_stacked/page-1.png" width="160" alt="Chart Line Stacked"/></td>
216
- <td align="center"><a href="#chart-line-stacked">View Code &amp; Detail</a></td>
217
- </tr>
218
- <tr>
219
- <td><strong>Chart Pie</strong></td>
220
- <td align="center"><img src="../../test/visual/baselines/chart_pie/page-1.png" width="160" alt="Chart Pie"/></td>
221
- <td align="center"><a href="#chart-pie">View Code &amp; Detail</a></td>
222
- </tr>
223
- <tr>
224
- <td><strong>Chart Radar</strong></td>
225
- <td align="center"><img src="../../test/visual/baselines/chart_radar/page-1.png" width="160" alt="Chart Radar"/></td>
226
- <td align="center"><a href="#chart-radar">View Code &amp; Detail</a></td>
227
- </tr>
228
- <tr>
229
- <td><strong>Chart Scatter</strong></td>
230
- <td align="center"><img src="../../test/visual/baselines/chart_scatter/page-1.png" width="160" alt="Chart Scatter"/></td>
231
- <td align="center"><a href="#chart-scatter">View Code &amp; Detail</a></td>
232
- </tr>
233
- <tr>
234
- <td><strong>Col Grouping</strong></td>
235
- <td align="center"><img src="../../test/visual/baselines/col_grouping/page-1.png" width="160" alt="Col Grouping"/></td>
236
- <td align="center"><a href="#col-grouping">View Code &amp; Detail</a></td>
237
- </tr>
238
- <tr>
239
- <td><strong>Col Width Tall</strong></td>
240
- <td align="center"><img src="../../test/visual/baselines/col_width_tall/page-1.png" width="160" alt="Col Width Tall"/></td>
241
- <td align="center"><a href="#col-width-tall">View Code &amp; Detail</a></td>
242
- </tr>
243
- <tr>
244
- <td><strong>Col Widths</strong></td>
245
- <td align="center"><img src="../../test/visual/baselines/col_widths/page-1.png" width="160" alt="Col Widths"/></td>
246
- <td align="center"><a href="#col-widths">View Code &amp; Detail</a></td>
247
- </tr>
248
- <tr>
249
- <td><strong>Conditional Formatting</strong></td>
250
- <td align="center"><img src="../../test/visual/baselines/conditional_formatting/page-1.png" width="160" alt="Conditional Formatting"/></td>
251
- <td align="center"><a href="#conditional-formatting">View Code &amp; Detail</a></td>
252
- </tr>
253
- <tr>
254
- <td><strong>Drawing Shapes</strong></td>
255
- <td align="center"><img src="../../test/visual/baselines/drawing_shapes/page-1.png" width="160" alt="Drawing Shapes"/></td>
256
- <td align="center"><a href="#drawing-shapes">View Code &amp; Detail</a></td>
257
- </tr>
258
- <tr>
259
- <td><strong>Embedded Images</strong></td>
260
- <td align="center"><img src="../../test/visual/baselines/embedded_images/page-1.png" width="160" alt="Embedded Images"/></td>
261
- <td align="center"><a href="#embedded-images">View Code &amp; Detail</a></td>
262
- </tr>
263
- <tr>
264
- <td><strong>Fill Gradients</strong></td>
265
- <td align="center"><img src="../../test/visual/baselines/fill_gradients/page-1.png" width="160" alt="Fill Gradients"/></td>
266
- <td align="center"><a href="#fill-gradients">View Code &amp; Detail</a></td>
267
- </tr>
268
- <tr>
269
- <td><strong>Fill Patterns</strong></td>
270
- <td align="center"><img src="../../test/visual/baselines/fill_patterns/page-1.png" width="160" alt="Fill Patterns"/></td>
271
- <td align="center"><a href="#fill-patterns">View Code &amp; Detail</a></td>
272
- </tr>
273
- <tr>
274
- <td><strong>Fill Solid Colors</strong></td>
275
- <td align="center"><img src="../../test/visual/baselines/fill_solid_colors/page-1.png" width="160" alt="Fill Solid Colors"/></td>
276
- <td align="center"><a href="#fill-solid-colors">View Code &amp; Detail</a></td>
277
- </tr>
278
- <tr>
279
- <td><strong>Fonts</strong></td>
280
- <td align="center"><img src="../../test/visual/baselines/fonts/page-1.png" width="160" alt="Fonts"/></td>
281
- <td align="center"><a href="#fonts">View Code &amp; Detail</a></td>
282
- </tr>
283
- <tr>
284
- <td><strong>Interactive Autofilter</strong></td>
285
- <td align="center"><img src="../../test/visual/baselines/interactive_autofilter/page-1.png" width="160" alt="Interactive Autofilter"/></td>
286
- <td align="center"><a href="#interactive-autofilter">View Code &amp; Detail</a></td>
287
- </tr>
288
- <tr>
289
- <td><strong>Interactive Comments</strong></td>
290
- <td align="center"><img src="../../test/visual/baselines/interactive_comments/page-1.png" width="160" alt="Interactive Comments"/></td>
291
- <td align="center"><a href="#interactive-comments">View Code &amp; Detail</a></td>
292
- </tr>
293
- <tr>
294
- <td><strong>Interactive Validation Custom</strong></td>
295
- <td align="center"><img src="../../test/visual/baselines/interactive_validation_custom/page-1.png" width="160" alt="Interactive Validation Custom"/></td>
296
- <td align="center"><a href="#interactive-validation-custom">View Code &amp; Detail</a></td>
297
- </tr>
298
- <tr>
299
- <td><strong>Interactive Validation Date</strong></td>
300
- <td align="center"><img src="../../test/visual/baselines/interactive_validation_date/page-1.png" width="160" alt="Interactive Validation Date"/></td>
301
- <td align="center"><a href="#interactive-validation-date">View Code &amp; Detail</a></td>
302
- </tr>
303
- <tr>
304
- <td><strong>Interactive Validation List</strong></td>
305
- <td align="center"><img src="../../test/visual/baselines/interactive_validation_list/page-1.png" width="160" alt="Interactive Validation List"/></td>
306
- <td align="center"><a href="#interactive-validation-list">View Code &amp; Detail</a></td>
307
- </tr>
308
- <tr>
309
- <td><strong>Interactive Validation Range</strong></td>
310
- <td align="center"><img src="../../test/visual/baselines/interactive_validation_range/page-1.png" width="160" alt="Interactive Validation Range"/></td>
311
- <td align="center"><a href="#interactive-validation-range">View Code &amp; Detail</a></td>
312
- </tr>
313
- <tr>
314
- <td><strong>Interactive Validation Text Length</strong></td>
315
- <td align="center"><img src="../../test/visual/baselines/interactive_validation_text_length/page-1.png" width="160" alt="Interactive Validation Text Length"/></td>
316
- <td align="center"><a href="#interactive-validation-text-length">View Code &amp; Detail</a></td>
317
- </tr>
318
- <tr>
319
- <td><strong>Interactive Validation Time</strong></td>
320
- <td align="center"><img src="../../test/visual/baselines/interactive_validation_time/page-1.png" width="160" alt="Interactive Validation Time"/></td>
321
- <td align="center"><a href="#interactive-validation-time">View Code &amp; Detail</a></td>
322
- </tr>
323
- <tr>
324
- <td><strong>Japanese Text</strong></td>
325
- <td align="center"><img src="../../test/visual/baselines/japanese_text/page-1.png" width="160" alt="Japanese Text"/></td>
326
- <td align="center"><a href="#japanese-text">View Code &amp; Detail</a></td>
327
- </tr>
328
- <tr>
329
- <td><strong>Merge Freeze</strong></td>
330
- <td align="center"><img src="../../test/visual/baselines/merge_freeze/page-1.png" width="160" alt="Merge Freeze"/></td>
331
- <td align="center"><a href="#merge-freeze">View Code &amp; Detail</a></td>
332
- </tr>
333
- <tr>
334
- <td><strong>Page Grid Lines Print</strong></td>
335
- <td align="center"><img src="../../test/visual/baselines/page_grid_lines_print/page-1.png" width="160" alt="Page Grid Lines Print"/></td>
336
- <td align="center"><a href="#page-grid-lines-print">View Code &amp; Detail</a></td>
337
- </tr>
338
- <tr>
339
- <td><strong>Page Header Footer</strong></td>
340
- <td align="center"><img src="../../test/visual/baselines/page_header_footer/page-1.png" width="160" alt="Page Header Footer"/></td>
341
- <td align="center"><a href="#page-header-footer">View Code &amp; Detail</a></td>
342
- </tr>
343
- <tr>
344
- <td><strong>Page Headings Print</strong></td>
345
- <td align="center"><img src="../../test/visual/baselines/page_headings_print/page-1.png" width="160" alt="Page Headings Print"/></td>
346
- <td align="center"><a href="#page-headings-print">View Code &amp; Detail</a></td>
347
- </tr>
348
- <tr>
349
- <td><strong>Page Margins Narrow</strong></td>
350
- <td align="center"><img src="../../test/visual/baselines/page_margins_narrow/page-1.png" width="160" alt="Page Margins Narrow"/></td>
351
- <td align="center"><a href="#page-margins-narrow">View Code &amp; Detail</a></td>
352
- </tr>
353
- <tr>
354
- <td><strong>Page Margins Wide</strong></td>
355
- <td align="center"><img src="../../test/visual/baselines/page_margins_wide/page-1.png" width="160" alt="Page Margins Wide"/></td>
356
- <td align="center"><a href="#page-margins-wide">View Code &amp; Detail</a></td>
357
- </tr>
358
- <tr>
359
- <td><strong>Page Orientation Landscape</strong></td>
360
- <td align="center"><img src="../../test/visual/baselines/page_orientation_landscape/page-1.png" width="160" alt="Page Orientation Landscape"/></td>
361
- <td align="center"><a href="#page-orientation-landscape">View Code &amp; Detail</a></td>
362
- </tr>
363
- <tr>
364
- <td><strong>Page Paper Size A3</strong></td>
365
- <td align="center"><img src="../../test/visual/baselines/page_paper_size_a3/page-1.png" width="160" alt="Page Paper Size A3"/></td>
366
- <td align="center"><a href="#page-paper-size-a3">View Code &amp; Detail</a></td>
367
- </tr>
368
- <tr>
369
- <td><strong>Pivot Table</strong></td>
370
- <td align="center"><img src="../../test/visual/baselines/pivot_table/page-1.png" width="160" alt="Pivot Table"/></td>
371
- <td align="center"><a href="#pivot-table">View Code &amp; Detail</a></td>
372
- </tr>
373
- <tr>
374
- <td><strong>Row Grouping</strong></td>
375
- <td align="center"><img src="../../test/visual/baselines/row_grouping/page-1.png" width="160" alt="Row Grouping"/></td>
376
- <td align="center"><a href="#row-grouping">View Code &amp; Detail</a></td>
377
- </tr>
378
- <tr>
379
- <td><strong>Row Height Tall</strong></td>
380
- <td align="center"><img src="../../test/visual/baselines/row_height_tall/page-1.png" width="160" alt="Row Height Tall"/></td>
381
- <td align="center"><a href="#row-height-tall">View Code &amp; Detail</a></td>
382
- </tr>
383
- <tr>
384
- <td><strong>Row Heights</strong></td>
385
- <td align="center"><img src="../../test/visual/baselines/row_heights/page-1.png" width="160" alt="Row Heights"/></td>
386
- <td align="center"><a href="#row-heights">View Code &amp; Detail</a></td>
387
- </tr>
388
- <tr>
389
- <td><strong>Sheet Tab Colors</strong></td>
390
- <td align="center"><img src="../../test/visual/baselines/sheet_tab_colors/page-1.png" width="160" alt="Sheet Tab Colors"/></td>
391
- <td align="center"><a href="#sheet-tab-colors">View Code &amp; Detail</a></td>
392
- </tr>
393
- <tr>
394
- <td><strong>Sparkline Column</strong></td>
395
- <td align="center"><img src="../../test/visual/baselines/sparkline_column/page-1.png" width="160" alt="Sparkline Column"/></td>
396
- <td align="center"><a href="#sparkline-column">View Code &amp; Detail</a></td>
397
- </tr>
398
- <tr>
399
- <td><strong>Sparkline Line</strong></td>
400
- <td align="center"><img src="../../test/visual/baselines/sparkline_line/page-1.png" width="160" alt="Sparkline Line"/></td>
401
- <td align="center"><a href="#sparkline-line">View Code &amp; Detail</a></td>
402
- </tr>
403
- <tr>
404
- <td><strong>Styles Fonts Fills</strong></td>
405
- <td align="center"><img src="../../test/visual/baselines/styles_fonts_fills/page-1.png" width="160" alt="Styles Fonts Fills"/></td>
406
- <td align="center"><a href="#styles-fonts-fills">View Code &amp; Detail</a></td>
407
- </tr>
408
- <tr>
409
- <td><strong>Table Styles</strong></td>
410
- <td align="center"><img src="../../test/visual/baselines/table_styles/page-1.png" width="160" alt="Table Styles"/></td>
411
- <td align="center"><a href="#table-styles">View Code &amp; Detail</a></td>
412
- </tr>
413
- <tr>
414
- <td><strong>View Show Grid Lines</strong></td>
415
- <td align="center"><img src="../../test/visual/baselines/view_show_grid_lines/page-1.png" width="160" alt="View Show Grid Lines"/></td>
416
- <td align="center"><a href="#view-show-grid-lines">View Code &amp; Detail</a></td>
417
- </tr>
418
- <tr>
419
- <td><strong>View Zoom Scale</strong></td>
420
- <td align="center"><img src="../../test/visual/baselines/view_zoom_scale/page-1.png" width="160" alt="View Zoom Scale"/></td>
421
- <td align="center"><a href="#view-zoom-scale">View Code &amp; Detail</a></td>
422
- </tr>
423
- <tr>
424
- <td><strong>Workbook Three Sheets</strong></td>
425
- <td align="center"><img src="../../test/visual/baselines/workbook_three_sheets/page-1.png" width="160" alt="Workbook Three Sheets"/></td>
426
- <td align="center"><a href="#workbook-three-sheets">View Code &amp; Detail</a></td>
427
- </tr>
428
- </tbody>
429
- </table>
430
-
431
-
432
- ---
433
-
434
- ## Align Horizontal
435
-
436
- Demonstrates horizontal text alignment (left, center, right).
437
-
438
- ### Rendered Output (LibreOffice Calc)
439
-
440
- <div><img src="../../test/visual/baselines/align_horizontal/page-1.png" width="100%" alt="Preview"/></div>
441
-
442
- ### DSL Code
443
-
444
- ```ruby
445
- # frozen_string_literal: true
446
-
447
- require "xlsxrb"
448
- output_path = ARGV[0] || "align_horizontal.xlsx"
449
- Xlsxrb.write(output_path) do |wb|
450
- wb.style("left") { |s| s.align_horizontal("left") }
451
- wb.style("center") { |s| s.align_horizontal("center") }
452
- wb.style("right") { |s| s.align_horizontal("right") }
453
- wb.sheet("Alignment") do |s|
454
- s.print_options(:grid_lines, true)
455
- s.column(0, width: 20)
456
- s.column(1, width: 20)
457
- s.column(2, width: 20)
458
- s.row(%w[Left Center Right], styles: { 0 => "left", 1 => "center", 2 => "right" })
459
- end
460
- end
461
-
462
- # 2. Read the generated sheet and print the parsed alignments
463
- puts "=== Read Alignment (Xlsxrb.read) ==="
464
- workbook = Xlsxrb.read(output_path).load
465
- sheet = workbook.sheets.first
466
- row = sheet.rows.first
467
-
468
- row.cells.each do |c|
469
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
470
- align_h = xf&.dig(:alignment, :horizontal)
471
- puts "Cell #{c.ref} ('#{c.value}'): align_horizontal = #{align_h.inspect}"
472
- end
473
- ```
474
-
475
- ### Console Output
476
-
477
- ```text
478
- === Read Alignment (Xlsxrb.read) ===
479
- Cell A1 ('Left'): align_horizontal = "left"
480
- Cell B1 ('Center'): align_horizontal = "center"
481
- Cell C1 ('Right'): align_horizontal = "right"
482
- ```
483
-
484
- <hr/>
485
-
486
- ## Align Horizontal Fill
487
-
488
- Demonstrates horizontal fill alignment (repeats value to fill cell width).
489
-
490
- ### Rendered Output (LibreOffice Calc)
491
-
492
- <div><img src="../../test/visual/baselines/align_horizontal_fill/page-1.png" width="100%" alt="Preview"/></div>
493
-
494
- ### DSL Code
495
-
496
- ```ruby
497
- # frozen_string_literal: true
498
-
499
- require "xlsxrb"
500
- output_path = ARGV[0] || "align_horizontal_fill.xlsx"
501
- Xlsxrb.write(output_path) do |wb|
502
- wb.style("fill_align") { |s| s.align_horizontal("fill") }
503
- wb.sheet("Alignment") do |s|
504
- s.column(0, width: 30)
505
- s.row(["X "], styles: { 0 => "fill_align" })
506
- end
507
- end
508
-
509
- # 2. Read the generated sheet and print the parsed alignments
510
- puts "=== Read Validation ==="
511
- workbook = Xlsxrb.read(output_path).load
512
- sheet = workbook.sheets.first
513
- row = sheet.rows.first
514
- row.cells.each do |c|
515
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
516
- align_h = xf&.dig(:alignment, :horizontal)
517
- align_v = xf&.dig(:alignment, :vertical)
518
- wrap = xf&.dig(:alignment, :wrap_text)
519
- indent = xf&.dig(:alignment, :indent)
520
- rot = xf&.dig(:alignment, :text_rotation)
521
- shrink = xf&.dig(:alignment, :shrink_to_fit)
522
- 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}"
523
- end
524
- ```
525
-
526
- ### Console Output
527
-
528
- ```text
529
- === Read Validation ===
530
- Cell A1 ('X '): align_h="fill", align_v=nil, wrap=nil, indent=nil, rotation=nil, shrink=nil
531
- ```
532
-
533
- <hr/>
534
-
535
- ## Align Horizontal Justify
536
-
537
- Demonstrates horizontal justify text alignment.
538
-
539
- ### Rendered Output (LibreOffice Calc)
540
-
541
- <div><img src="../../test/visual/baselines/align_horizontal_justify/page-1.png" width="100%" alt="Preview"/></div>
542
-
543
- ### DSL Code
544
-
545
- ```ruby
546
- # frozen_string_literal: true
547
-
548
- require "xlsxrb"
549
- output_path = ARGV[0] || "align_horizontal_justify.xlsx"
550
- Xlsxrb.write(output_path) do |wb|
551
- wb.style("justify_align") do |s|
552
- s.align_horizontal("justify")
553
- s.wrap_text(true)
554
- end
555
- wb.sheet("Alignment") do |s|
556
- s.column(0, width: 25)
557
- s.row(["Justified alignment wraps and distributes text evenly."], styles: { 0 => "justify_align" })
558
- end
559
- end
560
-
561
- # 2. Read the generated sheet and print the parsed alignments
562
- puts "=== Read Validation ==="
563
- workbook = Xlsxrb.read(output_path).load
564
- sheet = workbook.sheets.first
565
- row = sheet.rows.first
566
- row.cells.each do |c|
567
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
568
- align_h = xf&.dig(:alignment, :horizontal)
569
- align_v = xf&.dig(:alignment, :vertical)
570
- wrap = xf&.dig(:alignment, :wrap_text)
571
- indent = xf&.dig(:alignment, :indent)
572
- rot = xf&.dig(:alignment, :text_rotation)
573
- shrink = xf&.dig(:alignment, :shrink_to_fit)
574
- 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}"
575
- end
576
- ```
577
-
578
- ### Console Output
579
-
580
- ```text
581
- === Read Validation ===
582
- Cell A1 ('Justified alignment wraps and distributes text evenly.'): align_h="justify", align_v=nil, wrap=true, indent=nil, rotation=nil, shrink=nil
583
- ```
584
-
585
- <hr/>
586
-
587
- ## Align Indent
588
-
589
- Demonstrates text indentation inside cells.
590
-
591
- ### Rendered Output (LibreOffice Calc)
592
-
593
- <div><img src="../../test/visual/baselines/align_indent/page-1.png" width="100%" alt="Preview"/></div>
594
-
595
- ### DSL Code
596
-
597
- ```ruby
598
- # frozen_string_literal: true
599
-
600
- require "xlsxrb"
601
- output_path = ARGV[0] || "align_indent.xlsx"
602
- Xlsxrb.write(output_path) do |wb|
603
- wb.style("indent_1") { |s| s.align_horizontal("left").indent(1) }
604
- wb.style("indent_3") { |s| s.align_horizontal("left").indent(3) }
605
- wb.sheet("Indent") do |s|
606
- s.column(0, width: 25)
607
- s.column(1, width: 25)
608
- s.print_options(:grid_lines, true)
609
- s.row(["No Indent"])
610
- s.row(["Indent 1"], styles: { 0 => "indent_1" })
611
- s.row(["Indent 3"], styles: { 0 => "indent_3" })
612
- end
613
- end
614
-
615
- # 2. Read the generated sheet and print the parsed alignments
616
- puts "=== Read Validation ==="
617
- workbook = Xlsxrb.read(output_path).load
618
- sheet = workbook.sheets.first
619
- row = sheet.rows.first
620
- row.cells.each do |c|
621
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
622
- align_h = xf&.dig(:alignment, :horizontal)
623
- align_v = xf&.dig(:alignment, :vertical)
624
- wrap = xf&.dig(:alignment, :wrap_text)
625
- indent = xf&.dig(:alignment, :indent)
626
- rot = xf&.dig(:alignment, :text_rotation)
627
- shrink = xf&.dig(:alignment, :shrink_to_fit)
628
- 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}"
629
- end
630
- ```
631
-
632
- ### Console Output
633
-
634
- ```text
635
- === Read Validation ===
636
- Cell A1 ('No Indent'): align_h=nil, align_v=nil, wrap=nil, indent=nil, rotation=nil, shrink=nil
637
- ```
638
-
639
- <hr/>
640
-
641
- ## Align Text Rotation
642
-
643
- Demonstrates text rotated by specific angles (45, 90 degrees).
644
-
645
- ### Rendered Output (LibreOffice Calc)
646
-
647
- <div><img src="../../test/visual/baselines/align_text_rotation/page-1.png" width="100%" alt="Preview"/></div>
648
-
649
- ### DSL Code
650
-
651
- ```ruby
652
- # frozen_string_literal: true
653
-
654
- require "xlsxrb"
655
- output_path = ARGV[0] || "align_text_rotation.xlsx"
656
- Xlsxrb.write(output_path) do |wb|
657
- wb.style("rot_45") { |s| s.text_rotation(45) }
658
- wb.style("rot_90") { |s| s.text_rotation(90) }
659
- wb.sheet("Rotation") do |s|
660
- s.column(0, width: 25)
661
- s.column(1, width: 25)
662
- s.print_options(:grid_lines, true)
663
- s.row(["Rotated 45", "Rotated 90"], styles: { 0 => "rot_45", 1 => "rot_90" }, height: 50)
664
- end
665
- end
666
-
667
- # 2. Read the generated sheet and print the parsed alignments
668
- puts "=== Read Validation ==="
669
- workbook = Xlsxrb.read(output_path).load
670
- sheet = workbook.sheets.first
671
- row = sheet.rows.first
672
- row.cells.each do |c|
673
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
674
- align_h = xf&.dig(:alignment, :horizontal)
675
- align_v = xf&.dig(:alignment, :vertical)
676
- wrap = xf&.dig(:alignment, :wrap_text)
677
- indent = xf&.dig(:alignment, :indent)
678
- rot = xf&.dig(:alignment, :text_rotation)
679
- shrink = xf&.dig(:alignment, :shrink_to_fit)
680
- 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}"
681
- end
682
- ```
683
-
684
- ### Console Output
685
-
686
- ```text
687
- === Read Validation ===
688
- Cell A1 ('Rotated 45'): align_h=nil, align_v=nil, wrap=nil, indent=nil, rotation=45, shrink=nil
689
- Cell B1 ('Rotated 90'): align_h=nil, align_v=nil, wrap=nil, indent=nil, rotation=90, shrink=nil
690
- ```
691
-
692
- <hr/>
693
-
694
- ## Align Text Wrap
695
-
696
- Demonstrates auto-wrapping multi-line text inside narrow cells.
697
-
698
- ### Rendered Output (LibreOffice Calc)
699
-
700
- <div><img src="../../test/visual/baselines/align_text_wrap/page-1.png" width="100%" alt="Preview"/></div>
701
-
702
- ### DSL Code
703
-
704
- ```ruby
705
- # frozen_string_literal: true
706
-
707
- require "xlsxrb"
708
- output_path = ARGV[0] || "align_text_wrap.xlsx"
709
- Xlsxrb.write(output_path) do |wb|
710
- wb.style("wrap", &:wrap_text)
711
- wb.sheet("Text Wrap") do |s|
712
- s.print_options(:grid_lines, true)
713
- s.column(0, width: 15)
714
- s.row(["This is a long sentence that wraps inside the cell."], styles: { 0 => "wrap" })
715
- end
716
- end
717
-
718
- # 2. Read the generated sheet and print the parsed alignments
719
- puts "=== Read Validation ==="
720
- workbook = Xlsxrb.read(output_path).load
721
- sheet = workbook.sheets.first
722
- row = sheet.rows.first
723
- row.cells.each do |c|
724
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
725
- align_h = xf&.dig(:alignment, :horizontal)
726
- align_v = xf&.dig(:alignment, :vertical)
727
- wrap = xf&.dig(:alignment, :wrap_text)
728
- indent = xf&.dig(:alignment, :indent)
729
- rot = xf&.dig(:alignment, :text_rotation)
730
- shrink = xf&.dig(:alignment, :shrink_to_fit)
731
- 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}"
732
- end
733
- ```
734
-
735
- ### Console Output
736
-
737
- ```text
738
- === Read Validation ===
739
- Cell A1 ('This is a long sentence that wraps inside the cell.'): align_h=nil, align_v=nil, wrap=true, indent=nil, rotation=nil, shrink=nil
740
- ```
741
-
742
- <hr/>
743
-
744
- ## Align Vertical
745
-
746
- Demonstrates vertical text alignment (top, center, bottom).
747
-
748
- ### Rendered Output (LibreOffice Calc)
749
-
750
- <div><img src="../../test/visual/baselines/align_vertical/page-1.png" width="100%" alt="Preview"/></div>
751
-
752
- ### DSL Code
753
-
754
- ```ruby
755
- # frozen_string_literal: true
756
-
757
- require "xlsxrb"
758
- output_path = ARGV[0] || "align_vertical.xlsx"
759
- Xlsxrb.write(output_path) do |wb|
760
- wb.style("top") { |s| s.align_vertical("top") }
761
- wb.style("center") { |s| s.align_vertical("center") }
762
- wb.style("bottom") { |s| s.align_vertical("bottom") }
763
- wb.sheet("Vertical Alignment") do |s|
764
- s.column(0, width: 25)
765
- s.column(1, width: 25)
766
- s.print_options(:grid_lines, true)
767
- s.row(%w[Top Center Bottom], styles: { 0 => "top", 1 => "center", 2 => "bottom" }, height: 40)
768
- end
769
- end
770
-
771
- # 2. Read the generated sheet and print the parsed alignments
772
- puts "=== Read Validation ==="
773
- workbook = Xlsxrb.read(output_path).load
774
- sheet = workbook.sheets.first
775
- row = sheet.rows.first
776
- row.cells.each do |c|
777
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
778
- align_h = xf&.dig(:alignment, :horizontal)
779
- align_v = xf&.dig(:alignment, :vertical)
780
- wrap = xf&.dig(:alignment, :wrap_text)
781
- indent = xf&.dig(:alignment, :indent)
782
- rot = xf&.dig(:alignment, :text_rotation)
783
- shrink = xf&.dig(:alignment, :shrink_to_fit)
784
- 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}"
785
- end
786
- ```
787
-
788
- ### Console Output
789
-
790
- ```text
791
- === Read Validation ===
792
- Cell A1 ('Top'): align_h=nil, align_v="top", wrap=nil, indent=nil, rotation=nil, shrink=nil
793
- Cell B1 ('Center'): align_h=nil, align_v="center", wrap=nil, indent=nil, rotation=nil, shrink=nil
794
- Cell C1 ('Bottom'): align_h=nil, align_v="bottom", wrap=nil, indent=nil, rotation=nil, shrink=nil
795
- ```
796
-
797
- <hr/>
798
-
799
- ## Basic Data
800
-
801
- Demonstrates simple tabular data writing with basic Ruby types (Strings, Numbers, Dates, Booleans).
802
-
803
- ### Rendered Output (LibreOffice Calc)
804
-
805
- <div><img src="../../test/visual/baselines/basic_data/page-1.png" width="100%" alt="Preview"/></div>
806
-
807
- ### DSL Code
808
-
809
- ```ruby
810
- # frozen_string_literal: true
811
-
812
- require "xlsxrb"
813
- require "date"
814
-
815
- output_path = ARGV[0] || "basic_data.xlsx"
816
-
817
- Xlsxrb.write(output_path) do |wb|
818
- wb.style("currency") { |style| style.number_format("$#,##0.00") }
819
- wb.style("date") { |style| style.number_format("yyyy-mm-dd") }
820
- wb.sheet("Basic Data") do |sheet|
821
- sheet.sheet_properties(:fit_to_page, true)
822
- sheet.page_setup(fit_to_width: 1, fit_to_height: 1)
823
- sheet.column(0, width: 25)
824
- sheet.column(1, width: 25)
825
- sheet.row(%w[Product Qty Price Date Active])
826
- sheet.row(["Gadget A", 10, 99.99, Date.new(2026, 1, 15), true], styles: { 2 => "currency", 3 => "date" })
827
- sheet.row(["Widget B", 5, 49.50, Date.new(2026, 2, 20), false], styles: { 2 => "currency", 3 => "date" })
828
- end
829
- end
830
-
831
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
832
- puts "=== Read Validation ==="
833
- workbook = Xlsxrb.read(output_path).load
834
- sheet = workbook.sheets.first
835
- sheet.rows.each do |row|
836
- row_cells = row.cells.map do |c|
837
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
838
- end
839
- puts "Row #{row.index}: #{row_cells.join(", ")}"
840
- end
841
- ```
842
-
843
- ### Console Output
844
-
845
- ```text
846
- === Read Validation ===
847
- Row 0: A1: "Product" (String), B1: "Qty" (String), C1: "Price" (String), D1: "Date" (String), E1: "Active" (String)
848
- Row 1: A2: "Gadget A" (String), B2: 10 (Integer), C2: 99.99 (Float), D2: 46037 (Integer), E2: true (TrueClass)
849
- Row 2: A3: "Widget B" (String), B3: 5 (Integer), C3: 49.5 (Float), D3: 46073 (Integer), E3: false (FalseClass)
850
- ```
851
-
852
- <hr/>
853
-
854
- ## Borders
855
-
856
- Demonstrates border styles (thin, medium, thick, hair, dashed, medium dashed, dotted, double, dash-dot, medium dash-dot, dash-dot-dot, slanted, and diagonal cross borders) applied to cell ranges.
857
-
858
- ### Rendered Output (LibreOffice Calc)
859
-
860
- <div><img src="../../test/visual/baselines/borders/page-1.png" width="100%" alt="Preview"/></div>
861
-
862
- ### DSL Code
863
-
864
- ```ruby
865
- # frozen_string_literal: true
866
-
867
- require "xlsxrb"
868
-
869
- output_path = ARGV[0] || "borders.xlsx"
870
-
871
- Xlsxrb.write(output_path) do |wb|
872
- wb.style("thin") { |s| s.border_all(style: "thin", color: "FF000000") }
873
- wb.style("medium") { |s| s.border_all(style: "medium", color: "FF000000") }
874
- wb.style("thick") { |s| s.border_all(style: "thick", color: "FF000000") }
875
- wb.style("hair") { |s| s.border_all(style: "hair", color: "FF000000") }
876
- wb.style("dashed") { |s| s.border_all(style: "dashed", color: "FF000000") }
877
- wb.style("medium_dashed") { |s| s.border_all(style: "mediumDashed", color: "FF000000") }
878
- wb.style("dotted") { |s| s.border_all(style: "dotted", color: "FF000000") }
879
- wb.style("double") { |s| s.border_all(style: "double", color: "FF000000") }
880
- wb.style("dash_dot") { |s| s.border_all(style: "dashDot", color: "FF000000") }
881
- wb.style("medium_dash_dot") { |s| s.border_all(style: "mediumDashDot", color: "FF000000") }
882
- wb.style("dash_dot_dot") { |s| s.border_all(style: "dashDotDot", color: "FF000000") }
883
- wb.style("slanted") { |s| s.border_all(style: "slantedDashDot", color: "FF000000") }
884
- wb.style("diagonal") { |s| s.border_diagonal(style: "thin", color: "FF000000", up: true, down: true) }
885
-
886
- wb.sheet("Borders") do |s|
887
- s.column(0, width: 25)
888
- s.column(1, width: 25)
889
- s.print_options(:grid_lines, true)
890
-
891
- s.row(["Border Style", "Cell Preview"])
892
- s.row(["Thin", "Thin Border"], styles: { 1 => "thin" })
893
- s.row(["Medium", "Medium Border"], styles: { 1 => "medium" })
894
- s.row(["Thick", "Thick Border"], styles: { 1 => "thick" })
895
- s.row(["Hair", "Hair Border"], styles: { 1 => "hair" })
896
- s.row(["Dashed", "Dashed Border"], styles: { 1 => "dashed" })
897
- s.row(["Medium Dashed", "Medium Dashed"], styles: { 1 => "medium_dashed" })
898
- s.row(["Dotted", "Dotted Border"], styles: { 1 => "dotted" })
899
- s.row(["Double", "Double Border"], styles: { 1 => "double" })
900
- s.row(["Dash-Dot", "Dash-Dot Border"], styles: { 1 => "dash_dot" })
901
- s.row(["Medium Dash-Dot", "Medium Dash-Dot"], styles: { 1 => "medium_dash_dot" })
902
- s.row(%w[Dash-Dot-Dot Dash-Dot-Dot], styles: { 1 => "dash_dot_dot" })
903
- s.row(["Slanted Dash-Dot", "Slanted Border"], styles: { 1 => "slanted" })
904
- s.row(["Diagonal (Cross)", "Diagonal Border"], styles: { 1 => "diagonal" })
905
- end
906
- end
907
-
908
- # Read check
909
- puts "=== Read Validation ==="
910
- workbook = Xlsxrb.read(output_path).load
911
- sheet = workbook.sheets.first
912
- sheet.rows.each do |row|
913
- row_cells = row.cells.map do |c|
914
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
915
- border_id = xf ? xf[:border_id] : 0
916
- "#{c.ref}: #{c.value.inspect} (border_id: #{border_id})"
917
- end
918
- puts "Row #{row.index}: #{row_cells.join(", ")}"
919
- end
920
- ```
921
-
922
- ### Console Output
923
-
924
- ```text
925
- === Read Validation ===
926
- Row 0: A1: "Border Style" (border_id: 0), B1: "Cell Preview" (border_id: 0)
927
- Row 1: A2: "Thin" (border_id: 0), B2: "Thin Border" (border_id: 1)
928
- Row 2: A3: "Medium" (border_id: 0), B3: "Medium Border" (border_id: 2)
929
- Row 3: A4: "Thick" (border_id: 0), B4: "Thick Border" (border_id: 3)
930
- Row 4: A5: "Hair" (border_id: 0), B5: "Hair Border" (border_id: 4)
931
- Row 5: A6: "Dashed" (border_id: 0), B6: "Dashed Border" (border_id: 5)
932
- Row 6: A7: "Medium Dashed" (border_id: 0), B7: "Medium Dashed" (border_id: 6)
933
- Row 7: A8: "Dotted" (border_id: 0), B8: "Dotted Border" (border_id: 7)
934
- Row 8: A9: "Double" (border_id: 0), B9: "Double Border" (border_id: 8)
935
- Row 9: A10: "Dash-Dot" (border_id: 0), B10: "Dash-Dot Border" (border_id: 9)
936
- Row 10: A11: "Medium Dash-Dot" (border_id: 0), B11: "Medium Dash-Dot" (border_id: 10)
937
- Row 11: A12: "Dash-Dot-Dot" (border_id: 0), B12: "Dash-Dot-Dot" (border_id: 11)
938
- Row 12: A13: "Slanted Dash-Dot" (border_id: 0), B13: "Slanted Border" (border_id: 12)
939
- Row 13: A14: "Diagonal (Cross)" (border_id: 0), B14: "Diagonal Border" (border_id: 13)
940
- ```
941
-
942
- <hr/>
943
-
944
- ## Cell Booleans
945
-
946
- Demonstrates boolean values serialized and rendered.
947
-
948
- ### Rendered Output (LibreOffice Calc)
949
-
950
- <div><img src="../../test/visual/baselines/cell_booleans/page-1.png" width="100%" alt="Preview"/></div>
951
-
952
- ### DSL Code
953
-
954
- ```ruby
955
- # frozen_string_literal: true
956
-
957
- require "xlsxrb"
958
- output_path = ARGV[0] || "cell_booleans.xlsx"
959
- Xlsxrb.write(output_path) do |wb|
960
- wb.sheet("Booleans") do |s|
961
- s.column(0, width: 25)
962
- s.column(1, width: 25)
963
- s.row(["Label", "Boolean Value"])
964
- s.row(["Is Active", true])
965
- s.row(["Is Pending", false])
966
- end
967
- end
968
-
969
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
970
- puts "=== Read Validation ==="
971
- workbook = Xlsxrb.read(output_path).load
972
- sheet = workbook.sheets.first
973
- sheet.rows.each do |row|
974
- row_cells = row.cells.map do |c|
975
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
976
- end
977
- puts "Row #{row.index}: #{row_cells.join(", ")}"
978
- end
979
- ```
980
-
981
- ### Console Output
982
-
983
- ```text
984
- === Read Validation ===
985
- Row 0: A1: "Label" (String), B1: "Boolean Value" (String)
986
- Row 1: A2: "Is Active" (String), B2: true (TrueClass)
987
- Row 2: A3: "Is Pending" (String), B3: false (FalseClass)
988
- ```
989
-
990
- <hr/>
991
-
992
- ## Cell Dates
993
-
994
- Demonstrates dates serialized natively and formatted with standard or custom format strings.
995
-
996
- ### Rendered Output (LibreOffice Calc)
997
-
998
- <div><img src="../../test/visual/baselines/cell_dates/page-1.png" width="100%" alt="Preview"/></div>
999
-
1000
- ### DSL Code
1001
-
1002
- ```ruby
1003
- # frozen_string_literal: true
1004
-
1005
- require "xlsxrb"
1006
- require "date"
1007
- output_path = ARGV[0] || "cell_dates.xlsx"
1008
- Xlsxrb.write(output_path) do |wb|
1009
- wb.style("custom_date") { |s| s.num_fmt("yyyy-mm-dd") }
1010
- wb.sheet("Dates") do |s|
1011
- s.column(0, width: 25)
1012
- s.column(1, width: 25)
1013
- s.row(["Format", "Date Value"])
1014
- s.row(["Default Date", Date.new(2026, 7, 1)])
1015
- s.row(["Formatted Date", Date.new(2026, 12, 25)], styles: { 1 => "custom_date" })
1016
- end
1017
- end
1018
-
1019
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
1020
- puts "=== Read Validation ==="
1021
- workbook = Xlsxrb.read(output_path).load
1022
- sheet = workbook.sheets.first
1023
- sheet.rows.each do |row|
1024
- row_cells = row.cells.map do |c|
1025
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1026
- end
1027
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1028
- end
1029
- ```
1030
-
1031
- ### Console Output
1032
-
1033
- ```text
1034
- === Read Validation ===
1035
- Row 0: A1: "Format" (String), B1: "Date Value" (String)
1036
- Row 1: A2: "Default Date" (String), B2: 46204 (Integer)
1037
- Row 2: A3: "Formatted Date" (String), B3: 46381 (Integer)
1038
- ```
1039
-
1040
- <hr/>
1041
-
1042
- ## Cell Formulas
1043
-
1044
- Demonstrates standard spreadsheet calculations and formulas (SUM, AVERAGE).
1045
-
1046
- ### Rendered Output (LibreOffice Calc)
1047
-
1048
- <div><img src="../../test/visual/baselines/cell_formulas/page-1.png" width="100%" alt="Preview"/></div>
1049
-
1050
- ### DSL Code
1051
-
1052
- ```ruby
1053
- # frozen_string_literal: true
1054
-
1055
- require "xlsxrb"
1056
- output_path = ARGV[0] || "cell_formulas.xlsx"
1057
- Xlsxrb.write(output_path) do |wb|
1058
- wb.sheet("Formulas") do |s|
1059
- s.column(0, width: 25)
1060
- s.column(1, width: 25)
1061
- s.row(%w[Item Value])
1062
- s.row(["A", 10])
1063
- s.row(["B", 20])
1064
- s.row(["SUM", Xlsxrb::Elements::Formula.new(expression: "SUM(B2:B3)", cached_value: 30)])
1065
- s.row(["AVERAGE", Xlsxrb::Elements::Formula.new(expression: "AVERAGE(B2:B3)", cached_value: 15)])
1066
- end
1067
- end
1068
-
1069
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
1070
- puts "=== Read Validation ==="
1071
- workbook = Xlsxrb.read(output_path).load
1072
- sheet = workbook.sheets.first
1073
- sheet.rows.each do |row|
1074
- row_cells = row.cells.map do |c|
1075
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1076
- end
1077
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1078
- end
1079
- ```
1080
-
1081
- ### Console Output
1082
-
1083
- ```text
1084
- === Read Validation ===
1085
- Row 0: A1: "Item" (String), B1: "Value" (String)
1086
- Row 1: A2: "A" (String), B2: 10 (Integer)
1087
- Row 2: A3: "B" (String), B3: 20 (Integer)
1088
- Row 3: A4: "SUM" (String), B4: 30 (Integer)
1089
- Row 4: A5: "AVERAGE" (String), B5: 15 (Integer)
1090
- ```
1091
-
1092
- <hr/>
1093
-
1094
- ## Cell Num Currency Jpy
1095
-
1096
- Demonstrates Yen Currency format code formatting.
1097
-
1098
- ### Rendered Output (LibreOffice Calc)
1099
-
1100
- <div><img src="../../test/visual/baselines/cell_num_currency_jpy/page-1.png" width="100%" alt="Preview"/></div>
1101
-
1102
- ### DSL Code
1103
-
1104
- ```ruby
1105
- # frozen_string_literal: true
1106
-
1107
- require "xlsxrb"
1108
- output_path = ARGV[0] || "cell_num_currency_jpy.xlsx"
1109
- Xlsxrb.write(output_path) do |wb|
1110
- wb.style("jpy") { |s| s.num_fmt("¥#,##0;[Red]¥-#,##0") }
1111
- wb.sheet("JPY Currency") do |s|
1112
- s.column(0, width: 25)
1113
- s.column(1, width: 25)
1114
- s.row(%w[Format Value])
1115
- s.row(["Positive Yen", 12_500], styles: { 1 => "jpy" })
1116
- s.row(["Negative Yen", -8000], styles: { 1 => "jpy" })
1117
- end
1118
- end
1119
-
1120
- # 2. Read the generated sheet and print parsed cell numbers and format codes
1121
- puts "=== Read Validation ==="
1122
- workbook = Xlsxrb.read(output_path).load
1123
- sheet = workbook.sheets.first
1124
- sheet.rows.each do |row|
1125
- row_cells = row.cells.map do |c|
1126
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
1127
- num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1128
- "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1129
- end
1130
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1131
- end
1132
- ```
1133
-
1134
- ### Console Output
1135
-
1136
- ```text
1137
- === Read Validation ===
1138
- Row 0: A1: "Format" (Format ID: , Code: nil), B1: "Value" (Format ID: , Code: nil)
1139
- Row 1: A2: "Positive Yen" (Format ID: , Code: nil), B2: 12500 (Format ID: 166, Code: "¥#,##0;[Red]¥-#,##0")
1140
- Row 2: A3: "Negative Yen" (Format ID: , Code: nil), B3: -8000 (Format ID: 166, Code: "¥#,##0;[Red]¥-#,##0")
1141
- ```
1142
-
1143
- <hr/>
1144
-
1145
- ## Cell Num Custom Colors
1146
-
1147
- Demonstrates custom colored formats for positive and negative numbers.
1148
-
1149
- ### Rendered Output (LibreOffice Calc)
1150
-
1151
- <div><img src="../../test/visual/baselines/cell_num_custom_colors/page-1.png" width="100%" alt="Preview"/></div>
1152
-
1153
- ### DSL Code
1154
-
1155
- ```ruby
1156
- # frozen_string_literal: true
1157
-
1158
- require "xlsxrb"
1159
- output_path = ARGV[0] || "cell_num_custom_colors.xlsx"
1160
- Xlsxrb.write(output_path) do |wb|
1161
- wb.style("custom_color") { |s| s.num_fmt("[Green]#,##0;[Red]-#,##0") }
1162
- wb.sheet("Custom Colors") do |s|
1163
- s.column(0, width: 25)
1164
- s.column(1, width: 25)
1165
- s.row(%w[Format Value])
1166
- s.row(["Positive (Green)", 5000], styles: { 1 => "custom_color" })
1167
- s.row(["Negative (Red)", -2500], styles: { 1 => "custom_color" })
1168
- end
1169
- end
1170
-
1171
- # 2. Read the generated sheet and print parsed cell numbers and format codes
1172
- puts "=== Read Validation ==="
1173
- workbook = Xlsxrb.read(output_path).load
1174
- sheet = workbook.sheets.first
1175
- sheet.rows.each do |row|
1176
- row_cells = row.cells.map do |c|
1177
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
1178
- num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1179
- "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1180
- end
1181
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1182
- end
1183
- ```
1184
-
1185
- ### Console Output
1186
-
1187
- ```text
1188
- === Read Validation ===
1189
- Row 0: A1: "Format" (Format ID: , Code: nil), B1: "Value" (Format ID: , Code: nil)
1190
- Row 1: A2: "Positive (Green)" (Format ID: , Code: nil), B2: 5000 (Format ID: 166, Code: "[Green]#,##0;[Red]-#,##0")
1191
- Row 2: A3: "Negative (Red)" (Format ID: , Code: nil), B3: -2500 (Format ID: 166, Code: "[Green]#,##0;[Red]-#,##0")
1192
- ```
1193
-
1194
- <hr/>
1195
-
1196
- ## Cell Num Fractions
1197
-
1198
- Demonstrates fraction number formats (# ?/?).
1199
-
1200
- ### Rendered Output (LibreOffice Calc)
1201
-
1202
- <div><img src="../../test/visual/baselines/cell_num_fractions/page-1.png" width="100%" alt="Preview"/></div>
1203
-
1204
- ### DSL Code
1205
-
1206
- ```ruby
1207
- # frozen_string_literal: true
1208
-
1209
- require "xlsxrb"
1210
- output_path = ARGV[0] || "cell_num_fractions.xlsx"
1211
- Xlsxrb.write(output_path) do |wb|
1212
- wb.style("frac") { |s| s.num_fmt("# ?/?") }
1213
- wb.sheet("Fractions") do |s|
1214
- s.column(0, width: 25)
1215
- s.column(1, width: 25)
1216
- s.row(%w[Format Value])
1217
- s.row(["Half", 0.5], styles: { 1 => "frac" })
1218
- s.row(["Third", 0.3333], styles: { 1 => "frac" })
1219
- s.row(["Quarter", 0.75], styles: { 1 => "frac" })
1220
- end
1221
- end
1222
-
1223
- # 2. Read the generated sheet and print parsed cell numbers and format codes
1224
- puts "=== Read Validation ==="
1225
- workbook = Xlsxrb.read(output_path).load
1226
- sheet = workbook.sheets.first
1227
- sheet.rows.each do |row|
1228
- row_cells = row.cells.map do |c|
1229
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
1230
- num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1231
- "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1232
- end
1233
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1234
- end
1235
- ```
1236
-
1237
- ### Console Output
1238
-
1239
- ```text
1240
- === Read Validation ===
1241
- Row 0: A1: "Format" (Format ID: , Code: nil), B1: "Value" (Format ID: , Code: nil)
1242
- Row 1: A2: "Half" (Format ID: , Code: nil), B2: 0.5 (Format ID: 166, Code: "# ?/?")
1243
- Row 2: A3: "Third" (Format ID: , Code: nil), B3: 0.3333 (Format ID: 166, Code: "# ?/?")
1244
- Row 3: A4: "Quarter" (Format ID: , Code: nil), B4: 0.75 (Format ID: 166, Code: "# ?/?")
1245
- ```
1246
-
1247
- <hr/>
1248
-
1249
- ## Cell Num Percent Decimals
1250
-
1251
- Demonstrates percentages with two decimal places (0.00%).
1252
-
1253
- ### Rendered Output (LibreOffice Calc)
1254
-
1255
- <div><img src="../../test/visual/baselines/cell_num_percent_decimals/page-1.png" width="100%" alt="Preview"/></div>
1256
-
1257
- ### DSL Code
1258
-
1259
- ```ruby
1260
- # frozen_string_literal: true
1261
-
1262
- require "xlsxrb"
1263
- output_path = ARGV[0] || "cell_num_percent_decimals.xlsx"
1264
- Xlsxrb.write(output_path) do |wb|
1265
- wb.style("pct2") { |s| s.num_fmt("0.00%") }
1266
- wb.sheet("Percents") do |s|
1267
- s.column(0, width: 25)
1268
- s.column(1, width: 25)
1269
- s.row(%w[Format Value])
1270
- s.row(["Percent with 2 Decimals", 0.12345], styles: { 1 => "pct2" })
1271
- end
1272
- end
1273
-
1274
- # 2. Read the generated sheet and print parsed cell numbers and format codes
1275
- puts "=== Read Validation ==="
1276
- workbook = Xlsxrb.read(output_path).load
1277
- sheet = workbook.sheets.first
1278
- sheet.rows.each do |row|
1279
- row_cells = row.cells.map do |c|
1280
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
1281
- num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1282
- "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1283
- end
1284
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1285
- end
1286
- ```
1287
-
1288
- ### Console Output
1289
-
1290
- ```text
1291
- === Read Validation ===
1292
- Row 0: A1: "Format" (Format ID: , Code: nil), B1: "Value" (Format ID: , Code: nil)
1293
- Row 1: A2: "Percent with 2 Decimals" (Format ID: , Code: nil), B2: 0.12345 (Format ID: 166, Code: "0.00%")
1294
- ```
1295
-
1296
- <hr/>
1297
-
1298
- ## Cell Num Scientific
1299
-
1300
- Demonstrates scientific number formats (0.00E+00).
1301
-
1302
- ### Rendered Output (LibreOffice Calc)
1303
-
1304
- <div><img src="../../test/visual/baselines/cell_num_scientific/page-1.png" width="100%" alt="Preview"/></div>
1305
-
1306
- ### DSL Code
1307
-
1308
- ```ruby
1309
- # frozen_string_literal: true
1310
-
1311
- require "xlsxrb"
1312
- output_path = ARGV[0] || "cell_num_scientific.xlsx"
1313
- Xlsxrb.write(output_path) do |wb|
1314
- wb.style("sci") { |s| s.num_fmt("0.00E+00") }
1315
- wb.sheet("Scientific") do |s|
1316
- s.column(0, width: 25)
1317
- s.column(1, width: 25)
1318
- s.row(%w[Format Value])
1319
- s.row(["Scientific", 123_456_789.0], styles: { 1 => "sci" })
1320
- s.row(["Small Scientific", 0.00001234], styles: { 1 => "sci" })
1321
- end
1322
- end
1323
-
1324
- # 2. Read the generated sheet and print parsed cell numbers and format codes
1325
- puts "=== Read Validation ==="
1326
- workbook = Xlsxrb.read(output_path).load
1327
- sheet = workbook.sheets.first
1328
- sheet.rows.each do |row|
1329
- row_cells = row.cells.map do |c|
1330
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
1331
- num_fmt = xf ? workbook.styles[:num_fmts][xf[:num_fmt_id]] : nil
1332
- "#{c.ref}: #{c.value.inspect} (Format ID: #{xf&.[](:num_fmt_id)}, Code: #{num_fmt.inspect})"
1333
- end
1334
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1335
- end
1336
- ```
1337
-
1338
- ### Console Output
1339
-
1340
- ```text
1341
- === Read Validation ===
1342
- Row 0: A1: "Format" (Format ID: , Code: nil), B1: "Value" (Format ID: , Code: nil)
1343
- Row 1: A2: "Scientific" (Format ID: , Code: nil), B2: 123456789.0 (Format ID: 166, Code: "0.00E+00")
1344
- Row 2: A3: "Small Scientific" (Format ID: , Code: nil), B3: 1.234e-05 (Format ID: 166, Code: "0.00E+00")
1345
- ```
1346
-
1347
- <hr/>
1348
-
1349
- ## Cell Numbers
1350
-
1351
- Demonstrates custom formatting for integers, floating point numbers, currencies, and percentages.
1352
-
1353
- ### Rendered Output (LibreOffice Calc)
1354
-
1355
- <div><img src="../../test/visual/baselines/cell_numbers/page-1.png" width="100%" alt="Preview"/></div>
1356
-
1357
- ### DSL Code
1358
-
1359
- ```ruby
1360
- # frozen_string_literal: true
1361
-
1362
- require "xlsxrb"
1363
- output_path = ARGV[0] || "cell_numbers.xlsx"
1364
- Xlsxrb.write(output_path) do |wb|
1365
- wb.style("currency") { |s| s.num_fmt("$#,##0.00") }
1366
- wb.style("percent") { |s| s.num_fmt("0.0%") }
1367
- wb.sheet("Numbers") do |s|
1368
- s.column(0, width: 25)
1369
- s.column(1, width: 25)
1370
- s.row(%w[Format Value])
1371
- s.row(["Integer", 12_345])
1372
- s.row(["Float", 123.456])
1373
- s.row(["Currency", 1234.5], styles: { 1 => "currency" })
1374
- s.row(["Percentage", 0.85], styles: { 1 => "percent" })
1375
- end
1376
- end
1377
-
1378
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
1379
- puts "=== Read Validation ==="
1380
- workbook = Xlsxrb.read(output_path).load
1381
- sheet = workbook.sheets.first
1382
- sheet.rows.each do |row|
1383
- row_cells = row.cells.map do |c|
1384
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1385
- end
1386
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1387
- end
1388
- ```
1389
-
1390
- ### Console Output
1391
-
1392
- ```text
1393
- === Read Validation ===
1394
- Row 0: A1: "Format" (String), B1: "Value" (String)
1395
- Row 1: A2: "Integer" (String), B2: 12345 (Integer)
1396
- Row 2: A3: "Float" (String), B3: 123.456 (Float)
1397
- Row 3: A4: "Currency" (String), B4: 1234.5 (Float)
1398
- Row 4: A5: "Percentage" (String), B5: 0.85 (Float)
1399
- ```
1400
-
1401
- <hr/>
1402
-
1403
- ## Cell Rich Text
1404
-
1405
- Demonstrates Rich Text cells with multiple font weights, styles, and colors in a single cell.
1406
-
1407
- ### Rendered Output (LibreOffice Calc)
1408
-
1409
- <div><img src="../../test/visual/baselines/cell_rich_text/page-1.png" width="100%" alt="Preview"/></div>
1410
-
1411
- ### DSL Code
1412
-
1413
- ```ruby
1414
- # frozen_string_literal: true
1415
-
1416
- require "xlsxrb"
1417
- output_path = ARGV[0] || "cell_rich_text.xlsx"
1418
- Xlsxrb.write(output_path) do |wb|
1419
- rt = Xlsxrb.rich_text(
1420
- { text: "Normal " },
1421
- { text: "BOLD RED ", font: { bold: true, color: "FFC00000", sz: 16 } },
1422
- { text: "ITALIC BLUE", font: { italic: true, color: :blue, sz: 20 } }
1423
- )
1424
- wb.sheet("Rich Text") do |s|
1425
- s.column(0, width: 25)
1426
- s.column(1, width: 25)
1427
- s.row(%w[Format Value])
1428
- s.row(["Rich Text Cell", rt])
1429
- end
1430
- end
1431
-
1432
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
1433
- puts "=== Read Validation ==="
1434
- workbook = Xlsxrb.read(output_path).load
1435
- sheet = workbook.sheets.first
1436
- sheet.rows.each do |row|
1437
- row_cells = row.cells.map do |c|
1438
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1439
- end
1440
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1441
- end
1442
- ```
1443
-
1444
- ### Console Output
1445
-
1446
- ```text
1447
- === Read Validation ===
1448
- Row 0: A1: "Format" (String), B1: "Value" (String)
1449
- Row 1: A2: "Rich Text Cell" (String), B2: "Normal BOLD RED ITALIC BLUE" (String)
1450
- ```
1451
-
1452
- <hr/>
1453
-
1454
- ## Cell Times
1455
-
1456
- Demonstrates timestamp values serialized natively and formatted showing hours, minutes, and seconds.
1457
-
1458
- ### Rendered Output (LibreOffice Calc)
1459
-
1460
- <div><img src="../../test/visual/baselines/cell_times/page-1.png" width="100%" alt="Preview"/></div>
1461
-
1462
- ### DSL Code
1463
-
1464
- ```ruby
1465
- # frozen_string_literal: true
1466
-
1467
- require "xlsxrb"
1468
- require "time"
1469
- output_path = ARGV[0] || "cell_times.xlsx"
1470
- Xlsxrb.write(output_path) do |wb|
1471
- wb.style("time_fmt") { |s| s.num_fmt("hh:mm:ss") }
1472
- wb.sheet("Times") do |s|
1473
- s.column(0, width: 25)
1474
- s.column(1, width: 25)
1475
- s.row(["Format", "Time Value"])
1476
- s.row(["DateTime", Time.new(2026, 7, 1, 12, 34, 56)])
1477
- s.row(["Time Only", Time.new(2026, 7, 1, 9, 15, 0)], styles: { 1 => "time_fmt" })
1478
- end
1479
- end
1480
-
1481
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
1482
- puts "=== Read Validation ==="
1483
- workbook = Xlsxrb.read(output_path).load
1484
- sheet = workbook.sheets.first
1485
- sheet.rows.each do |row|
1486
- row_cells = row.cells.map do |c|
1487
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
1488
- end
1489
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1490
- end
1491
- ```
1492
-
1493
- ### Console Output
1494
-
1495
- ```text
1496
- === Read Validation ===
1497
- Row 0: A1: "Format" (String), B1: "Time Value" (String)
1498
- Row 1: A2: "DateTime" (String), B2: 46204.52425925926 (Float)
1499
- Row 2: A3: "Time Only" (String), B3: 46204.385416666664 (Float)
1500
- ```
1501
-
1502
- <hr/>
1503
-
1504
- ## Cf Begins With
1505
-
1506
- Demonstrates conditional formatting highlighting cells starting with specific text.
1507
-
1508
- ### Rendered Output (LibreOffice Calc)
1509
-
1510
- <div><img src="../../test/visual/baselines/cf_begins_with/page-1.png" width="100%" alt="Preview"/></div>
1511
-
1512
- ### DSL Code
1513
-
1514
- ```ruby
1515
- # frozen_string_literal: true
1516
-
1517
- require "xlsxrb"
1518
- output_path = ARGV[0] || "cf_begins_with.xlsx"
1519
- Xlsxrb.write(output_path) do |wb|
1520
- wb.sheet("CF Begins") do |s|
1521
- s.column(0, width: 25)
1522
- s.column(1, width: 25)
1523
- s.row(["Code"])
1524
- s.row(["A-100"])
1525
- s.row(["B-200"])
1526
- s.row(["A-300"])
1527
- s.conditional_format("A2:A4", type: "beginsWith", operator: "beginsWith", text: "A", formula: 'LEFT(A2,1)="A"', fill_color: "FFFFC7CE")
1528
- end
1529
- end
1530
-
1531
- # 2. Read the generated sheet and print cell values
1532
- puts "=== Read Validation ==="
1533
- workbook = Xlsxrb.read(output_path).load
1534
- sheet = workbook.sheets.first
1535
- sheet.rows.first(5).each do |row|
1536
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1537
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1538
- end
1539
- ```
1540
-
1541
- ### Console Output
1542
-
1543
- ```text
1544
- === Read Validation ===
1545
- Row 0: A1: "Code"
1546
- Row 1: A2: "A-100"
1547
- Row 2: A3: "B-200"
1548
- Row 3: A4: "A-300"
1549
- ```
1550
-
1551
- <hr/>
1552
-
1553
- ## Cf Cell Between
1554
-
1555
- Demonstrates conditional formatting highlighting cells within a range.
1556
-
1557
- ### Rendered Output (LibreOffice Calc)
1558
-
1559
- <div><img src="../../test/visual/baselines/cf_cell_between/page-1.png" width="100%" alt="Preview"/></div>
1560
-
1561
- ### DSL Code
1562
-
1563
- ```ruby
1564
- # frozen_string_literal: true
1565
-
1566
- require "xlsxrb"
1567
- output_path = ARGV[0] || "cf_cell_between.xlsx"
1568
- Xlsxrb.write(output_path) do |wb|
1569
- wb.style("center") { |style| style.align_horizontal("center") }
1570
- wb.sheet("CF Between") do |s|
1571
- s.column(0, width: 25)
1572
- s.column(1, width: 25)
1573
- s.row(["Values"])
1574
- s.row([15], styles: "center")
1575
- s.row([25], styles: "center")
1576
- s.row([5], styles: "center")
1577
- s.conditional_format("A2:A4", type: "cellIs", operator: "between", formulas: %w[10 20], fill_color: :green)
1578
- end
1579
- end
1580
-
1581
- # 2. Read the generated sheet and print cell values
1582
- puts "=== Read Validation ==="
1583
- workbook = Xlsxrb.read(output_path).load
1584
- sheet = workbook.sheets.first
1585
- sheet.rows.first(5).each do |row|
1586
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1587
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1588
- end
1589
- ```
1590
-
1591
- ### Console Output
1592
-
1593
- ```text
1594
- === Read Validation ===
1595
- Row 0: A1: "Values"
1596
- Row 1: A2: 15
1597
- Row 2: A3: 25
1598
- Row 3: A4: 5
1599
- ```
1600
-
1601
- <hr/>
1602
-
1603
- ## Cf Cell Equal To
1604
-
1605
- Demonstrates conditional formatting highlighting cells equal to a target value.
1606
-
1607
- ### Rendered Output (LibreOffice Calc)
1608
-
1609
- <div><img src="../../test/visual/baselines/cf_cell_equal_to/page-1.png" width="100%" alt="Preview"/></div>
1610
-
1611
- ### DSL Code
1612
-
1613
- ```ruby
1614
- # frozen_string_literal: true
1615
-
1616
- require "xlsxrb"
1617
- output_path = ARGV[0] || "cf_cell_equal_to.xlsx"
1618
- Xlsxrb.write(output_path) do |wb|
1619
- wb.style("center") { |style| style.align_horizontal("center") }
1620
- wb.sheet("CF Equal") do |s|
1621
- s.column(0, width: 25)
1622
- s.column(1, width: 25)
1623
- s.row(["Values"])
1624
- s.row([10], styles: "center")
1625
- s.row([20], styles: "center")
1626
- s.row([10], styles: "center")
1627
- s.conditional_format("A2:A4", type: "cellIs", operator: "equal", formula: "10", fill_color: "FFFFC7CE")
1628
- end
1629
- end
1630
-
1631
- # 2. Read the generated sheet and print cell values
1632
- puts "=== Read Validation ==="
1633
- workbook = Xlsxrb.read(output_path).load
1634
- sheet = workbook.sheets.first
1635
- sheet.rows.first(5).each do |row|
1636
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1637
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1638
- end
1639
- ```
1640
-
1641
- ### Console Output
1642
-
1643
- ```text
1644
- === Read Validation ===
1645
- Row 0: A1: "Values"
1646
- Row 1: A2: 10
1647
- Row 2: A3: 20
1648
- Row 3: A4: 10
1649
- ```
1650
-
1651
- <hr/>
1652
-
1653
- ## Cf Cell Greater Equal
1654
-
1655
- Demonstrates conditional formatting highlighting cells greater than or equal to a threshold.
1656
-
1657
- ### Rendered Output (LibreOffice Calc)
1658
-
1659
- <div><img src="../../test/visual/baselines/cf_cell_greater_equal/page-1.png" width="100%" alt="Preview"/></div>
1660
-
1661
- ### DSL Code
1662
-
1663
- ```ruby
1664
- # frozen_string_literal: true
1665
-
1666
- require "xlsxrb"
1667
- output_path = ARGV[0] || "cf_cell_greater_equal.xlsx"
1668
- Xlsxrb.write(output_path) do |wb|
1669
- wb.style("center") { |style| style.align_horizontal("center") }
1670
- wb.sheet("CF Greater Equal") do |s|
1671
- s.column(0, width: 25)
1672
- s.column(1, width: 25)
1673
- s.row(["Values"])
1674
- s.row([10], styles: "center")
1675
- s.row([50], styles: "center")
1676
- s.row([100], styles: "center")
1677
- s.conditional_format("A2:A4", type: "cellIs", operator: "greaterThanOrEqual", formula: "50", fill_color: "FFFFC7CE")
1678
- end
1679
- end
1680
-
1681
- # 2. Read the generated sheet and print cell values
1682
- puts "=== Read Validation ==="
1683
- workbook = Xlsxrb.read(output_path).load
1684
- sheet = workbook.sheets.first
1685
- sheet.rows.first(5).each do |row|
1686
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1687
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1688
- end
1689
- ```
1690
-
1691
- ### Console Output
1692
-
1693
- ```text
1694
- === Read Validation ===
1695
- Row 0: A1: "Values"
1696
- Row 1: A2: 10
1697
- Row 2: A3: 50
1698
- Row 3: A4: 100
1699
- ```
1700
-
1701
- <hr/>
1702
-
1703
- ## Cf Cell Greater Than
1704
-
1705
- Demonstrates conditional formatting highlighting cells greater than a threshold.
1706
-
1707
- ### Rendered Output (LibreOffice Calc)
1708
-
1709
- <div><img src="../../test/visual/baselines/cf_cell_greater_than/page-1.png" width="100%" alt="Preview"/></div>
1710
-
1711
- ### DSL Code
1712
-
1713
- ```ruby
1714
- # frozen_string_literal: true
1715
-
1716
- require "xlsxrb"
1717
- output_path = ARGV[0] || "cf_cell_greater_than.xlsx"
1718
- Xlsxrb.write(output_path) do |wb|
1719
- wb.style("center") { |style| style.align_horizontal("center") }
1720
- wb.sheet("CF Greater") do |s|
1721
- s.column(0, width: 25)
1722
- s.column(1, width: 25)
1723
- s.row(["Values"])
1724
- s.row([25], styles: "center")
1725
- s.row([75], styles: "center")
1726
- s.row([10], styles: "center")
1727
- s.conditional_format("A2:A4", type: "cellIs", operator: "greaterThan", formula: "50", fill_color: "FFFFC7CE")
1728
- end
1729
- end
1730
-
1731
- # 2. Read the generated sheet and print cell values
1732
- puts "=== Read Validation ==="
1733
- workbook = Xlsxrb.read(output_path).load
1734
- sheet = workbook.sheets.first
1735
- sheet.rows.first(5).each do |row|
1736
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1737
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1738
- end
1739
- ```
1740
-
1741
- ### Console Output
1742
-
1743
- ```text
1744
- === Read Validation ===
1745
- Row 0: A1: "Values"
1746
- Row 1: A2: 25
1747
- Row 2: A3: 75
1748
- Row 3: A4: 10
1749
- ```
1750
-
1751
- <hr/>
1752
-
1753
- ## Cf Cell Less Than
1754
-
1755
- Demonstrates conditional formatting highlighting cells less than a threshold.
1756
-
1757
- ### Rendered Output (LibreOffice Calc)
1758
-
1759
- <div><img src="../../test/visual/baselines/cf_cell_less_than/page-1.png" width="100%" alt="Preview"/></div>
1760
-
1761
- ### DSL Code
1762
-
1763
- ```ruby
1764
- # frozen_string_literal: true
1765
-
1766
- require "xlsxrb"
1767
- output_path = ARGV[0] || "cf_cell_less_than.xlsx"
1768
- Xlsxrb.write(output_path) do |wb|
1769
- wb.style("center") { |style| style.align_horizontal("center") }
1770
- wb.sheet("CF Less") do |s|
1771
- s.column(0, width: 25)
1772
- s.column(1, width: 25)
1773
- s.row(["Values"])
1774
- s.row([25], styles: "center")
1775
- s.row([75], styles: "center")
1776
- s.row([10], styles: "center")
1777
- s.conditional_format("A2:A4", type: "cellIs", operator: "lessThan", formula: "20", fill_color: "FFFFC7CE")
1778
- end
1779
- end
1780
-
1781
- # 2. Read the generated sheet and print cell values
1782
- puts "=== Read Validation ==="
1783
- workbook = Xlsxrb.read(output_path).load
1784
- sheet = workbook.sheets.first
1785
- sheet.rows.first(5).each do |row|
1786
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1787
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1788
- end
1789
- ```
1790
-
1791
- ### Console Output
1792
-
1793
- ```text
1794
- === Read Validation ===
1795
- Row 0: A1: "Values"
1796
- Row 1: A2: 25
1797
- Row 2: A3: 75
1798
- Row 3: A4: 10
1799
- ```
1800
-
1801
- <hr/>
1802
-
1803
- ## Cf Color Scale
1804
-
1805
- Demonstrates color scale/heatmap conditional formatting.
1806
-
1807
- ### Rendered Output (LibreOffice Calc)
1808
-
1809
- <div><img src="../../test/visual/baselines/cf_color_scale/page-1.png" width="100%" alt="Preview"/></div>
1810
-
1811
- ### DSL Code
1812
-
1813
- ```ruby
1814
- # frozen_string_literal: true
1815
-
1816
- require "xlsxrb"
1817
- output_path = ARGV[0] || "cf_color_scale.xlsx"
1818
- Xlsxrb.write(output_path) do |wb|
1819
- wb.style("center") { |style| style.align_horizontal("center") }
1820
- wb.sheet("Colors") do |s|
1821
- s.column(0, width: 25)
1822
- s.column(1, width: 25)
1823
- s.row([10], styles: "center")
1824
- s.row([50], styles: "center")
1825
- s.row([90], styles: "center")
1826
- s.conditional_format("A1:A3", type: :colorScale, priority: 1)
1827
- end
1828
- end
1829
-
1830
- # 2. Read the generated sheet and print cell values
1831
- puts "=== Read Validation ==="
1832
- workbook = Xlsxrb.read(output_path).load
1833
- sheet = workbook.sheets.first
1834
- sheet.rows.first(5).each do |row|
1835
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1836
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1837
- end
1838
- ```
1839
-
1840
- ### Console Output
1841
-
1842
- ```text
1843
- === Read Validation ===
1844
- Row 0: A1: 10
1845
- Row 1: A2: 50
1846
- Row 2: A3: 90
1847
- ```
1848
-
1849
- <hr/>
1850
-
1851
- ## Cf Contains Text
1852
-
1853
- Demonstrates conditional formatting highlighting cells containing specific text.
1854
-
1855
- ### Rendered Output (LibreOffice Calc)
1856
-
1857
- <div><img src="../../test/visual/baselines/cf_contains_text/page-1.png" width="100%" alt="Preview"/></div>
1858
-
1859
- ### DSL Code
1860
-
1861
- ```ruby
1862
- # frozen_string_literal: true
1863
-
1864
- require "xlsxrb"
1865
- output_path = ARGV[0] || "cf_contains_text.xlsx"
1866
- Xlsxrb.write(output_path) do |wb|
1867
- wb.sheet("CF Contains") do |s|
1868
- s.column(0, width: 25)
1869
- s.column(1, width: 25)
1870
- s.row(["Status"])
1871
- s.row(["Error"])
1872
- s.row(["Success"])
1873
- s.row(["Pending"])
1874
- s.conditional_format("A2:A4", type: "containsText", operator: "containsText", text: "Error", formula: 'NOT(ISERROR(SEARCH("Error",A2)))', fill_color: :red)
1875
- end
1876
- end
1877
-
1878
- # 2. Read the generated sheet and print cell values
1879
- puts "=== Read Validation ==="
1880
- workbook = Xlsxrb.read(output_path).load
1881
- sheet = workbook.sheets.first
1882
- sheet.rows.first(5).each do |row|
1883
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1884
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1885
- end
1886
- ```
1887
-
1888
- ### Console Output
1889
-
1890
- ```text
1891
- === Read Validation ===
1892
- Row 0: A1: "Status"
1893
- Row 1: A2: "Error"
1894
- Row 2: A3: "Success"
1895
- Row 3: A4: "Pending"
1896
- ```
1897
-
1898
- <hr/>
1899
-
1900
- ## Cf Data Bar
1901
-
1902
- Demonstrates data bar visual conditional formatting indicators.
1903
-
1904
- ### Rendered Output (LibreOffice Calc)
1905
-
1906
- <div><img src="../../test/visual/baselines/cf_data_bar/page-1.png" width="100%" alt="Preview"/></div>
1907
-
1908
- ### DSL Code
1909
-
1910
- ```ruby
1911
- # frozen_string_literal: true
1912
-
1913
- require "xlsxrb"
1914
- output_path = ARGV[0] || "cf_data_bar.xlsx"
1915
- Xlsxrb.write(output_path) do |wb|
1916
- wb.style("center") { |style| style.align_horizontal("center") }
1917
- wb.sheet("Data Bars") do |s|
1918
- s.column(0, width: 25)
1919
- s.column(1, width: 25)
1920
- s.row([20], styles: "center")
1921
- s.row([60], styles: "center")
1922
- s.row([100], styles: "center")
1923
- s.conditional_format("A1:A3", type: :dataBar, priority: 1, color: "FF0070C0")
1924
- end
1925
- end
1926
-
1927
- # 2. Read the generated sheet and print cell values
1928
- puts "=== Read Validation ==="
1929
- workbook = Xlsxrb.read(output_path).load
1930
- sheet = workbook.sheets.first
1931
- sheet.rows.first(5).each do |row|
1932
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1933
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1934
- end
1935
- ```
1936
-
1937
- ### Console Output
1938
-
1939
- ```text
1940
- === Read Validation ===
1941
- Row 0: A1: 20
1942
- Row 1: A2: 60
1943
- Row 2: A3: 100
1944
- ```
1945
-
1946
- <hr/>
1947
-
1948
- ## Cf Ends With
1949
-
1950
- Demonstrates conditional formatting highlighting cells ending with specific text.
1951
-
1952
- ### Rendered Output (LibreOffice Calc)
1953
-
1954
- <div><img src="../../test/visual/baselines/cf_ends_with/page-1.png" width="100%" alt="Preview"/></div>
1955
-
1956
- ### DSL Code
1957
-
1958
- ```ruby
1959
- # frozen_string_literal: true
1960
-
1961
- require "xlsxrb"
1962
- output_path = ARGV[0] || "cf_ends_with.xlsx"
1963
- Xlsxrb.write(output_path) do |wb|
1964
- wb.sheet("CF Ends") do |s|
1965
- s.column(0, width: 25)
1966
- s.column(1, width: 25)
1967
- s.row(["Code"])
1968
- s.row(["100-Z"])
1969
- s.row(["200-Y"])
1970
- s.row(["300-Z"])
1971
- s.conditional_format("A2:A4", type: "endsWith", operator: "endsWith", text: "Z", formula: 'RIGHT(A2,1)="Z"', fill_color: "FFFFC7CE")
1972
- end
1973
- end
1974
-
1975
- # 2. Read the generated sheet and print cell values
1976
- puts "=== Read Validation ==="
1977
- workbook = Xlsxrb.read(output_path).load
1978
- sheet = workbook.sheets.first
1979
- sheet.rows.first(5).each do |row|
1980
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
1981
- puts "Row #{row.index}: #{row_cells.join(", ")}"
1982
- end
1983
- ```
1984
-
1985
- ### Console Output
1986
-
1987
- ```text
1988
- === Read Validation ===
1989
- Row 0: A1: "Code"
1990
- Row 1: A2: "100-Z"
1991
- Row 2: A3: "200-Y"
1992
- Row 3: A4: "300-Z"
1993
- ```
1994
-
1995
- <hr/>
1996
-
1997
- ## Cf Expression Formula
1998
-
1999
- Demonstrates conditional formatting using a custom formula expression.
2000
-
2001
- ### Rendered Output (LibreOffice Calc)
2002
-
2003
- <div><img src="../../test/visual/baselines/cf_expression_formula/page-1.png" width="100%" alt="Preview"/></div>
2004
-
2005
- ### DSL Code
2006
-
2007
- ```ruby
2008
- # frozen_string_literal: true
2009
-
2010
- require "xlsxrb"
2011
- output_path = ARGV[0] || "cf_expression_formula.xlsx"
2012
- Xlsxrb.write(output_path) do |wb|
2013
- wb.style("center") { |style| style.align_horizontal("center") }
2014
- wb.sheet("CF Expression") do |s|
2015
- s.column(0, width: 25)
2016
- s.column(1, width: 25)
2017
- s.row(["Values"])
2018
- s.row([10], styles: "center")
2019
- s.row([20], styles: "center")
2020
- s.row([30], styles: "center")
2021
- s.row([100], styles: "center") # Average is 40. 100 is above average.
2022
- s.conditional_format("A2:A5", type: "expression", formula: "A2>AVERAGE($A$2:$A$5)", fill_color: "FFFFC7CE")
2023
- end
2024
- end
2025
-
2026
- # 2. Read the generated sheet and print cell values
2027
- puts "=== Read Validation ==="
2028
- workbook = Xlsxrb.read(output_path).load
2029
- sheet = workbook.sheets.first
2030
- sheet.rows.first(5).each do |row|
2031
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2032
- puts "Row #{row.index}: #{row_cells.join(", ")}"
2033
- end
2034
- ```
2035
-
2036
- ### Console Output
2037
-
2038
- ```text
2039
- === Read Validation ===
2040
- Row 0: A1: "Values"
2041
- Row 1: A2: 10
2042
- Row 2: A3: 20
2043
- Row 3: A4: 30
2044
- Row 4: A5: 100
2045
- ```
2046
-
2047
- <hr/>
2048
-
2049
- ## Cf Icon Set
2050
-
2051
- Demonstrates icon set indicators (red/yellow/green arrows).
2052
-
2053
- ### Rendered Output (LibreOffice Calc)
2054
-
2055
- <div><img src="../../test/visual/baselines/cf_icon_set/page-1.png" width="100%" alt="Preview"/></div>
2056
-
2057
- ### DSL Code
2058
-
2059
- ```ruby
2060
- # frozen_string_literal: true
2061
-
2062
- require "xlsxrb"
2063
- output_path = ARGV[0] || "cf_icon_set.xlsx"
2064
- Xlsxrb.write(output_path) do |wb|
2065
- wb.style("center") { |style| style.align_horizontal("center") }
2066
- wb.sheet("Icons") do |s|
2067
- s.column(0, width: 25)
2068
- s.column(1, width: 25)
2069
- s.row([25], styles: "center")
2070
- s.row([50], styles: "center")
2071
- s.row([75], styles: "center")
2072
- s.conditional_format("A1:A3", type: :iconSet, icon_style: "3Arrows", priority: 1)
2073
- end
2074
- end
2075
-
2076
- # 2. Read the generated sheet and print cell values
2077
- puts "=== Read Validation ==="
2078
- workbook = Xlsxrb.read(output_path).load
2079
- sheet = workbook.sheets.first
2080
- sheet.rows.first(5).each do |row|
2081
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2082
- puts "Row #{row.index}: #{row_cells.join(", ")}"
2083
- end
2084
- ```
2085
-
2086
- ### Console Output
2087
-
2088
- ```text
2089
- === Read Validation ===
2090
- Row 0: A1: 25
2091
- Row 1: A2: 50
2092
- Row 2: A3: 75
2093
- ```
2094
-
2095
- <hr/>
2096
-
2097
- ## Chart Area
2098
-
2099
- Demonstrates embedding a standard 2D Area Chart.
2100
-
2101
- ### Rendered Output (LibreOffice Calc)
2102
-
2103
- <div><img src="../../test/visual/baselines/chart_area/page-1.png" width="100%" alt="Preview"/></div>
2104
-
2105
- ### DSL Code
2106
-
2107
- ```ruby
2108
- # frozen_string_literal: true
2109
-
2110
- require "xlsxrb"
2111
- output_path = ARGV[0] || "chart_area.xlsx"
2112
- Xlsxrb.write(output_path) do |wb|
2113
- wb.sheet("Data") do |s|
2114
- s.sheet_properties(:fit_to_page, true)
2115
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2116
- s.column(0, width: 25)
2117
- s.column(1, width: 25)
2118
- s.row(%w[Day Value])
2119
- s.row(["Mon", 10])
2120
- s.row(["Tue", 15])
2121
- s.chart(
2122
- type: :area,
2123
- title: "Daily Area",
2124
- from_col: 3, from_row: 0, to_col: 8, to_row: 12,
2125
- series: [{ cat_ref: "Data!$A$2:$A$3", val_ref: "Data!$B$2:$B$3", fill_color: "4F81BD" }]
2126
- )
2127
- end
2128
- end
2129
-
2130
- # 2. Read the generated sheet and print the chart count
2131
- puts "=== Read Validation ==="
2132
- workbook = Xlsxrb.read(output_path).load
2133
- sheet = workbook.sheets.first
2134
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2135
- ```
2136
-
2137
- ### Console Output
2138
-
2139
- ```text
2140
- === Read Validation ===
2141
- Sheet 'Data' has 0 chart(s)
2142
- ```
2143
-
2144
- <hr/>
2145
-
2146
- ## Chart Area Stacked
2147
-
2148
- Demonstrates embedding a stacked 2D Area Chart.
2149
-
2150
- ### Rendered Output (LibreOffice Calc)
2151
-
2152
- <div><img src="../../test/visual/baselines/chart_area_stacked/page-1.png" width="100%" alt="Preview"/></div>
2153
-
2154
- ### DSL Code
2155
-
2156
- ```ruby
2157
- # frozen_string_literal: true
2158
-
2159
- require "xlsxrb"
2160
- output_path = ARGV[0] || "chart_area_stacked.xlsx"
2161
- Xlsxrb.write(output_path) do |wb|
2162
- wb.sheet("Data") do |s|
2163
- s.column(0, width: 25)
2164
- s.column(1, width: 25)
2165
- s.row(["Year", "Sales A", "Sales B"])
2166
- s.row([2024, 100, 150])
2167
- s.row([2025, 120, 180])
2168
- s.row([2026, 140, 210])
2169
- s.sheet_properties(:fit_to_page, true)
2170
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2171
- s.chart(
2172
- type: :area,
2173
- grouping: :stacked,
2174
- title: "Stacked Area Chart",
2175
- from_col: 0, from_row: 5, to_col: 6, to_row: 17,
2176
- series: [
2177
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$B$2:$B$4", name: "'Data'!$B$1", fill_color: "4F81BD" },
2178
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$C$2:$C$4", name: "'Data'!$C$1", fill_color: "C0504D" }
2179
- ]
2180
- )
2181
- end
2182
- end
2183
-
2184
- # 2. Read the generated sheet and print the chart count
2185
- puts "=== Read Validation ==="
2186
- workbook = Xlsxrb.read(output_path).load
2187
- sheet = workbook.sheets.first
2188
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2189
- ```
2190
-
2191
- ### Console Output
2192
-
2193
- ```text
2194
- === Read Validation ===
2195
- Sheet 'Data' has 0 chart(s)
2196
- ```
2197
-
2198
- <hr/>
2199
-
2200
- ## Chart Bar
2201
-
2202
- Demonstrates embedding a standard 2D Bar Chart referencing worksheet cell ranges.
2203
-
2204
- ### Rendered Output (LibreOffice Calc)
2205
-
2206
- <div><img src="../../test/visual/baselines/chart_bar/page-1.png" width="100%" alt="Preview"/></div>
2207
-
2208
- ### DSL Code
2209
-
2210
- ```ruby
2211
- # frozen_string_literal: true
2212
-
2213
- require "xlsxrb"
2214
-
2215
- output_path = ARGV[0] || "chart_bar.xlsx"
2216
-
2217
- Xlsxrb.write(output_path) do |wb|
2218
- wb.sheet("Sales Data") do |s|
2219
- s.sheet_properties(:fit_to_page, true)
2220
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2221
- s.column(0, width: 25)
2222
- s.column(1, width: 25)
2223
- s.row(%w[Month Value])
2224
- s.row(["Jan", 100])
2225
- s.row(["Feb", 200])
2226
-
2227
- s.chart(
2228
- type: :bar,
2229
- title: "Monthly Sales",
2230
- from_col: 3,
2231
- from_row: 0,
2232
- to_col: 8,
2233
- to_row: 12,
2234
- series: [
2235
- { cat_ref: "'Sales Data'!$A$2:$A$3", val_ref: "'Sales Data'!$B$2:$B$3", fill_color: "4F81BD" }
2236
- ]
2237
- )
2238
- end
2239
- end
2240
-
2241
- # 2. Read the generated sheet and print the chart count
2242
- puts "=== Read Validation ==="
2243
- workbook = Xlsxrb.read(output_path).load
2244
- sheet = workbook.sheets.first
2245
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2246
- ```
2247
-
2248
- ### Console Output
2249
-
2250
- ```text
2251
- === Read Validation ===
2252
- Sheet 'Sales Data' has 0 chart(s)
2253
- ```
2254
-
2255
- <hr/>
2256
-
2257
- ## Chart Bar Percent Stacked
2258
-
2259
- Demonstrates embedding a 100% stacked 2D Bar Chart.
2260
-
2261
- ### Rendered Output (LibreOffice Calc)
2262
-
2263
- <div><img src="../../test/visual/baselines/chart_bar_percent_stacked/page-1.png" width="100%" alt="Preview"/></div>
2264
-
2265
- ### DSL Code
2266
-
2267
- ```ruby
2268
- # frozen_string_literal: true
2269
-
2270
- require "xlsxrb"
2271
- output_path = ARGV[0] || "chart_bar_percent_stacked.xlsx"
2272
- Xlsxrb.write(output_path) do |wb|
2273
- wb.sheet("Data") do |s|
2274
- s.column(0, width: 25)
2275
- s.column(1, width: 25)
2276
- s.row(["Year", "Sales A", "Sales B"])
2277
- s.row([2024, 100, 150])
2278
- s.row([2025, 120, 180])
2279
- s.row([2026, 140, 210])
2280
- s.sheet_properties(:fit_to_page, true)
2281
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2282
- s.chart(
2283
- type: :bar,
2284
- grouping: :percentStacked,
2285
- title: "100% Stacked Bar Chart",
2286
- from_col: 0, from_row: 5, to_col: 6, to_row: 17,
2287
- series: [
2288
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$B$2:$B$4", name: "'Data'!$B$1", fill_color: "4F81BD" },
2289
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$C$2:$C$4", name: "'Data'!$C$1", fill_color: "C0504D" }
2290
- ]
2291
- )
2292
- end
2293
- end
2294
-
2295
- # 2. Read the generated sheet and print the chart count
2296
- puts "=== Read Validation ==="
2297
- workbook = Xlsxrb.read(output_path).load
2298
- sheet = workbook.sheets.first
2299
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2300
- ```
2301
-
2302
- ### Console Output
2303
-
2304
- ```text
2305
- === Read Validation ===
2306
- Sheet 'Data' has 0 chart(s)
2307
- ```
2308
-
2309
- <hr/>
2310
-
2311
- ## Chart Bar Stacked
2312
-
2313
- Demonstrates embedding a stacked 2D Bar Chart.
2314
-
2315
- ### Rendered Output (LibreOffice Calc)
2316
-
2317
- <div><img src="../../test/visual/baselines/chart_bar_stacked/page-1.png" width="100%" alt="Preview"/></div>
2318
-
2319
- ### DSL Code
2320
-
2321
- ```ruby
2322
- # frozen_string_literal: true
2323
-
2324
- require "xlsxrb"
2325
- output_path = ARGV[0] || "chart_bar_stacked.xlsx"
2326
- Xlsxrb.write(output_path) do |wb|
2327
- wb.sheet("Data") do |s|
2328
- s.column(0, width: 25)
2329
- s.column(1, width: 25)
2330
- s.row(["Year", "Sales A", "Sales B"])
2331
- s.row([2024, 100, 150])
2332
- s.row([2025, 120, 180])
2333
- s.row([2026, 140, 210])
2334
- s.sheet_properties(:fit_to_page, true)
2335
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2336
- s.chart(
2337
- type: :bar,
2338
- grouping: :stacked,
2339
- title: "Stacked Bar Chart",
2340
- from_col: 0, from_row: 5, to_col: 6, to_row: 17,
2341
- series: [
2342
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$B$2:$B$4", name: "'Data'!$B$1", fill_color: "4F81BD" },
2343
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$C$2:$C$4", name: "'Data'!$C$1", fill_color: "C0504D" }
2344
- ]
2345
- )
2346
- end
2347
- end
2348
-
2349
- # 2. Read the generated sheet and print the chart count
2350
- puts "=== Read Validation ==="
2351
- workbook = Xlsxrb.read(output_path).load
2352
- sheet = workbook.sheets.first
2353
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2354
- ```
2355
-
2356
- ### Console Output
2357
-
2358
- ```text
2359
- === Read Validation ===
2360
- Sheet 'Data' has 0 chart(s)
2361
- ```
2362
-
2363
- <hr/>
2364
-
2365
- ## Chart Doughnut
2366
-
2367
- Demonstrates embedding a standard 2D Doughnut Chart.
2368
-
2369
- ### Rendered Output (LibreOffice Calc)
2370
-
2371
- <div><img src="../../test/visual/baselines/chart_doughnut/page-1.png" width="100%" alt="Preview"/></div>
2372
-
2373
- ### DSL Code
2374
-
2375
- ```ruby
2376
- # frozen_string_literal: true
2377
-
2378
- require "xlsxrb"
2379
- output_path = ARGV[0] || "chart_doughnut.xlsx"
2380
- Xlsxrb.write(output_path) do |wb|
2381
- wb.sheet("Data") do |s|
2382
- s.sheet_properties(:fit_to_page, true)
2383
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2384
- s.column(0, width: 25)
2385
- s.column(1, width: 25)
2386
- s.row(%w[Label Percent])
2387
- s.row(["A", 40])
2388
- s.row(["B", 60])
2389
- s.chart(
2390
- type: :doughnut,
2391
- title: "Ratio",
2392
- from_col: 3, from_row: 0, to_col: 8, to_row: 12,
2393
- series: [{
2394
- cat_ref: "Data!$A$2:$A$3",
2395
- val_ref: "Data!$B$2:$B$3",
2396
- data_points: [
2397
- { idx: 0, fill_color: "4F81BD" },
2398
- { idx: 1, fill_color: "C0504D" }
2399
- ]
2400
- }]
2401
- )
2402
- end
2403
- end
2404
-
2405
- # 2. Read the generated sheet and print the chart count
2406
- puts "=== Read Validation ==="
2407
- workbook = Xlsxrb.read(output_path).load
2408
- sheet = workbook.sheets.first
2409
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2410
- ```
2411
-
2412
- ### Console Output
2413
-
2414
- ```text
2415
- === Read Validation ===
2416
- Sheet 'Data' has 0 chart(s)
2417
- ```
2418
-
2419
- <hr/>
2420
-
2421
- ## Chart Line
2422
-
2423
- Demonstrates embedding a standard 2D Line Chart.
2424
-
2425
- ### Rendered Output (LibreOffice Calc)
2426
-
2427
- <div><img src="../../test/visual/baselines/chart_line/page-1.png" width="100%" alt="Preview"/></div>
2428
-
2429
- ### DSL Code
2430
-
2431
- ```ruby
2432
- # frozen_string_literal: true
2433
-
2434
- require "xlsxrb"
2435
- output_path = ARGV[0] || "chart_line.xlsx"
2436
- Xlsxrb.write(output_path) do |wb|
2437
- wb.sheet("Data") do |s|
2438
- s.sheet_properties(:fit_to_page, true)
2439
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2440
- s.column(0, width: 25)
2441
- s.column(1, width: 25)
2442
- s.row(%w[Day Value])
2443
- s.row(["Mon", 10])
2444
- s.row(["Tue", 15])
2445
- s.row(["Wed", 12])
2446
- s.chart(
2447
- type: :line,
2448
- title: "Daily Value",
2449
- from_col: 3, from_row: 0, to_col: 8, to_row: 12,
2450
- series: [{ cat_ref: "Data!$A$2:$A$4", val_ref: "Data!$B$2:$B$4", line_color: "4F81BD", line_width: 2.0 }]
2451
- )
2452
- end
2453
- end
2454
-
2455
- # 2. Read the generated sheet and print the chart count
2456
- puts "=== Read Validation ==="
2457
- workbook = Xlsxrb.read(output_path).load
2458
- sheet = workbook.sheets.first
2459
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2460
- ```
2461
-
2462
- ### Console Output
2463
-
2464
- ```text
2465
- === Read Validation ===
2466
- Sheet 'Data' has 0 chart(s)
2467
- ```
2468
-
2469
- <hr/>
2470
-
2471
- ## Chart Line Stacked
2472
-
2473
- Demonstrates embedding a stacked 2D Line Chart.
2474
-
2475
- ### Rendered Output (LibreOffice Calc)
2476
-
2477
- <div><img src="../../test/visual/baselines/chart_line_stacked/page-1.png" width="100%" alt="Preview"/></div>
2478
-
2479
- ### DSL Code
2480
-
2481
- ```ruby
2482
- # frozen_string_literal: true
2483
-
2484
- require "xlsxrb"
2485
- output_path = ARGV[0] || "chart_line_stacked.xlsx"
2486
- Xlsxrb.write(output_path) do |wb|
2487
- wb.sheet("Data") do |s|
2488
- s.column(0, width: 25)
2489
- s.column(1, width: 25)
2490
- s.row(["Year", "Sales A", "Sales B"])
2491
- s.row([2024, 100, 150])
2492
- s.row([2025, 120, 180])
2493
- s.row([2026, 140, 210])
2494
- s.sheet_properties(:fit_to_page, true)
2495
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2496
- s.chart(
2497
- type: :line,
2498
- grouping: :stacked,
2499
- title: "Stacked Line Chart",
2500
- from_col: 0, from_row: 5, to_col: 6, to_row: 17,
2501
- series: [
2502
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$B$2:$B$4", name: "'Data'!$B$1", line_color: "4F81BD", line_width: 2.0 },
2503
- { cat_ref: "'Data'!$A$2:$A$4", val_ref: "'Data'!$C$2:$C$4", name: "'Data'!$C$1", line_color: "C0504D", line_width: 2.0 }
2504
- ]
2505
- )
2506
- end
2507
- end
2508
-
2509
- # 2. Read the generated sheet and print the chart count
2510
- puts "=== Read Validation ==="
2511
- workbook = Xlsxrb.read(output_path).load
2512
- sheet = workbook.sheets.first
2513
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2514
- ```
2515
-
2516
- ### Console Output
2517
-
2518
- ```text
2519
- === Read Validation ===
2520
- Sheet 'Data' has 0 chart(s)
2521
- ```
2522
-
2523
- <hr/>
2524
-
2525
- ## Chart Pie
2526
-
2527
- Demonstrates embedding a standard 2D Pie Chart.
2528
-
2529
- ### Rendered Output (LibreOffice Calc)
2530
-
2531
- <div><img src="../../test/visual/baselines/chart_pie/page-1.png" width="100%" alt="Preview"/></div>
2532
-
2533
- ### DSL Code
2534
-
2535
- ```ruby
2536
- # frozen_string_literal: true
2537
-
2538
- require "xlsxrb"
2539
- output_path = ARGV[0] || "chart_pie.xlsx"
2540
- Xlsxrb.write(output_path) do |wb|
2541
- wb.sheet("Data") do |s|
2542
- s.sheet_properties(:fit_to_page, true)
2543
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2544
- s.column(0, width: 25)
2545
- s.column(1, width: 25)
2546
- s.row(%w[Label Percent])
2547
- s.row(["Yes", 70])
2548
- s.row(["No", 30])
2549
- s.chart(
2550
- type: :pie,
2551
- title: "Responses",
2552
- from_col: 3, from_row: 0, to_col: 8, to_row: 12,
2553
- series: [{
2554
- cat_ref: "Data!$A$2:$A$3",
2555
- val_ref: "Data!$B$2:$B$3",
2556
- data_points: [
2557
- { idx: 0, fill_color: "4F81BD" },
2558
- { idx: 1, fill_color: "C0504D" }
2559
- ]
2560
- }]
2561
- )
2562
- end
2563
- end
2564
-
2565
- # 2. Read the generated sheet and print the chart count
2566
- puts "=== Read Validation ==="
2567
- workbook = Xlsxrb.read(output_path).load
2568
- sheet = workbook.sheets.first
2569
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2570
- ```
2571
-
2572
- ### Console Output
2573
-
2574
- ```text
2575
- === Read Validation ===
2576
- Sheet 'Data' has 0 chart(s)
2577
- ```
2578
-
2579
- <hr/>
2580
-
2581
- ## Chart Radar
2582
-
2583
- Demonstrates embedding a standard 2D Radar Chart.
2584
-
2585
- ### Rendered Output (LibreOffice Calc)
2586
-
2587
- <div><img src="../../test/visual/baselines/chart_radar/page-1.png" width="100%" alt="Preview"/></div>
2588
-
2589
- ### DSL Code
2590
-
2591
- ```ruby
2592
- # frozen_string_literal: true
2593
-
2594
- require "xlsxrb"
2595
- output_path = ARGV[0] || "chart_radar.xlsx"
2596
- Xlsxrb.write(output_path) do |wb|
2597
- wb.sheet("Data") do |s|
2598
- s.sheet_properties(:fit_to_page, true)
2599
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2600
- s.column(0, width: 25)
2601
- s.column(1, width: 25)
2602
- s.row(%w[Stat Value])
2603
- s.row(["Atk", 80])
2604
- s.row(["Def", 60])
2605
- s.chart(
2606
- type: :radar,
2607
- title: "Stats",
2608
- from_col: 3, from_row: 0, to_col: 8, to_row: 12,
2609
- series: [{ cat_ref: "Data!$A$2:$A$3", val_ref: "Data!$B$2:$B$3", line_color: "4F81BD", line_width: 2.0 }]
2610
- )
2611
- end
2612
- end
2613
-
2614
- # 2. Read the generated sheet and print the chart count
2615
- puts "=== Read Validation ==="
2616
- workbook = Xlsxrb.read(output_path).load
2617
- sheet = workbook.sheets.first
2618
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2619
- ```
2620
-
2621
- ### Console Output
2622
-
2623
- ```text
2624
- === Read Validation ===
2625
- Sheet 'Data' has 0 chart(s)
2626
- ```
2627
-
2628
- <hr/>
2629
-
2630
- ## Chart Scatter
2631
-
2632
- Demonstrates embedding a standard 2D Scatter Plot.
2633
-
2634
- ### Rendered Output (LibreOffice Calc)
2635
-
2636
- <div><img src="../../test/visual/baselines/chart_scatter/page-1.png" width="100%" alt="Preview"/></div>
2637
-
2638
- ### DSL Code
2639
-
2640
- ```ruby
2641
- # frozen_string_literal: true
2642
-
2643
- require "xlsxrb"
2644
- output_path = ARGV[0] || "chart_scatter.xlsx"
2645
- Xlsxrb.write(output_path) do |wb|
2646
- wb.sheet("Data") do |s|
2647
- s.sheet_properties(:fit_to_page, true)
2648
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2649
- s.column(0, width: 25)
2650
- s.column(1, width: 25)
2651
- s.row(%w[X Y])
2652
- s.row([1, 10])
2653
- s.row([2, 15])
2654
- s.chart(
2655
- type: :scatter,
2656
- title: "Scatter Plot",
2657
- from_col: 3, from_row: 0, to_col: 8, to_row: 12,
2658
- series: [{ cat_ref: "Data!$A$2:$A$3", val_ref: "Data!$B$2:$B$3", line_color: "4F81BD", line_width: 2.0 }]
2659
- )
2660
- end
2661
- end
2662
-
2663
- # 2. Read the generated sheet and print the chart count
2664
- puts "=== Read Validation ==="
2665
- workbook = Xlsxrb.read(output_path).load
2666
- sheet = workbook.sheets.first
2667
- puts "Sheet '#{sheet.name}' has #{sheet.charts.size} chart(s)"
2668
- ```
2669
-
2670
- ### Console Output
2671
-
2672
- ```text
2673
- === Read Validation ===
2674
- Sheet 'Data' has 0 chart(s)
2675
- ```
2676
-
2677
- <hr/>
2678
-
2679
- ## Col Grouping
2680
-
2681
- Demonstrates outline grouping for columns.
2682
-
2683
- ### Rendered Output (LibreOffice Calc)
2684
-
2685
- <div><img src="../../test/visual/baselines/col_grouping/page-1.png" width="100%" alt="Preview"/></div>
2686
-
2687
- ### DSL Code
2688
-
2689
- ```ruby
2690
- # frozen_string_literal: true
2691
-
2692
- require "xlsxrb"
2693
- output_path = ARGV[0] || "col_grouping.xlsx"
2694
- Xlsxrb.write(output_path) do |wb|
2695
- wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2696
- wb.sheet("Col Grouping") do |s|
2697
- s.sheet_properties(:fit_to_page, true)
2698
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
2699
- s.column(0, width: 25, outline_level: 0)
2700
- s.column(1, width: 25, outline_level: 1)
2701
- s.column(2, width: 25, outline_level: 1)
2702
- s.row(["Col A", "Col B (Grouped)", "Col C (Grouped)"], styles: %w[border border border])
2703
- end
2704
- end
2705
-
2706
- # 2. Read the generated sheet and print column dimensions
2707
- puts "=== Read Validation ==="
2708
- workbook = Xlsxrb.read(output_path).load
2709
- sheet = workbook.sheets.first
2710
- sheet.columns.each do |col|
2711
- puts "Column #{col.index}: width=#{col.width}, hidden=#{col.hidden}, outline_level=#{col.outline_level}"
2712
- end
2713
- ```
2714
-
2715
- ### Console Output
2716
-
2717
- ```text
2718
- === Read Validation ===
2719
- Column 0: width=25.0, hidden=false, outline_level=0
2720
- Column 1: width=25.0, hidden=false, outline_level=1
2721
- Column 2: width=25.0, hidden=false, outline_level=1
2722
- ```
2723
-
2724
- <hr/>
2725
-
2726
- ## Col Width Tall
2727
-
2728
- Demonstrates setting very wide column widths.
2729
-
2730
- ### Rendered Output (LibreOffice Calc)
2731
-
2732
- <div><img src="../../test/visual/baselines/col_width_tall/page-1.png" width="100%" alt="Preview"/></div>
2733
-
2734
- ### DSL Code
2735
-
2736
- ```ruby
2737
- # frozen_string_literal: true
2738
-
2739
- require "xlsxrb"
2740
- output_path = ARGV[0] || "col_width_tall.xlsx"
2741
- Xlsxrb.write(output_path) do |wb|
2742
- wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2743
- wb.sheet("Col Width") do |s|
2744
- s.column(0, width: 50)
2745
- s.column(1, width: 10)
2746
- s.row(["Very Wide Column (Width 50)", "Normal (10)"], styles: %w[border border])
2747
- end
2748
- end
2749
-
2750
- # 2. Read the generated sheet and print column dimensions
2751
- puts "=== Read Validation ==="
2752
- workbook = Xlsxrb.read(output_path).load
2753
- sheet = workbook.sheets.first
2754
- sheet.columns.each do |col|
2755
- puts "Column #{col.index}: width=#{col.width}, hidden=#{col.hidden}, outline_level=#{col.outline_level}"
2756
- end
2757
- ```
2758
-
2759
- ### Console Output
2760
-
2761
- ```text
2762
- === Read Validation ===
2763
- Column 0: width=50.0, hidden=false, outline_level=
2764
- Column 1: width=10.0, hidden=false, outline_level=
2765
- ```
2766
-
2767
- <hr/>
2768
-
2769
- ## Col Widths
2770
-
2771
- Demonstrates setting custom column widths.
2772
-
2773
- ### Rendered Output (LibreOffice Calc)
2774
-
2775
- <div><img src="../../test/visual/baselines/col_widths/page-1.png" width="100%" alt="Preview"/></div>
2776
-
2777
- ### DSL Code
2778
-
2779
- ```ruby
2780
- # frozen_string_literal: true
2781
-
2782
- require "xlsxrb"
2783
- output_path = ARGV[0] || "col_widths.xlsx"
2784
- Xlsxrb.write(output_path) do |wb|
2785
- wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
2786
- wb.sheet("Widths") do |s|
2787
- s.column(0, width: 30)
2788
- s.column(1, width: 10)
2789
- s.row(["Wide Column A", "Narrow B"], styles: %w[border border])
2790
- end
2791
- end
2792
-
2793
- # 2. Read the generated sheet and print column dimensions
2794
- puts "=== Read Validation ==="
2795
- workbook = Xlsxrb.read(output_path).load
2796
- sheet = workbook.sheets.first
2797
- sheet.columns.each do |col|
2798
- puts "Column #{col.index}: width=#{col.width}, hidden=#{col.hidden}, outline_level=#{col.outline_level}"
2799
- end
2800
- ```
2801
-
2802
- ### Console Output
2803
-
2804
- ```text
2805
- === Read Validation ===
2806
- Column 0: width=30.0, hidden=false, outline_level=
2807
- Column 1: width=10.0, hidden=false, outline_level=
2808
- ```
2809
-
2810
- <hr/>
2811
-
2812
- ## Conditional Formatting
2813
-
2814
- Demonstrates adding conditional formatting rules that style cells automatically based on value ranges.
2815
-
2816
- ### Rendered Output (LibreOffice Calc)
2817
-
2818
- <div><img src="../../test/visual/baselines/conditional_formatting/page-1.png" width="100%" alt="Preview"/></div>
2819
-
2820
- ### DSL Code
2821
-
2822
- ```ruby
2823
- # frozen_string_literal: true
2824
-
2825
- require "xlsxrb"
2826
-
2827
- output_path = ARGV[0] || "conditional_formatting.xlsx"
2828
-
2829
- Xlsxrb.write(output_path) do |wb|
2830
- wb.style("center") { |style| style.align_horizontal("center") }
2831
- wb.sheet("Scores") do |s|
2832
- s.column(0, width: 25)
2833
- s.column(1, width: 25)
2834
- s.row([90, 45, 72, 88], styles: %w[center center center center])
2835
-
2836
- s.conditional_format("A1:D1",
2837
- type: :cell_is, operator: :greaterThan,
2838
- formula: "80", priority: 1,
2839
- fill_color: "FFFFC7CE")
2840
- end
2841
- end
2842
-
2843
- # 2. Read the generated sheet and print cell values
2844
- puts "=== Read Validation ==="
2845
- workbook = Xlsxrb.read(output_path).load
2846
- sheet = workbook.sheets.first
2847
- sheet.rows.first(5).each do |row|
2848
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2849
- puts "Row #{row.index}: #{row_cells.join(", ")}"
2850
- end
2851
- ```
2852
-
2853
- ### Console Output
2854
-
2855
- ```text
2856
- === Read Validation ===
2857
- Row 0: A1: 90, B1: 45, C1: 72, D1: 88
2858
- ```
2859
-
2860
- <hr/>
2861
-
2862
- ## Drawing Shapes
2863
-
2864
- Visual demonstration for Drawing Shapes.
2865
-
2866
- ### Rendered Output (LibreOffice Calc)
2867
-
2868
- <div><img src="../../test/visual/baselines/drawing_shapes/page-1.png" width="100%" alt="Preview"/></div>
2869
-
2870
- ### DSL Code
2871
-
2872
- ```ruby
2873
- # frozen_string_literal: true
2874
-
2875
- require "xlsxrb"
2876
-
2877
- output_path = ARGV[0] || "drawing_shapes.xlsx"
2878
-
2879
- Xlsxrb.write(output_path) do |wb|
2880
- wb.sheet("Shapes") do |sheet|
2881
- sheet.column(0..4, width: 12)
2882
- sheet.row(["Diagram with shapes and annotations"])
2883
- sheet.row([])
2884
- sheet.shape(preset: "rect", text: "Start", from_col: 0, from_row: 2, to_col: 1, to_row: 4)
2885
- sheet.shape(preset: "rightArrow", text: "Next", from_col: 1, from_row: 3, to_col: 2, to_row: 4)
2886
- sheet.shape(preset: "roundRect", text: "Processing", from_col: 2, from_row: 2, to_col: 4, to_row: 4)
2887
- end
2888
- end
2889
-
2890
- puts "=== Read Validation ==="
2891
- workbook = Xlsxrb.read(output_path).load
2892
- sheet = workbook.sheets.first
2893
- sheet.rows.each do |row|
2894
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2895
- puts "Row #{row.index}: #{row_cells.join(", ")}"
2896
- end
2897
- ```
2898
-
2899
- ### Console Output
2900
-
2901
- ```text
2902
- === Read Validation ===
2903
- Row 0: A1: "Diagram with shapes and annotations"
2904
- Row 1:
2905
- ```
2906
-
2907
- <hr/>
2908
-
2909
- ## Embedded Images
2910
-
2911
- Demonstrates embedding raster PNG images in cell ranges.
2912
-
2913
- ### Rendered Output (LibreOffice Calc)
2914
-
2915
- <div><img src="../../test/visual/baselines/embedded_images/page-1.png" width="100%" alt="Preview"/></div>
2916
-
2917
- ### DSL Code
2918
-
2919
- ```ruby
2920
- # frozen_string_literal: true
2921
-
2922
- require "xlsxrb"
2923
- output_path = ARGV[0] || "embedded_images.xlsx"
2924
-
2925
- require "zlib"
2926
-
2927
- def make_png(width, height, red, green, blue)
2928
- png = "\x89PNG\r\n\x1a\n".dup.force_encoding("BINARY")
2929
- ihdr_data = [width, height, 8, 2, 0, 0, 0].pack("N2C5")
2930
- ihdr_chunk = "IHDR".dup.force_encoding("BINARY") + ihdr_data
2931
- ihdr_crc = Zlib.crc32(ihdr_chunk)
2932
- png << [ihdr_data.bytesize].pack("N") << ihdr_chunk << [ihdr_crc].pack("N")
2933
- raw_data = Array.new(height) { "\x00".dup.force_encoding("BINARY") + ([red, green, blue].pack("C3") * width) }.join
2934
- compressed = Zlib.deflate(raw_data)
2935
- idat_chunk = "IDAT".dup.force_encoding("BINARY") + compressed
2936
- idat_crc = Zlib.crc32(idat_chunk)
2937
- png << [compressed.bytesize].pack("N") << idat_chunk << [idat_crc].pack("N")
2938
- iend_chunk = "IEND".dup.force_encoding("BINARY")
2939
- iend_crc = Zlib.crc32(iend_chunk)
2940
- png << [0].pack("N") << iend_chunk << [iend_crc].pack("N")
2941
- png
2942
- end
2943
-
2944
- dummy_png = make_png(100, 100, 255, 0, 0)
2945
-
2946
- Xlsxrb.write(output_path) do |wb|
2947
- wb.style("center") { |st| st.align_horizontal(:center) }
2948
- wb.sheet("Images") do |s|
2949
- s.row(["Logo Target cell:", "", "", "Boundary"], styles: %w[left center center center])
2950
- s.row(["", "", "", ""])
2951
- s.row(["", "", "", ""])
2952
- s.row(["", "", "", ""])
2953
- s.row(["", "", "", "Boundary End"], styles: %w[left center center center])
2954
- s.image(dummy_png, ext: "png", from_col: 1, from_row: 1, to_col: 3, to_row: 5)
2955
- s.column(0, width: 20)
2956
- s.column(1, width: 15)
2957
- s.column(2, width: 15)
2958
- s.column(3, width: 15)
2959
- end
2960
- end
2961
-
2962
- # 2. Read the generated sheet and print cell values + parsed embedded images details
2963
- puts "=== Read Validation ==="
2964
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
2965
- workbook = Xlsxrb.read(output_path).load
2966
- sheet = workbook.sheets.first
2967
- sheet.rows.first(5).each do |row|
2968
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
2969
- puts "Row #{row.index}: #{row_cells.join(", ")}"
2970
- end
2971
- images = reader.images(sheet: sheet.name)
2972
- images.each_with_index do |img, idx|
2973
- zip_path = File.expand_path(img[:target], "/xl/drawings").sub(%r{^/}, "")
2974
- img_data = reader.send(:extract_zip_entry, zip_path)
2975
- is_png = img_data && img_data[0..3] == "\x89PNG".b
2976
- puts "Image ##{idx + 1}: name='#{img[:name]}', target='#{img[:target]}' -> ZIP path='#{zip_path}', size=#{img_data&.bytesize} bytes, valid_png=#{is_png}, range=Col #{img[:from_col]} Row #{img[:from_row]} to Col #{img[:to_col]} Row #{img[:to_row]}"
2977
- end
2978
- ```
2979
-
2980
- ### Console Output
2981
-
2982
- ```text
2983
- === Read Validation ===
2984
- Row 0: A1: "Logo Target cell:", B1: "", C1: "", D1: "Boundary"
2985
- Row 1: A2: "", B2: "", C2: "", D2: ""
2986
- Row 2: A3: "", B3: "", C3: "", D3: ""
2987
- Row 3: A4: "", B4: "", C4: "", D4: ""
2988
- Row 4: A5: "", B5: "", C5: "", D5: "Boundary End"
2989
- Image #1: name='', target='../media/image1.png' -> ZIP path='xl/media/image1.png', size=334 bytes, valid_png=true, range=Col 1 Row 1 to Col 3 Row 5
2990
- ```
2991
-
2992
- <hr/>
2993
-
2994
- ## Fill Gradients
2995
-
2996
- Demonstrates linear gradients inside cell backgrounds.
2997
-
2998
- ### Rendered Output (LibreOffice Calc)
2999
-
3000
- <div><img src="../../test/visual/baselines/fill_gradients/page-1.png" width="100%" alt="Preview"/></div>
3001
-
3002
- ### DSL Code
3003
-
3004
- ```ruby
3005
- # frozen_string_literal: true
3006
-
3007
- require "xlsxrb"
3008
- output_path = ARGV[0] || "fill_gradients.xlsx"
3009
- Xlsxrb.write(output_path) do |wb|
3010
- wb.style("gradient") do |style|
3011
- style.fill_gradient(type: "linear", degree: 45, stops: [
3012
- { position: 0, color: "FFFFFFFF" },
3013
- { position: 1, color: "FF4F81BD" }
3014
- ])
3015
- end
3016
- wb.sheet("Gradients") do |s|
3017
- s.column(0, width: 25)
3018
- s.column(1, width: 25)
3019
- s.row(["Normal Cell", "Gradient Cell"], styles: { 1 => "gradient" })
3020
- end
3021
- end
3022
-
3023
- # 2. Read the generated sheet and print cell fill properties
3024
- puts "=== Read Validation ==="
3025
- workbook = Xlsxrb.read(output_path).load
3026
- sheet = workbook.sheets.first
3027
- row = sheet.rows.first
3028
- row.cells.each do |c|
3029
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
3030
- fill = xf ? workbook.styles[:fills][xf[:fill_id]] : nil
3031
- puts "Cell #{c.ref} ('#{c.value}'): fill pattern = #{fill&.[](:pattern).inspect}, fg_color = #{fill&.[](:fg_color).inspect}"
3032
- end
3033
- ```
3034
-
3035
- ### Console Output
3036
-
3037
- ```text
3038
- === Read Validation ===
3039
- Cell A1 ('Normal Cell'): fill pattern = nil, fg_color = nil
3040
- Cell B1 ('Gradient Cell'): fill pattern = nil, fg_color = nil
3041
- ```
3042
-
3043
- <hr/>
3044
-
3045
- ## Fill Patterns
3046
-
3047
- Demonstrates standard pattern fills (darkGray, darkGrid) in cell backgrounds.
3048
-
3049
- ### Rendered Output (LibreOffice Calc)
3050
-
3051
- <div><img src="../../test/visual/baselines/fill_patterns/page-1.png" width="100%" alt="Preview"/></div>
3052
-
3053
- ### DSL Code
3054
-
3055
- ```ruby
3056
- # frozen_string_literal: true
3057
-
3058
- require "xlsxrb"
3059
- output_path = ARGV[0] || "fill_patterns.xlsx"
3060
- Xlsxrb.write(output_path) do |wb|
3061
- wb.style("dark_gray") { |s| s.fill(pattern: "darkGray", fg_color: "FFC0C0C0", bg_color: "FFFFFFFF") }
3062
- wb.style("grid_fill") { |s| s.fill(pattern: "darkGrid", fg_color: "FFC0C0C0", bg_color: "FFFFFFFF") }
3063
- wb.sheet("Patterns") do |s|
3064
- s.column(0, width: 25)
3065
- s.column(1, width: 25)
3066
- s.row(%w[Pattern Preview])
3067
- s.row(["Dark Gray", "Pattern Fill"], styles: { 1 => "dark_gray" })
3068
- s.row(["Dark Grid", "Grid Fill"], styles: { 1 => "grid_fill" })
3069
- end
3070
- end
3071
-
3072
- # 2. Read the generated sheet and print cell fill properties
3073
- puts "=== Read Validation ==="
3074
- workbook = Xlsxrb.read(output_path).load
3075
- sheet = workbook.sheets.first
3076
- row = sheet.rows.first
3077
- row.cells.each do |c|
3078
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
3079
- fill = xf ? workbook.styles[:fills][xf[:fill_id]] : nil
3080
- puts "Cell #{c.ref} ('#{c.value}'): fill pattern = #{fill&.[](:pattern).inspect}, fg_color = #{fill&.[](:fg_color).inspect}"
3081
- end
3082
- ```
3083
-
3084
- ### Console Output
3085
-
3086
- ```text
3087
- === Read Validation ===
3088
- Cell A1 ('Pattern'): fill pattern = nil, fg_color = nil
3089
- Cell B1 ('Preview'): fill pattern = nil, fg_color = nil
3090
- ```
3091
-
3092
- <hr/>
3093
-
3094
- ## Fill Solid Colors
3095
-
3096
- Demonstrates solid cell background fill colors.
3097
-
3098
- ### Rendered Output (LibreOffice Calc)
3099
-
3100
- <div><img src="../../test/visual/baselines/fill_solid_colors/page-1.png" width="100%" alt="Preview"/></div>
3101
-
3102
- ### DSL Code
3103
-
3104
- ```ruby
3105
- # frozen_string_literal: true
3106
-
3107
- require "xlsxrb"
3108
- output_path = ARGV[0] || "fill_solid_colors.xlsx"
3109
- Xlsxrb.write(output_path) do |wb|
3110
- wb.style("red_fill") { |s| s.fill_color("FFFFC7CE") }
3111
- wb.style("green_fill") { |s| s.fill_color("FFC6EFCE") }
3112
- wb.sheet("Fills") do |s|
3113
- s.column(0, width: 25)
3114
- s.column(1, width: 25)
3115
- s.row(%w[Color Preview])
3116
- s.row(["Red", "Red Fill"], styles: { 1 => "red_fill" })
3117
- s.row(["Green", "Green Fill"], styles: { 1 => "green_fill" })
3118
- end
3119
- end
3120
-
3121
- # 2. Read the generated sheet and print cell fill properties
3122
- puts "=== Read Validation ==="
3123
- workbook = Xlsxrb.read(output_path).load
3124
- sheet = workbook.sheets.first
3125
- row = sheet.rows.first
3126
- row.cells.each do |c|
3127
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
3128
- fill = xf ? workbook.styles[:fills][xf[:fill_id]] : nil
3129
- puts "Cell #{c.ref} ('#{c.value}'): fill pattern = #{fill&.[](:pattern).inspect}, fg_color = #{fill&.[](:fg_color).inspect}"
3130
- end
3131
- ```
3132
-
3133
- ### Console Output
3134
-
3135
- ```text
3136
- === Read Validation ===
3137
- Cell A1 ('Color'): fill pattern = nil, fg_color = nil
3138
- Cell B1 ('Preview'): fill pattern = nil, fg_color = nil
3139
- ```
3140
-
3141
- <hr/>
3142
-
3143
- ## Fonts
3144
-
3145
- Demonstrates cell fonts properties (Arial, Georgia, Courier New, Times New Roman, Tahoma, sizes 10pt/16pt/24pt, red/green/blue colors, bold/italic/underline/double underline/strike-through styles, superscript/subscript).
3146
-
3147
- ### Rendered Output (LibreOffice Calc)
3148
-
3149
- <div><img src="../../test/visual/baselines/fonts/page-1.png" width="100%" alt="Preview"/></div>
3150
-
3151
- ### DSL Code
3152
-
3153
- ```ruby
3154
- # frozen_string_literal: true
3155
-
3156
- require "xlsxrb"
3157
-
3158
- output_path = ARGV[0] || "fonts.xlsx"
3159
-
3160
- Xlsxrb.write(output_path) do |wb|
3161
- # Font Families (using nested hash options)
3162
- wb.style("f_arial", font: { name: "Arial" })
3163
- wb.style("f_times", font: { name: "Times New Roman" })
3164
- wb.style("f_courier", font: { name: "Courier New" })
3165
- wb.style("f_georgia", font: { name: "Georgia" })
3166
- wb.style("f_tahoma", font: { name: "Tahoma" })
3167
-
3168
- # Font Sizes
3169
- wb.style("sz_10", font: { size: 10 })
3170
- wb.style("sz_16", font: { size: 16 })
3171
- wb.style("sz_24", font: { size: 24 })
3172
-
3173
- # Font Colors
3174
- wb.style("c_red", font: { color: "FFC00000" })
3175
- wb.style("c_green", font: { color: "FF008000" })
3176
- wb.style("c_blue", font: { color: :blue })
3177
-
3178
- # Font Styles
3179
- wb.style("bold", font: { bold: true })
3180
- wb.style("italic", font: { italic: true })
3181
- wb.style("underline", font: { underline: true })
3182
- wb.style("double_underline", font: { underline: "double" })
3183
- wb.style("strike", font: { strike: true })
3184
-
3185
- # Vertical Alignment (Subscript / Superscript)
3186
- wb.style("superscript", font: { vert_align: "superscript" })
3187
- wb.style("subscript", font: { vert_align: "subscript" })
3188
-
3189
- wb.style("header", font: { bold: true, color: :white }, fill: { color: "FF4F81BD" })
3190
- wb.style("bg_light", fill: { color: "FFDCE6F1" })
3191
-
3192
- wb.sheet("Fonts") do |s|
3193
- s.column(0, width: 25)
3194
- s.column(1, width: 35)
3195
-
3196
- s.row(["Font Feature", "Text Preview"], styles: "header")
3197
-
3198
- s.row(["Family: Arial", "Arial Text"], styles: %w[bg_light f_arial])
3199
- s.row(["Family: Times New Roman", "Times New Roman"], styles: [nil, "f_times"])
3200
- s.row(["Family: Courier New", "Courier New Text"], styles: %w[bg_light f_courier])
3201
- s.row(["Family: Georgia", "Georgia Text"], styles: [nil, "f_georgia"])
3202
- s.row(["Family: Tahoma", "Tahoma Text"], styles: %w[bg_light f_tahoma])
3203
-
3204
- s.row(["Size: 10pt", "10pt Font Size"], styles: [nil, "sz_10"])
3205
- s.row(["Size: 16pt", "16pt Font Size"], styles: %w[bg_light sz_16])
3206
- s.row(["Size: 24pt", "24pt Font Size"], styles: [nil, "sz_24"])
3207
-
3208
- s.row(["Color: Red", "Red Text"], styles: %w[bg_light c_red])
3209
- s.row(["Color: Green", "Green Text"], styles: [nil, "c_green"])
3210
- s.row(["Color: Blue", "Blue Text"], styles: %w[bg_light c_blue])
3211
-
3212
- s.row(["Style: Bold", "Bold Text"], styles: [nil, "bold"])
3213
- s.row(["Style: Italic", "Italic Text"], styles: %w[bg_light italic])
3214
- s.row(["Style: Underline", "Underline Text"], styles: [nil, "underline"])
3215
- s.row(["Style: Double Underline", "Double Underline"], styles: %w[bg_light double_underline])
3216
- s.row(["Style: Strike-through", "Strike-through Text"], styles: [nil, "strike"])
3217
-
3218
- s.row(["Align: Superscript", "x2 (2 is super)"], styles: %w[bg_light superscript])
3219
- s.row(["Align: Subscript", "H2O (2 is sub)"], styles: [nil, "subscript"])
3220
- end
3221
- end
3222
- puts "Created #{output_path}"
3223
- ```
3224
-
3225
- ### Console Output
3226
-
3227
- ```text
3228
- Created /workspaces/xlsxrb/docs/visual/files/fonts.xlsx
3229
- ```
3230
-
3231
- <hr/>
3232
-
3233
- ## Interactive Autofilter
3234
-
3235
- > [!TIP]
3236
- > **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!
3237
-
3238
- Demonstrates enabling auto-filter sorting headers on tables. Download the sheet to interactively filter and sort columns.
3239
-
3240
- ### Rendered Output (LibreOffice Calc)
3241
-
3242
- <div><img src="../../test/visual/baselines/interactive_autofilter/page-1.png" width="100%" alt="Preview"/></div>
3243
-
3244
- <div><img src="../../test/visual/support/illustrations/interactive_autofilter_page-2.png" width="100%" alt="Preview"/></div>
3245
-
3246
- ### DSL Code
3247
-
3248
- ```ruby
3249
- # frozen_string_literal: true
3250
-
3251
- require "xlsxrb"
3252
- output_path = ARGV[0] || "interactive_autofilter.xlsx"
3253
- Xlsxrb.write(output_path) do |wb|
3254
- wb.sheet("Filter") do |s|
3255
- s.column(0, width: 25)
3256
- s.column(1, width: 25)
3257
- s.row(%w[Name Department])
3258
- s.row(%w[Alice HR])
3259
- s.row(%w[Bob Eng])
3260
- s.auto_filter("A1:B3")
3261
- end
3262
- wb.defined_name("_xlnm._FilterDatabase", "Filter!$A$1:$B$3", sheet: "Filter", hidden: true)
3263
- end
3264
-
3265
- # 2. Read the generated sheet and print cell values
3266
- puts "=== Read Validation ==="
3267
- workbook = Xlsxrb.read(output_path).load
3268
- sheet = workbook.sheets.first
3269
- sheet.rows.first(5).each do |row|
3270
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
3271
- puts "Row #{row.index}: #{row_cells.join(", ")}"
3272
- end
3273
- ```
3274
-
3275
- ### Console Output
3276
-
3277
- ```text
3278
- === Read Validation ===
3279
- Row 0: A1: "Name", B1: "Department"
3280
- Row 1: A2: "Alice", B2: "HR"
3281
- Row 2: A3: "Bob", B3: "Eng"
3282
- ```
3283
-
3284
- <hr/>
3285
-
3286
- ## Interactive Comments
3287
-
3288
- > [!TIP]
3289
- > **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!
3290
-
3291
- 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.
3292
-
3293
- ### Rendered Output (LibreOffice Calc)
3294
-
3295
- <div><img src="../../test/visual/baselines/interactive_comments/page-1.png" width="100%" alt="Preview"/></div>
3296
-
3297
- <div><img src="../../test/visual/support/illustrations/interactive_comments_page-2.png" width="100%" alt="Preview"/></div>
3298
-
3299
- ### DSL Code
3300
-
3301
- ```ruby
3302
- # frozen_string_literal: true
3303
-
3304
- require "xlsxrb"
3305
- output_path = ARGV[0] || "interactive_comments.xlsx"
3306
- Xlsxrb.write(output_path) do |wb|
3307
- wb.sheet("Comments") do |s|
3308
- s.column(0, width: 25)
3309
- s.column(1, width: 25)
3310
- s.row(["Item A", "Item B"])
3311
- s.comment("A1", "This is an important comment.", author: "System")
3312
- end
3313
- end
3314
-
3315
- # 2. Read the generated sheet and print cell values
3316
- puts "=== Read Validation ==="
3317
- workbook = Xlsxrb.read(output_path).load
3318
- sheet = workbook.sheets.first
3319
- sheet.rows.first(5).each do |row|
3320
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
3321
- puts "Row #{row.index}: #{row_cells.join(", ")}"
3322
- end
3323
- ```
3324
-
3325
- ### Console Output
3326
-
3327
- ```text
3328
- === Read Validation ===
3329
- Row 0: A1: "Item A", B1: "Item B"
3330
- ```
3331
-
3332
- <hr/>
3333
-
3334
- ## Interactive Validation Custom
3335
-
3336
- > [!TIP]
3337
- > **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!
3338
-
3339
- Demonstrates interactive custom formula validation rules.
3340
-
3341
- ### Rendered Output (LibreOffice Calc)
3342
-
3343
- <div><img src="../../test/visual/baselines/interactive_validation_custom/page-1.png" width="100%" alt="Preview"/></div>
3344
-
3345
- <div><img src="../../test/visual/support/illustrations/interactive_validation_custom_page-2.png" width="100%" alt="Preview"/></div>
3346
-
3347
- ### DSL Code
3348
-
3349
- ```ruby
3350
- # frozen_string_literal: true
3351
-
3352
- require "xlsxrb"
3353
- output_path = ARGV[0] || "interactive_validation_custom.xlsx"
3354
- Xlsxrb.write(output_path) do |wb|
3355
- wb.sheet("Custom Rule") do |s|
3356
- s.column(0, width: 25)
3357
- s.column(1, width: 25)
3358
- s.row(["Number A", "Number B (Must be larger A)"])
3359
- s.row([10, ""])
3360
- 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")
3361
- end
3362
- end
3363
-
3364
- # 2. Read the generated sheet and print data validations
3365
- puts "=== Read Validation ==="
3366
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3367
- workbook = Xlsxrb.read(output_path).load
3368
- sheet = workbook.sheets.first
3369
- validations = reader.data_validations(sheet: sheet.name)
3370
- validations.each do |v|
3371
- puts "Validation range #{v[:sqref]}: type=#{v[:type]}, formula1=#{v[:formula1]}, formula2=#{v[:formula2]}"
3372
- end
3373
- ```
3374
-
3375
- ### Console Output
3376
-
3377
- ```text
3378
- === Read Validation ===
3379
- Validation range B2: type=custom, formula1=B2>A2, formula2=
3380
- ```
3381
-
3382
- <hr/>
3383
-
3384
- ## Interactive Validation Date
3385
-
3386
- > [!TIP]
3387
- > **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!
3388
-
3389
- Demonstrates interactive date range constraints validation rules.
3390
-
3391
- ### Rendered Output (LibreOffice Calc)
3392
-
3393
- <div><img src="../../test/visual/baselines/interactive_validation_date/page-1.png" width="100%" alt="Preview"/></div>
3394
-
3395
- <div><img src="../../test/visual/support/illustrations/interactive_validation_date_page-2.png" width="100%" alt="Preview"/></div>
3396
-
3397
- ### DSL Code
3398
-
3399
- ```ruby
3400
- # frozen_string_literal: true
3401
-
3402
- require "xlsxrb"
3403
- output_path = ARGV[0] || "interactive_validation_date.xlsx"
3404
- Xlsxrb.write(output_path) do |wb|
3405
- wb.sheet("Date Validation") do |s|
3406
- s.column(0, width: 25)
3407
- s.column(1, width: 25)
3408
- s.row(["Date Range", "Enter Date (2026):"])
3409
- 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")
3410
- end
3411
- end
3412
-
3413
- # 2. Read the generated sheet and print data validations
3414
- puts "=== Read Validation ==="
3415
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3416
- workbook = Xlsxrb.read(output_path).load
3417
- sheet = workbook.sheets.first
3418
- validations = reader.data_validations(sheet: sheet.name)
3419
- validations.each do |v|
3420
- puts "Validation range #{v[:sqref]}: type=#{v[:type]}, formula1=#{v[:formula1]}, formula2=#{v[:formula2]}"
3421
- end
3422
- ```
3423
-
3424
- ### Console Output
3425
-
3426
- ```text
3427
- === Read Validation ===
3428
- Validation range B2: type=date, formula1=Date(2026,1,1), formula2=Date(2026,12,31)
3429
- ```
3430
-
3431
- <hr/>
3432
-
3433
- ## Interactive Validation List
3434
-
3435
- > [!TIP]
3436
- > **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!
3437
-
3438
- Demonstrates dropdown list data validations. Open the sheet in Excel and select cell A1/A2 to see the dropdown list in action.
3439
-
3440
- ### Rendered Output (LibreOffice Calc)
3441
-
3442
- <div><img src="../../test/visual/baselines/interactive_validation_list/page-1.png" width="100%" alt="Preview"/></div>
3443
-
3444
- <div><img src="../../test/visual/support/illustrations/interactive_validation_list_page-2.png" width="100%" alt="Preview"/></div>
3445
-
3446
- ### DSL Code
3447
-
3448
- ```ruby
3449
- # frozen_string_literal: true
3450
-
3451
- require "xlsxrb"
3452
- output_path = ARGV[0] || "interactive_validation_list.xlsx"
3453
- Xlsxrb.write(output_path) do |wb|
3454
- wb.sheet("List Validation") do |s|
3455
- s.column(0, width: 25)
3456
- s.column(1, width: 25)
3457
- s.row(["Department", "Select:"])
3458
- s.validate_data("B2", in: %w[HR Sales Engineering])
3459
- end
3460
- end
3461
-
3462
- # 2. Read the generated sheet and print data validations
3463
- puts "=== Read Validation ==="
3464
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3465
- workbook = Xlsxrb.read(output_path).load
3466
- sheet = workbook.sheets.first
3467
- validations = reader.data_validations(sheet: sheet.name)
3468
- validations.each do |v|
3469
- puts "Validation range #{v[:sqref]}: type=#{v[:type]}, formula1=#{v[:formula1]}, formula2=#{v[:formula2]}"
3470
- end
3471
- ```
3472
-
3473
- ### Console Output
3474
-
3475
- ```text
3476
- === Read Validation ===
3477
- Validation range B2: type=list, formula1="HR,Sales,Engineering", formula2=
3478
- ```
3479
-
3480
- <hr/>
3481
-
3482
- ## Interactive Validation Range
3483
-
3484
- > [!TIP]
3485
- > **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!
3486
-
3487
- Demonstrates range constraints for whole number validations. Open the sheet in Excel and try entering a value outside 10-100 to trigger the warning.
3488
-
3489
- ### Rendered Output (LibreOffice Calc)
3490
-
3491
- <div><img src="../../test/visual/baselines/interactive_validation_range/page-1.png" width="100%" alt="Preview"/></div>
3492
-
3493
- <div><img src="../../test/visual/support/illustrations/interactive_validation_range_page-2.png" width="100%" alt="Preview"/></div>
3494
-
3495
- ### DSL Code
3496
-
3497
- ```ruby
3498
- # frozen_string_literal: true
3499
-
3500
- require "xlsxrb"
3501
- output_path = ARGV[0] || "interactive_validation_range.xlsx"
3502
- Xlsxrb.write(output_path) do |wb|
3503
- wb.sheet("Range Validation") do |s|
3504
- s.column(0, width: 25)
3505
- s.column(1, width: 25)
3506
- s.row(["Age", "Enter (18-99):"])
3507
- 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!")
3508
- end
3509
- end
3510
-
3511
- # 2. Read the generated sheet and print data validations
3512
- puts "=== Read Validation ==="
3513
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3514
- workbook = Xlsxrb.read(output_path).load
3515
- sheet = workbook.sheets.first
3516
- validations = reader.data_validations(sheet: sheet.name)
3517
- validations.each do |v|
3518
- puts "Validation range #{v[:sqref]}: type=#{v[:type]}, formula1=#{v[:formula1]}, formula2=#{v[:formula2]}"
3519
- end
3520
- ```
3521
-
3522
- ### Console Output
3523
-
3524
- ```text
3525
- === Read Validation ===
3526
- Validation range B2: type=whole, formula1=18, formula2=99
3527
- ```
3528
-
3529
- <hr/>
3530
-
3531
- ## Interactive Validation Text Length
3532
-
3533
- > [!TIP]
3534
- > **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!
3535
-
3536
- Demonstrates interactive text length validation rules.
3537
-
3538
- ### Rendered Output (LibreOffice Calc)
3539
-
3540
- <div><img src="../../test/visual/baselines/interactive_validation_text_length/page-1.png" width="100%" alt="Preview"/></div>
3541
-
3542
- <div><img src="../../test/visual/support/illustrations/interactive_validation_text_length_page-2.png" width="100%" alt="Preview"/></div>
3543
-
3544
- ### DSL Code
3545
-
3546
- ```ruby
3547
- # frozen_string_literal: true
3548
-
3549
- require "xlsxrb"
3550
- output_path = ARGV[0] || "interactive_validation_text_length.xlsx"
3551
- Xlsxrb.write(output_path) do |wb|
3552
- wb.sheet("Text Length") do |s|
3553
- s.column(0, width: 25)
3554
- s.column(1, width: 25)
3555
- s.row(["Username", "Enter (< 10 chars):"])
3556
- 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")
3557
- end
3558
- end
3559
-
3560
- # 2. Read the generated sheet and print data validations
3561
- puts "=== Read Validation ==="
3562
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3563
- workbook = Xlsxrb.read(output_path).load
3564
- sheet = workbook.sheets.first
3565
- validations = reader.data_validations(sheet: sheet.name)
3566
- validations.each do |v|
3567
- puts "Validation range #{v[:sqref]}: type=#{v[:type]}, formula1=#{v[:formula1]}, formula2=#{v[:formula2]}"
3568
- end
3569
- ```
3570
-
3571
- ### Console Output
3572
-
3573
- ```text
3574
- === Read Validation ===
3575
- Validation range B2: type=textLength, formula1=10, formula2=
3576
- ```
3577
-
3578
- <hr/>
3579
-
3580
- ## Interactive Validation Time
3581
-
3582
- > [!TIP]
3583
- > **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!
3584
-
3585
- Demonstrates interactive time validation rules.
3586
-
3587
- ### Rendered Output (LibreOffice Calc)
3588
-
3589
- <div><img src="../../test/visual/baselines/interactive_validation_time/page-1.png" width="100%" alt="Preview"/></div>
3590
-
3591
- <div><img src="../../test/visual/support/illustrations/interactive_validation_time_page-2.png" width="100%" alt="Preview"/></div>
3592
-
3593
- ### DSL Code
3594
-
3595
- ```ruby
3596
- # frozen_string_literal: true
3597
-
3598
- require "xlsxrb"
3599
- output_path = ARGV[0] || "interactive_validation_time.xlsx"
3600
- Xlsxrb.write(output_path) do |wb|
3601
- wb.sheet("Time Validation") do |s|
3602
- s.column(0, width: 25)
3603
- s.column(1, width: 25)
3604
- s.row(["Schedule", "Enter Time (after 08:00):"])
3605
- 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")
3606
- end
3607
- end
3608
-
3609
- # 2. Read the generated sheet and print data validations
3610
- puts "=== Read Validation ==="
3611
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3612
- workbook = Xlsxrb.read(output_path).load
3613
- sheet = workbook.sheets.first
3614
- validations = reader.data_validations(sheet: sheet.name)
3615
- validations.each do |v|
3616
- puts "Validation range #{v[:sqref]}: type=#{v[:type]}, formula1=#{v[:formula1]}, formula2=#{v[:formula2]}"
3617
- end
3618
- ```
3619
-
3620
- ### Console Output
3621
-
3622
- ```text
3623
- === Read Validation ===
3624
- Validation range B2: type=time, formula1=0.33333, formula2=
3625
- ```
3626
-
3627
- <hr/>
3628
-
3629
- ## Japanese Text
3630
-
3631
- Demonstrates writing multi-byte Japanese text and setting appropriate Japanese font names (e.g., Noto Sans CJK JP).
3632
-
3633
- ### Rendered Output (LibreOffice Calc)
3634
-
3635
- <div><img src="../../test/visual/baselines/japanese_text/page-1.png" width="100%" alt="Preview"/></div>
3636
-
3637
- ### DSL Code
3638
-
3639
- ```ruby
3640
- # frozen_string_literal: true
3641
-
3642
- require "xlsxrb"
3643
-
3644
- output_path = ARGV[0] || "japanese_text.xlsx"
3645
-
3646
- Xlsxrb.write(output_path) do |wb|
3647
- wb.style("ja_font") do |style|
3648
- style.font_name("Noto Sans CJK JP").size(12)
3649
- end
3650
-
3651
- wb.sheet("Japanese") do |s|
3652
- s.column(0, width: 25)
3653
- s.column(1, width: 25)
3654
- s.row(%w[日本語ラベル 値], styles: { 0 => "ja_font", 1 => "ja_font" })
3655
- s.row(["売上", 12_500], styles: { 0 => "ja_font" })
3656
- end
3657
- end
3658
-
3659
- # 2. Read the generated sheet and print parsed cell values and Ruby classes
3660
- puts "=== Read Validation ==="
3661
- workbook = Xlsxrb.read(output_path).load
3662
- sheet = workbook.sheets.first
3663
- sheet.rows.each do |row|
3664
- row_cells = row.cells.map do |c|
3665
- "#{c.ref}: #{c.value.inspect} (#{c.value.class})"
3666
- end
3667
- puts "Row #{row.index}: #{row_cells.join(", ")}"
3668
- end
3669
- ```
3670
-
3671
- ### Console Output
3672
-
3673
- ```text
3674
- === Read Validation ===
3675
- Row 0: A1: "日本語ラベル" (String), B1: "値" (String)
3676
- Row 1: A2: "売上" (String), B2: 12500 (Integer)
3677
- ```
3678
-
3679
- <hr/>
3680
-
3681
- ## Merge Freeze
3682
-
3683
- Demonstrates merging a cell range into a single cell, and freezing the top rows of a sheet.
3684
-
3685
- ### Rendered Output (LibreOffice Calc)
3686
-
3687
- <div><img src="../../test/visual/baselines/merge_freeze/page-1.png" width="100%" alt="Preview"/></div>
3688
-
3689
- ### DSL Code
3690
-
3691
- ```ruby
3692
- # frozen_string_literal: true
3693
-
3694
- require "xlsxrb"
3695
-
3696
- output_path = ARGV[0] || "merge_freeze.xlsx"
3697
-
3698
- Xlsxrb.write(output_path) do |wb|
3699
- wb.style("title") { |style| style.border_all(style: "thin", color: "FF000000").align_horizontal("center") }
3700
- wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
3701
- wb.sheet("Merge & Freeze") do |s|
3702
- s.sheet_properties(:fit_to_page, true)
3703
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
3704
- s.column(0, width: 25)
3705
- s.column(1, width: 25)
3706
- s.column(2, width: 25)
3707
- s.row(["Merged Title Row", nil, nil], styles: %w[title title title])
3708
- s.row(["Header A", "Header B", "Header C"], styles: %w[border border border])
3709
- s.row(["Row 1 Col A", "Row 1 Col B", "Row 1 Col C"], styles: %w[border border border])
3710
- s.row(["Row 2 Col A", "Row 2 Col B", "Row 2 Col C"], styles: %w[border border border])
3711
-
3712
- s.merge(row: 0, col_start: 0, col_end: 2)
3713
- s.freeze_pane(row: 2, col: 0)
3714
- end
3715
- end
3716
-
3717
- # 2. Read the generated sheet and print cell values
3718
- puts "=== Read Validation ==="
3719
- workbook = Xlsxrb.read(output_path).load
3720
- sheet = workbook.sheets.first
3721
- sheet.rows.first(5).each do |row|
3722
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
3723
- puts "Row #{row.index}: #{row_cells.join(", ")}"
3724
- end
3725
- ```
3726
-
3727
- ### Console Output
3728
-
3729
- ```text
3730
- === Read Validation ===
3731
- Row 0: A1: "Merged Title Row", B1: nil, C1: nil
3732
- Row 1: A2: "Header A", B2: "Header B", C2: "Header C"
3733
- Row 2: A3: "Row 1 Col A", B3: "Row 1 Col B", C3: "Row 1 Col C"
3734
- Row 3: A4: "Row 2 Col A", B4: "Row 2 Col B", C4: "Row 2 Col C"
3735
- ```
3736
-
3737
- <hr/>
3738
-
3739
- ## Page Grid Lines Print
3740
-
3741
- Demonstrates enabling printing of grid lines.
3742
-
3743
- ### Rendered Output (LibreOffice Calc)
3744
-
3745
- <div><img src="../../test/visual/baselines/page_grid_lines_print/page-1.png" width="100%" alt="Preview"/></div>
3746
-
3747
- ### DSL Code
3748
-
3749
- ```ruby
3750
- # frozen_string_literal: true
3751
-
3752
- require "xlsxrb"
3753
- output_path = ARGV[0] || "page_grid_lines_print.xlsx"
3754
- Xlsxrb.write(output_path) do |wb|
3755
- wb.sheet("Print Grid Lines") do |s|
3756
- s.column(0, width: 25)
3757
- s.column(1, width: 25)
3758
- s.print_options(:grid_lines, true)
3759
- s.row(["Grid Lines Printed sheet"])
3760
- end
3761
- end
3762
-
3763
- # 2. Read the generated sheet and print page setup properties
3764
- puts "=== Read Validation ==="
3765
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3766
- workbook = Xlsxrb.read(output_path).load
3767
- sheet = workbook.sheets.first
3768
- margins = reader.page_margins(sheet: sheet.name)
3769
- setup = reader.page_setup(sheet: sheet.name)
3770
- opts = reader.print_options(sheet: sheet.name)
3771
- puts "Page Margins: #{margins.inspect}"
3772
- puts "Page Setup: #{setup.inspect}"
3773
- puts "Print Options: #{opts.inspect}"
3774
- ```
3775
-
3776
- ### Console Output
3777
-
3778
- ```text
3779
- === Read Validation ===
3780
- Page Margins: nil
3781
- Page Setup: {}
3782
- Print Options: {grid_lines: true}
3783
- ```
3784
-
3785
- <hr/>
3786
-
3787
- ## Page Header Footer
3788
-
3789
- Demonstrates setting odd page headers and footers.
3790
-
3791
- ### Rendered Output (LibreOffice Calc)
3792
-
3793
- <div><img src="../../test/visual/baselines/page_header_footer/page-1.png" width="100%" alt="Preview"/></div>
3794
-
3795
- ### DSL Code
3796
-
3797
- ```ruby
3798
- # frozen_string_literal: true
3799
-
3800
- require "xlsxrb"
3801
- output_path = ARGV[0] || "page_header_footer.xlsx"
3802
- Xlsxrb.write(output_path) do |wb|
3803
- wb.sheet("Header Footer") do |s|
3804
- s.column(0, width: 25)
3805
- s.column(1, width: 25)
3806
- s.header_footer(odd_header: "&LMy Company&RPage &P", odd_footer: "&CConfidential")
3807
- s.row(["Header Footer sheet"])
3808
- end
3809
- end
3810
-
3811
- # 2. Read the generated sheet and print page setup properties
3812
- puts "=== Read Validation ==="
3813
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3814
- workbook = Xlsxrb.read(output_path).load
3815
- sheet = workbook.sheets.first
3816
- margins = reader.page_margins(sheet: sheet.name)
3817
- setup = reader.page_setup(sheet: sheet.name)
3818
- opts = reader.print_options(sheet: sheet.name)
3819
- puts "Page Margins: #{margins.inspect}"
3820
- puts "Page Setup: #{setup.inspect}"
3821
- puts "Print Options: #{opts.inspect}"
3822
- ```
3823
-
3824
- ### Console Output
3825
-
3826
- ```text
3827
- === Read Validation ===
3828
- Page Margins: nil
3829
- Page Setup: {}
3830
- Print Options: {}
3831
- ```
3832
-
3833
- <hr/>
3834
-
3835
- ## Page Headings Print
3836
-
3837
- Demonstrates enabling printing of row and column headings.
3838
-
3839
- ### Rendered Output (LibreOffice Calc)
3840
-
3841
- <div><img src="../../test/visual/baselines/page_headings_print/page-1.png" width="100%" alt="Preview"/></div>
3842
-
3843
- ### DSL Code
3844
-
3845
- ```ruby
3846
- # frozen_string_literal: true
3847
-
3848
- require "xlsxrb"
3849
- output_path = ARGV[0] || "page_headings_print.xlsx"
3850
- Xlsxrb.write(output_path) do |wb|
3851
- wb.sheet("Print Headings") do |s|
3852
- s.column(0, width: 25)
3853
- s.column(1, width: 25)
3854
- s.print_options(:headings, true)
3855
- s.row(["Row/Col Headings Printed sheet"])
3856
- end
3857
- end
3858
-
3859
- # 2. Read the generated sheet and print page setup properties
3860
- puts "=== Read Validation ==="
3861
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3862
- workbook = Xlsxrb.read(output_path).load
3863
- sheet = workbook.sheets.first
3864
- margins = reader.page_margins(sheet: sheet.name)
3865
- setup = reader.page_setup(sheet: sheet.name)
3866
- opts = reader.print_options(sheet: sheet.name)
3867
- puts "Page Margins: #{margins.inspect}"
3868
- puts "Page Setup: #{setup.inspect}"
3869
- puts "Print Options: #{opts.inspect}"
3870
- ```
3871
-
3872
- ### Console Output
3873
-
3874
- ```text
3875
- === Read Validation ===
3876
- Page Margins: nil
3877
- Page Setup: {}
3878
- Print Options: {headings: true}
3879
- ```
3880
-
3881
- <hr/>
3882
-
3883
- ## Page Margins Narrow
3884
-
3885
- Demonstrates setting narrow page margins.
3886
-
3887
- ### Rendered Output (LibreOffice Calc)
3888
-
3889
- <div><img src="../../test/visual/baselines/page_margins_narrow/page-1.png" width="100%" alt="Preview"/></div>
3890
-
3891
- ### DSL Code
3892
-
3893
- ```ruby
3894
- # frozen_string_literal: true
3895
-
3896
- require "xlsxrb"
3897
- output_path = ARGV[0] || "page_margins_narrow.xlsx"
3898
- Xlsxrb.write(output_path) do |wb|
3899
- wb.sheet("Narrow Margins") do |s|
3900
- s.column(0, width: 25)
3901
- s.column(1, width: 25)
3902
- s.page_margins(top: 0.25, bottom: 0.25, left: 0.25, right: 0.25, header: 0.1, footer: 0.1)
3903
- s.row(["Narrow Margins sheet"])
3904
- end
3905
- end
3906
-
3907
- # 2. Read the generated sheet and print page setup properties
3908
- puts "=== Read Validation ==="
3909
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3910
- workbook = Xlsxrb.read(output_path).load
3911
- sheet = workbook.sheets.first
3912
- margins = reader.page_margins(sheet: sheet.name)
3913
- setup = reader.page_setup(sheet: sheet.name)
3914
- opts = reader.print_options(sheet: sheet.name)
3915
- puts "Page Margins: #{margins.inspect}"
3916
- puts "Page Setup: #{setup.inspect}"
3917
- puts "Print Options: #{opts.inspect}"
3918
- ```
3919
-
3920
- ### Console Output
3921
-
3922
- ```text
3923
- === Read Validation ===
3924
- Page Margins: {left: 0.25, right: 0.25, top: 0.25, bottom: 0.25, header: 0.1, footer: 0.1}
3925
- Page Setup: {}
3926
- Print Options: {}
3927
- ```
3928
-
3929
- <hr/>
3930
-
3931
- ## Page Margins Wide
3932
-
3933
- Demonstrates setting wide page margins.
3934
-
3935
- ### Rendered Output (LibreOffice Calc)
3936
-
3937
- <div><img src="../../test/visual/baselines/page_margins_wide/page-1.png" width="100%" alt="Preview"/></div>
3938
-
3939
- ### DSL Code
3940
-
3941
- ```ruby
3942
- # frozen_string_literal: true
3943
-
3944
- require "xlsxrb"
3945
- output_path = ARGV[0] || "page_margins_wide.xlsx"
3946
- Xlsxrb.write(output_path) do |wb|
3947
- wb.sheet("Wide Margins") do |s|
3948
- s.column(0, width: 25)
3949
- s.column(1, width: 25)
3950
- s.page_margins(top: 1.0, bottom: 1.0, left: 1.0, right: 1.0, header: 0.5, footer: 0.5)
3951
- s.row(["Wide Margins sheet"])
3952
- end
3953
- end
3954
-
3955
- # 2. Read the generated sheet and print page setup properties
3956
- puts "=== Read Validation ==="
3957
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
3958
- workbook = Xlsxrb.read(output_path).load
3959
- sheet = workbook.sheets.first
3960
- margins = reader.page_margins(sheet: sheet.name)
3961
- setup = reader.page_setup(sheet: sheet.name)
3962
- opts = reader.print_options(sheet: sheet.name)
3963
- puts "Page Margins: #{margins.inspect}"
3964
- puts "Page Setup: #{setup.inspect}"
3965
- puts "Print Options: #{opts.inspect}"
3966
- ```
3967
-
3968
- ### Console Output
3969
-
3970
- ```text
3971
- === Read Validation ===
3972
- Page Margins: {left: 1.0, right: 1.0, top: 1.0, bottom: 1.0, header: 0.5, footer: 0.5}
3973
- Page Setup: {}
3974
- Print Options: {}
3975
- ```
3976
-
3977
- <hr/>
3978
-
3979
- ## Page Orientation Landscape
3980
-
3981
- Demonstrates landscape page setup for printing.
3982
-
3983
- ### Rendered Output (LibreOffice Calc)
3984
-
3985
- <div><img src="../../test/visual/baselines/page_orientation_landscape/page-1.png" width="100%" alt="Preview"/></div>
3986
-
3987
- ### DSL Code
3988
-
3989
- ```ruby
3990
- # frozen_string_literal: true
3991
-
3992
- require "xlsxrb"
3993
- output_path = ARGV[0] || "page_orientation_landscape.xlsx"
3994
- Xlsxrb.write(output_path) do |wb|
3995
- wb.sheet("Landscape") do |s|
3996
- s.column(0, width: 25)
3997
- s.column(1, width: 25)
3998
- s.page_setup(orientation: :landscape)
3999
- s.row(["Landscape Orientation sheet"])
4000
- end
4001
- end
4002
-
4003
- # 2. Read the generated sheet and print page setup properties
4004
- puts "=== Read Validation ==="
4005
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
4006
- workbook = Xlsxrb.read(output_path).load
4007
- sheet = workbook.sheets.first
4008
- margins = reader.page_margins(sheet: sheet.name)
4009
- setup = reader.page_setup(sheet: sheet.name)
4010
- opts = reader.print_options(sheet: sheet.name)
4011
- puts "Page Margins: #{margins.inspect}"
4012
- puts "Page Setup: #{setup.inspect}"
4013
- puts "Print Options: #{opts.inspect}"
4014
- ```
4015
-
4016
- ### Console Output
4017
-
4018
- ```text
4019
- === Read Validation ===
4020
- Page Margins: nil
4021
- Page Setup: {orientation: "landscape"}
4022
- Print Options: {}
4023
- ```
4024
-
4025
- <hr/>
4026
-
4027
- ## Page Paper Size A3
4028
-
4029
- Demonstrates setting paper size to A3 (paper size 8).
4030
-
4031
- ### Rendered Output (LibreOffice Calc)
4032
-
4033
- <div><img src="../../test/visual/baselines/page_paper_size_a3/page-1.png" width="100%" alt="Preview"/></div>
4034
-
4035
- ### DSL Code
4036
-
4037
- ```ruby
4038
- # frozen_string_literal: true
4039
-
4040
- require "xlsxrb"
4041
- output_path = ARGV[0] || "page_paper_size_a3.xlsx"
4042
- Xlsxrb.write(output_path) do |wb|
4043
- wb.sheet("A3 Sheet") do |s|
4044
- s.column(0, width: 25)
4045
- s.column(1, width: 25)
4046
- s.page_setup(paper_size: 8) # ISO A3 is paperSize="8"
4047
- s.row(["ISO A3 Paper Size sheet"])
4048
- end
4049
- end
4050
-
4051
- # 2. Read the generated sheet and print page setup properties
4052
- puts "=== Read Validation ==="
4053
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
4054
- workbook = Xlsxrb.read(output_path).load
4055
- sheet = workbook.sheets.first
4056
- margins = reader.page_margins(sheet: sheet.name)
4057
- setup = reader.page_setup(sheet: sheet.name)
4058
- opts = reader.print_options(sheet: sheet.name)
4059
- puts "Page Margins: #{margins.inspect}"
4060
- puts "Page Setup: #{setup.inspect}"
4061
- puts "Print Options: #{opts.inspect}"
4062
- ```
4063
-
4064
- ### Console Output
4065
-
4066
- ```text
4067
- === Read Validation ===
4068
- Page Margins: nil
4069
- Page Setup: {paper_size: 8}
4070
- Print Options: {}
4071
- ```
4072
-
4073
- <hr/>
4074
-
4075
- ## Pivot Table
4076
-
4077
- Visual demonstration for Pivot Table.
4078
-
4079
- ### Rendered Output (LibreOffice Calc)
4080
-
4081
- <div><img src="../../test/visual/baselines/pivot_table/page-1.png" width="100%" alt="Preview"/></div>
4082
-
4083
- ### DSL Code
4084
-
4085
- ```ruby
4086
- # frozen_string_literal: true
4087
-
4088
- require "xlsxrb"
4089
-
4090
- output_path = ARGV[0] || "pivot_table.xlsx"
4091
-
4092
- Xlsxrb.write(output_path) do |wb|
4093
- wb.sheet("SalesData") do |sheet|
4094
- sheet.column(0..3, width: 14)
4095
- sheet.row(%w[Region Quarter Sales Rep])
4096
- sheet.row(["East", "Q1", 1000, "Alice"])
4097
- sheet.row(["West", "Q1", 1500, "Bob"])
4098
- sheet.row(["East", "Q2", 1200, "Alice"])
4099
- sheet.row(["West", "Q2", 1800, "Bob"])
4100
- sheet.row(["North", "Q1", 800, "Charlie"])
4101
- sheet.row(["North", "Q2", 950, "Charlie"])
4102
-
4103
- sheet.row([])
4104
- sheet.row([])
4105
- # Pre-populate summary cells in the pivot table target region (A10:D15) for headless renderers
4106
- sheet.row(["Sum of Sales", "Quarter", nil, nil])
4107
- sheet.row(["Region", "Q1", "Q2", "Grand Total"])
4108
- sheet.row(["East", 1000, 1200, 2200])
4109
- sheet.row(["North", 800, 950, 1750])
4110
- sheet.row(["West", 1500, 1800, 3300])
4111
- sheet.row(["Grand Total", 3300, 3950, 7250])
4112
-
4113
- sheet.pivot_table(
4114
- "SalesData!A1:D7",
4115
- row_fields: ["Region"],
4116
- data_fields: [{ name: "Sales", subtotal: "sum" }],
4117
- col_fields: ["Quarter"],
4118
- dest_ref: "A10",
4119
- name: "RegionalSalesSummary"
4120
- )
4121
- end
4122
- end
4123
-
4124
- puts "=== Read Validation ==="
4125
- workbook = Xlsxrb.read(output_path).load
4126
- sheet = workbook.sheets.first
4127
- sheet.rows.each do |row|
4128
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
4129
- puts "Row #{row.index}: #{row_cells.join(", ")}"
4130
- end
4131
- ```
4132
-
4133
- ### Console Output
4134
-
4135
- ```text
4136
- === Read Validation ===
4137
- Row 0: A1: "Region", B1: "Quarter", C1: "Sales", D1: "Rep"
4138
- Row 1: A2: "East", B2: "Q1", C2: 1000, D2: "Alice"
4139
- Row 2: A3: "West", B3: "Q1", C3: 1500, D3: "Bob"
4140
- Row 3: A4: "East", B4: "Q2", C4: 1200, D4: "Alice"
4141
- Row 4: A5: "West", B5: "Q2", C5: 1800, D5: "Bob"
4142
- Row 5: A6: "North", B6: "Q1", C6: 800, D6: "Charlie"
4143
- Row 6: A7: "North", B7: "Q2", C7: 950, D7: "Charlie"
4144
- Row 7:
4145
- Row 8:
4146
- Row 9: A10: "Sum of Sales", B10: "Quarter"
4147
- Row 10: A11: "Region", B11: "Q1", C11: "Q2", D11: "Grand Total"
4148
- Row 11: A12: "East", B12: 1000, C12: 1200, D12: 2200
4149
- Row 12: A13: "North", B13: 800, C13: 950, D13: 1750
4150
- Row 13: A14: "West", B14: 1500, C14: 1800, D14: 3300
4151
- Row 14: A15: "Grand Total", B15: 3300, C15: 3950, D15: 7250
4152
- ```
4153
-
4154
- <hr/>
4155
-
4156
- ## Row Grouping
4157
-
4158
- Demonstrates outline grouping for rows.
4159
-
4160
- ### Rendered Output (LibreOffice Calc)
4161
-
4162
- <div><img src="../../test/visual/baselines/row_grouping/page-1.png" width="100%" alt="Preview"/></div>
4163
-
4164
- ### DSL Code
4165
-
4166
- ```ruby
4167
- # frozen_string_literal: true
4168
-
4169
- require "xlsxrb"
4170
- output_path = ARGV[0] || "row_grouping.xlsx"
4171
- Xlsxrb.write(output_path) do |wb|
4172
- wb.style("parent") { |style| style.border_all(style: "thin", color: "FF000000").bold }
4173
- wb.style("child") { |style| style.border_all(style: "thin", color: "FF000000").align_horizontal("left").indent(2) }
4174
- wb.sheet("Row Grouping") do |s|
4175
- s.column(0, width: 25)
4176
- s.column(1, width: 25)
4177
- s.row(["Parent Row 1", ""], styles: %w[parent parent])
4178
- s.row(["Child Row 1.1", ""], outline_level: 1, styles: %w[child child])
4179
- s.row(["Child Row 1.2", ""], outline_level: 1, styles: %w[child child])
4180
- end
4181
- end
4182
-
4183
- # 2. Read the generated sheet and print row attributes
4184
- puts "=== Read Validation ==="
4185
- workbook = Xlsxrb.read(output_path).load
4186
- sheet = workbook.sheets.first
4187
- sheet.rows.each do |row|
4188
- puts "Row #{row.index}: height=#{row.height}, hidden=#{row.hidden}, outline_level=#{row.outline_level}"
4189
- end
4190
- ```
4191
-
4192
- ### Console Output
4193
-
4194
- ```text
4195
- === Read Validation ===
4196
- Row 0: height=, hidden=false, outline_level=
4197
- Row 1: height=, hidden=false, outline_level=1
4198
- Row 2: height=, hidden=false, outline_level=1
4199
- ```
4200
-
4201
- <hr/>
4202
-
4203
- ## Row Height Tall
4204
-
4205
- Demonstrates setting very tall row heights.
4206
-
4207
- ### Rendered Output (LibreOffice Calc)
4208
-
4209
- <div><img src="../../test/visual/baselines/row_height_tall/page-1.png" width="100%" alt="Preview"/></div>
4210
-
4211
- ### DSL Code
4212
-
4213
- ```ruby
4214
- # frozen_string_literal: true
4215
-
4216
- require "xlsxrb"
4217
- output_path = ARGV[0] || "row_height_tall.xlsx"
4218
- Xlsxrb.write(output_path) do |wb|
4219
- wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
4220
- wb.sheet("Row Height") do |s|
4221
- s.column(0, width: 25)
4222
- s.column(1, width: 25)
4223
- s.row(["Very Tall Row (Height 60)", ""], height: 60, styles: %w[border border])
4224
- s.row(["Normal Row", ""], styles: %w[border border])
4225
- end
4226
- end
4227
-
4228
- # 2. Read the generated sheet and print row attributes
4229
- puts "=== Read Validation ==="
4230
- workbook = Xlsxrb.read(output_path).load
4231
- sheet = workbook.sheets.first
4232
- sheet.rows.each do |row|
4233
- puts "Row #{row.index}: height=#{row.height}, hidden=#{row.hidden}, outline_level=#{row.outline_level}"
4234
- end
4235
- ```
4236
-
4237
- ### Console Output
4238
-
4239
- ```text
4240
- === Read Validation ===
4241
- Row 0: height=60.0, hidden=false, outline_level=
4242
- Row 1: height=, hidden=false, outline_level=
4243
- ```
4244
-
4245
- <hr/>
4246
-
4247
- ## Row Heights
4248
-
4249
- Demonstrates setting custom row heights.
4250
-
4251
- ### Rendered Output (LibreOffice Calc)
4252
-
4253
- <div><img src="../../test/visual/baselines/row_heights/page-1.png" width="100%" alt="Preview"/></div>
4254
-
4255
- ### DSL Code
4256
-
4257
- ```ruby
4258
- # frozen_string_literal: true
4259
-
4260
- require "xlsxrb"
4261
- output_path = ARGV[0] || "row_heights.xlsx"
4262
- Xlsxrb.write(output_path) do |wb|
4263
- wb.style("border") { |style| style.border_all(style: "thin", color: "FF000000") }
4264
- wb.sheet("Heights") do |s|
4265
- s.column(0, width: 25)
4266
- s.column(1, width: 25)
4267
- s.row(["Normal Row", ""], styles: %w[border border])
4268
- s.row(["Tall Row", ""], height: 40, styles: %w[border border])
4269
- end
4270
- end
4271
-
4272
- # 2. Read the generated sheet and print row attributes
4273
- puts "=== Read Validation ==="
4274
- workbook = Xlsxrb.read(output_path).load
4275
- sheet = workbook.sheets.first
4276
- sheet.rows.each do |row|
4277
- puts "Row #{row.index}: height=#{row.height}, hidden=#{row.hidden}, outline_level=#{row.outline_level}"
4278
- end
4279
- ```
4280
-
4281
- ### Console Output
4282
-
4283
- ```text
4284
- === Read Validation ===
4285
- Row 0: height=, hidden=false, outline_level=
4286
- Row 1: height=40.0, hidden=false, outline_level=
4287
- ```
4288
-
4289
- <hr/>
4290
-
4291
- ## Sheet Tab Colors
4292
-
4293
- Demonstrates customizing tab colors of individual worksheets.
4294
-
4295
- ### Rendered Output (LibreOffice Calc)
4296
-
4297
- <div><img src="../../test/visual/baselines/sheet_tab_colors/page-1.png" width="100%" alt="Preview"/></div>
4298
-
4299
- <div><img src="../../test/visual/baselines/sheet_tab_colors/page-2.png" width="100%" alt="Preview"/></div>
4300
-
4301
- <div><img src="../../test/visual/support/illustrations/sheet_tab_colors_page-2.png" width="100%" alt="Preview"/></div>
4302
-
4303
- ### DSL Code
4304
-
4305
- ```ruby
4306
- # frozen_string_literal: true
4307
-
4308
- require "xlsxrb"
4309
- output_path = ARGV[0] || "sheet_tab_colors.xlsx"
4310
- Xlsxrb.write(output_path) do |wb|
4311
- wb.sheet("Red Tab") do |s|
4312
- s.column(0, width: 25)
4313
- s.column(1, width: 25)
4314
- s.sheet_properties(:tab_color, :red)
4315
- s.row(["Red tab sheet"])
4316
- end
4317
- wb.sheet("Green Tab") do |s|
4318
- s.sheet_properties(:tab_color, :green)
4319
- s.row(["Green tab sheet"])
4320
- end
4321
- end
4322
-
4323
- # 2. Read the generated sheet and print sheet properties
4324
- puts "=== Read Validation ==="
4325
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
4326
- workbook = Xlsxrb.read(output_path).load
4327
- workbook.sheet_names.each do |s_name|
4328
- props = reader.sheet_properties(sheet: s_name)
4329
- puts "Sheet: #{s_name}, tab color: #{props[:tab_color].inspect}"
4330
- end
4331
- ```
4332
-
4333
- ### Console Output
4334
-
4335
- ```text
4336
- === Read Validation ===
4337
- Sheet: Red Tab, tab color: "red"
4338
- Sheet: Green Tab, tab color: "green"
4339
- ```
4340
-
4341
- <hr/>
4342
-
4343
- ## Sparkline Column
4344
-
4345
- Demonstrates embedded column sparklines in cell ranges.
4346
-
4347
- ### Rendered Output (LibreOffice Calc)
4348
-
4349
- <div><img src="../../test/visual/baselines/sparkline_column/page-1.png" width="100%" alt="Preview"/></div>
4350
-
4351
- ### DSL Code
4352
-
4353
- ```ruby
4354
- # frozen_string_literal: true
4355
-
4356
- require "xlsxrb"
4357
- output_path = ARGV[0] || "sparkline_column.xlsx"
4358
- Xlsxrb.write(output_path) do |wb|
4359
- wb.sheet("Sparkline") do |s|
4360
- s.sheet_properties(:fit_to_page, true)
4361
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
4362
- s.column(0, width: 25)
4363
- s.column(1, width: 25)
4364
- s.row([5, 12, 8, 15, nil])
4365
- s.sparkline_group(
4366
- type: :column,
4367
- sparklines: [{ location_ref: "E1", data_ref: "Sparkline!A1:D1" }]
4368
- )
4369
- end
4370
- end
4371
-
4372
- # 2. Read the generated sheet and print cell values
4373
- puts "=== Read Validation ==="
4374
- workbook = Xlsxrb.read(output_path).load
4375
- sheet = workbook.sheets.first
4376
- sheet.rows.first(3).each do |row|
4377
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
4378
- puts "Row #{row.index}: #{row_cells.join(", ")}"
4379
- end
4380
- ```
4381
-
4382
- ### Console Output
4383
-
4384
- ```text
4385
- === Read Validation ===
4386
- Row 0: A1: 5, B1: 12, C1: 8, D1: 15
4387
- ```
4388
-
4389
- <hr/>
4390
-
4391
- ## Sparkline Line
4392
-
4393
- Demonstrates embedded line sparklines in cell ranges.
4394
-
4395
- ### Rendered Output (LibreOffice Calc)
4396
-
4397
- <div><img src="../../test/visual/baselines/sparkline_line/page-1.png" width="100%" alt="Preview"/></div>
4398
-
4399
- <div><img src="../../test/visual/support/illustrations/sparkline_line_page-2.png" width="100%" alt="Preview"/></div>
4400
-
4401
- ### DSL Code
4402
-
4403
- ```ruby
4404
- # frozen_string_literal: true
4405
-
4406
- require "xlsxrb"
4407
- output_path = ARGV[0] || "sparkline_line.xlsx"
4408
- Xlsxrb.write(output_path) do |wb|
4409
- wb.sheet("Sparkline") do |s|
4410
- s.sheet_properties(:fit_to_page, true)
4411
- s.page_setup(fit_to_width: 1, fit_to_height: 1)
4412
- s.column(0, width: 25)
4413
- s.column(1, width: 25)
4414
- s.row([10, 20, 15, 30, nil])
4415
- s.sparkline_group(
4416
- type: :line,
4417
- markers: true,
4418
- color_series: "FF000000",
4419
- color_markers: :red,
4420
- sparklines: [{ location_ref: "E1", data_ref: "Sparkline!A1:D1" }]
4421
- )
4422
- end
4423
- end
4424
-
4425
- # 2. Read the generated sheet and print cell values
4426
- puts "=== Read Validation ==="
4427
- workbook = Xlsxrb.read(output_path).load
4428
- sheet = workbook.sheets.first
4429
- sheet.rows.first(3).each do |row|
4430
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
4431
- puts "Row #{row.index}: #{row_cells.join(", ")}"
4432
- end
4433
- ```
4434
-
4435
- ### Console Output
4436
-
4437
- ```text
4438
- === Read Validation ===
4439
- Row 0: A1: 10, B1: 20, C1: 15, D1: 30
4440
- ```
4441
-
4442
- <hr/>
4443
-
4444
- ## Styles Fonts Fills
4445
-
4446
- Demonstrates cell formatting, including custom font sizing, bold/italic text, custom text colors, and background fill colors.
4447
-
4448
- ### Rendered Output (LibreOffice Calc)
4449
-
4450
- <div><img src="../../test/visual/baselines/styles_fonts_fills/page-1.png" width="100%" alt="Preview"/></div>
4451
-
4452
- ### DSL Code
4453
-
4454
- ```ruby
4455
- # frozen_string_literal: true
4456
-
4457
- require "xlsxrb"
4458
-
4459
- output_path = ARGV[0] || "styles_fonts_fills.xlsx"
4460
-
4461
- Xlsxrb.write(output_path) do |wb|
4462
- wb.style("header") do |style|
4463
- style.bold.size(14).font_color("FFFFFFFF").fill_color("FF4F81BD")
4464
- end
4465
-
4466
- wb.style("highlight") do |style|
4467
- style.italic.font_color("FFC00000").fill_color("FFFFFF00")
4468
- end
4469
-
4470
- wb.sheet("Styles") do |sheet|
4471
- sheet.column(0, width: 25)
4472
- sheet.column(1, width: 25)
4473
- sheet.row(["Header 1", "Header 2"], styles: { 0 => "header", 1 => "header" })
4474
- sheet.row(["Normal Text", "Highlighted Text"], styles: { 1 => "highlight" })
4475
- end
4476
- end
4477
-
4478
- # 2. Read the generated sheet and print styling details
4479
- puts "=== Read Validation ==="
4480
- workbook = Xlsxrb.read(output_path).load
4481
- sheet = workbook.sheets.first
4482
- sheet.rows.first(4).each do |row|
4483
- row_cells = row.cells.map do |c|
4484
- xf = workbook.styles[:cell_xfs][c.style_index] if c.style_index
4485
- font = xf ? workbook.styles[:fonts][xf[:font_id]] : nil
4486
- fill = xf ? workbook.styles[:fills][xf[:fill_id]] : nil
4487
- "#{c.ref}: #{c.value.inspect} (font=#{font&.[](:name)}, fill=#{fill&.[](:fg_color)&.[](:rgb)})"
4488
- end
4489
- puts "Row #{row.index}: #{row_cells.join(", ")}"
4490
- end
4491
- ```
4492
-
4493
- ### Console Output
4494
-
4495
- ```text
4496
- === Read Validation ===
4497
- Row 0: A1: "Header 1" (font=Calibri, fill=FF4F81BD), B1: "Header 2" (font=Calibri, fill=FF4F81BD)
4498
- Row 1: A2: "Normal Text" (font=, fill=), B2: "Highlighted Text" (font=Calibri, fill=FFFFFF00)
4499
- ```
4500
-
4501
- <hr/>
4502
-
4503
- ## Table Styles
4504
-
4505
- Visual demonstration for Table Styles.
4506
-
4507
- ### Rendered Output (LibreOffice Calc)
4508
-
4509
- <div><img src="../../test/visual/baselines/table_styles/page-1.png" width="100%" alt="Preview"/></div>
4510
-
4511
- ### DSL Code
4512
-
4513
- ```ruby
4514
- # frozen_string_literal: true
4515
-
4516
- require "xlsxrb"
4517
-
4518
- output_path = ARGV[0] || "table_styles.xlsx"
4519
-
4520
- Xlsxrb.write(output_path) do |wb|
4521
- wb.sheet("Table Example") do |sheet|
4522
- sheet.column(0, width: 8)
4523
- sheet.column(1, width: 16)
4524
- sheet.column(2, width: 16)
4525
- sheet.column(3, width: 14)
4526
- sheet.row(%w[ID Name Department Salary])
4527
- sheet.row([101, "Alice Smith", "Engineering", 120_000])
4528
- sheet.row([102, "Bob Jones", "Marketing", 95_000])
4529
- sheet.row([103, "Carol White", "Sales", 110_000])
4530
- sheet.row([104, "David Brown", "Engineering", 130_000])
4531
-
4532
- sheet.table("A1:D5", columns: %w[ID Name Department Salary], name: "EmployeeTable", style: "TableStyleMedium9", total_row: false)
4533
- end
4534
- end
4535
-
4536
- puts "=== Read Validation ==="
4537
- workbook = Xlsxrb.read(output_path).load
4538
- sheet = workbook.sheets.first
4539
- sheet.rows.each do |row|
4540
- row_cells = row.cells.map { |c| "#{c.ref}: #{c.value.inspect}" }
4541
- puts "Row #{row.index}: #{row_cells.join(", ")}"
4542
- end
4543
- ```
4544
-
4545
- ### Console Output
4546
-
4547
- ```text
4548
- === Read Validation ===
4549
- Row 0: A1: "ID", B1: "Name", C1: "Department", D1: "Salary"
4550
- Row 1: A2: 101, B2: "Alice Smith", C2: "Engineering", D2: 120000
4551
- Row 2: A3: 102, B3: "Bob Jones", C3: "Marketing", D3: 95000
4552
- Row 3: A4: 103, B4: "Carol White", C4: "Sales", D4: 110000
4553
- Row 4: A5: 104, B5: "David Brown", C5: "Engineering", D5: 130000
4554
- ```
4555
-
4556
- <hr/>
4557
-
4558
- ## View Show Grid Lines
4559
-
4560
- Demonstrates disabling visible grid lines in spreadsheet view.
4561
-
4562
- ### Rendered Output (LibreOffice Calc)
4563
-
4564
- <div><img src="../../test/visual/baselines/view_show_grid_lines/page-1.png" width="100%" alt="Preview"/></div>
4565
-
4566
- ### DSL Code
4567
-
4568
- ```ruby
4569
- # frozen_string_literal: true
4570
-
4571
- require "xlsxrb"
4572
- output_path = ARGV[0] || "view_show_grid_lines.xlsx"
4573
- Xlsxrb.write(output_path) do |wb|
4574
- wb.sheet("Hide Grid Lines") do |s|
4575
- s.column(0, width: 25)
4576
- s.column(1, width: 25)
4577
- s.sheet_view(:show_grid_lines, false)
4578
- s.row(["No Grid Lines displayed"])
4579
- end
4580
- end
4581
-
4582
- # 2. Read the generated sheet and print view configurations
4583
- puts "=== Read Validation ==="
4584
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
4585
- workbook = Xlsxrb.read(output_path).load
4586
- workbook.sheet_names.each do |s_name|
4587
- view = reader.sheet_view(sheet: s_name)
4588
- puts "Sheet '#{s_name}' views zoom scale: #{view[:zoom_scale]}%, show grid lines: #{view[:show_grid_lines]}"
4589
- end
4590
- ```
4591
-
4592
- ### Console Output
4593
-
4594
- ```text
4595
- === Read Validation ===
4596
- Sheet 'Hide Grid Lines' views zoom scale: %, show grid lines: false
4597
- ```
4598
-
4599
- <hr/>
4600
-
4601
- ## View Zoom Scale
4602
-
4603
- Demonstrates setting custom zoom scale in sheet view (e.g. 150%).
4604
-
4605
- ### Rendered Output (LibreOffice Calc)
4606
-
4607
- <div><img src="../../test/visual/baselines/view_zoom_scale/page-1.png" width="100%" alt="Preview"/></div>
4608
-
4609
- ### DSL Code
4610
-
4611
- ```ruby
4612
- # frozen_string_literal: true
4613
-
4614
- require "xlsxrb"
4615
- output_path = ARGV[0] || "view_zoom_scale.xlsx"
4616
- Xlsxrb.write(output_path) do |wb|
4617
- wb.sheet("Zoom 150") do |s|
4618
- s.column(0, width: 25)
4619
- s.column(1, width: 25)
4620
- s.sheet_view(:zoom_scale, 150)
4621
- s.row(["Zoom scale is set to 150%"])
4622
- end
4623
- end
4624
-
4625
- # 2. Read the generated sheet and print view configurations
4626
- puts "=== Read Validation ==="
4627
- reader = Xlsxrb::Ooxml::Reader.new(output_path)
4628
- workbook = Xlsxrb.read(output_path).load
4629
- workbook.sheet_names.each do |s_name|
4630
- view = reader.sheet_view(sheet: s_name)
4631
- puts "Sheet '#{s_name}' views zoom scale: #{view[:zoom_scale]}%, show grid lines: #{view[:show_grid_lines]}"
4632
- end
4633
- ```
4634
-
4635
- ### Console Output
4636
-
4637
- ```text
4638
- === Read Validation ===
4639
- Sheet 'Zoom 150' views zoom scale: 150%, show grid lines:
4640
- ```
4641
-
4642
- <hr/>
4643
-
4644
- ## Workbook Three Sheets
4645
-
4646
- Demonstrates creating workbooks with multiple worksheets.
4647
-
4648
- ### Rendered Output (LibreOffice Calc)
4649
-
4650
- <div><img src="../../test/visual/baselines/workbook_three_sheets/page-1.png" width="100%" alt="Preview"/></div>
4651
-
4652
- <div><img src="../../test/visual/baselines/workbook_three_sheets/page-2.png" width="100%" alt="Preview"/></div>
4653
-
4654
- <div><img src="../../test/visual/baselines/workbook_three_sheets/page-3.png" width="100%" alt="Preview"/></div>
4655
-
4656
- ### DSL Code
4657
-
4658
- ```ruby
4659
- # frozen_string_literal: true
4660
-
4661
- require "xlsxrb"
4662
- output_path = ARGV[0] || "workbook_three_sheets.xlsx"
4663
- Xlsxrb.write(output_path) do |wb|
4664
- wb.sheet("First Sheet") { |s| s.row(["First Sheet Data"]) }
4665
- wb.sheet("Second Sheet") { |s| s.row(["Second Sheet Data"]) }
4666
- wb.sheet("Third Sheet") { |s| s.row(["Third Sheet Data"]) }
4667
- end
4668
-
4669
- # 2. Read the generated sheet and print the sheets structure
4670
- puts "=== Read Validation ==="
4671
- workbook = Xlsxrb.read(output_path).load
4672
- puts "Workbook sheets: #{workbook.sheet_names.join(", ")}"
4673
- ```
4674
-
4675
- ### Console Output
4676
-
4677
- ```text
4678
- === Read Validation ===
4679
- Workbook sheets: First Sheet, Second Sheet, Third Sheet
4680
- ```
4681
-
4682
- <hr/>
4683
-