xlsx_composer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +223 -0
- data/Rakefile +8 -0
- data/lib/xlsx_composer/base.rb +75 -0
- data/lib/xlsx_composer/formatter.rb +49 -0
- data/lib/xlsx_composer/indexer.rb +48 -0
- data/lib/xlsx_composer/version.rb +5 -0
- data/lib/xlsx_composer/worksheet.rb +53 -0
- data/lib/xlsx_composer.rb +13 -0
- data/sig/xlsx_composer.rbs +4 -0
- metadata +98 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: eb4ddd7e108efe7858b8c3ef358a003e9a0b5d94f3be1500aacee95cd7c9c9ca
|
|
4
|
+
data.tar.gz: ff4408f5e1a9edf7fdbcaf9eeb9d935cb6e907fdddb80e12e5310395e0fd0521
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ac1e35c9a14f3d0a8ea9f6cf9f4b61b2d7cba0dee6d21885676a205f748c9d72ab735b04fb4af9bfb3b782865d2ee5b933e7b90505c1cb4b6ef28a917b09ffdc
|
|
7
|
+
data.tar.gz: 1bf88f371a14a58e2160958fbf4518204d4c9ac724ec7460aedd4eef636edb11b66f6b3ba6e9909e1c08f1e4d405e794942b59aa57e5de2f1c0a12b0e62f77ca
|
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
"xlsx_composer" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
|
|
4
|
+
|
|
5
|
+
* Participants will be tolerant of opposing views.
|
|
6
|
+
* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
|
|
7
|
+
* When interpreting the words and actions of others, participants should always assume good intentions.
|
|
8
|
+
* Behaviour which can be reasonably considered harassment will not be tolerated.
|
|
9
|
+
|
|
10
|
+
If you have any concerns about behaviour within this project, please contact us at ["hugo.passos@hotmail.com"](mailto:"hugo.passos@hotmail.com").
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hugo Passos
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# XlsxComposer
|
|
2
|
+
|
|
3
|
+
**XlsxComposer** is a small Ruby library built on top of **WriteXLSX** that makes the creation of **complex and dynamic Excel spreadsheets** easier, more readable, and more maintainable.
|
|
4
|
+
|
|
5
|
+
It does **not** try to replace WriteXLSX.
|
|
6
|
+
Instead, it provides a higher-level abstraction focused on **navigation, composition, and formatting**, which are usually the hardest parts when spreadsheets stop being static.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Motivation
|
|
10
|
+
|
|
11
|
+
`WriteXLSX` does an excellent job at generating `.xlsx` files.
|
|
12
|
+
However, when spreadsheets become **dynamic**, code tends to become harder to read and maintain:
|
|
13
|
+
|
|
14
|
+
- manual row and column index management
|
|
15
|
+
- lots of hard-coded coordinates
|
|
16
|
+
- duplicated formatting logic
|
|
17
|
+
- fragile templates that only work for fixed layouts
|
|
18
|
+
|
|
19
|
+
**XlsxComposer** introduces a *cursor-based* approach to spreadsheet writing:
|
|
20
|
+
|
|
21
|
+
- move through the sheet with `next_row`, `next_col`, `go_to`, etc.
|
|
22
|
+
- reuse the same template for variable-length data
|
|
23
|
+
- define and reuse formats easily
|
|
24
|
+
- compose spreadsheets incrementally instead of calculating coordinates upfront
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Add this line to your application's Gemfile:
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
gem "xlsx_composer"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
And then execute:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
bundle install
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## Basic usage
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
require "xlsx_composer"
|
|
46
|
+
|
|
47
|
+
workbook = XlsxComposer.workbook("example.xlsx")
|
|
48
|
+
|
|
49
|
+
sheet = XlsxComposer::Worksheet.new(workbook, "Demo")
|
|
50
|
+
|
|
51
|
+
sheet.go_to("1", "A")
|
|
52
|
+
sheet.write_row(["Year", "Revenue"], sheet.bold)
|
|
53
|
+
|
|
54
|
+
sheet.next_row
|
|
55
|
+
sheet.write_row([2024, 1000], sheet.thousands_mark)
|
|
56
|
+
|
|
57
|
+
sheet.next_row
|
|
58
|
+
sheet.write_row([2025, 1250], sheet.thousands_mark)
|
|
59
|
+
|
|
60
|
+
workbook.close
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## Cursor-based navigation
|
|
65
|
+
|
|
66
|
+
Instead of calculating coordinates manually, you move a cursor across the sheet.
|
|
67
|
+
|
|
68
|
+
### Available navigation methods
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
go_to(row, col) # go_to("3", "B")
|
|
72
|
+
go_to_row(row)
|
|
73
|
+
go_to_col(col)
|
|
74
|
+
|
|
75
|
+
next_row
|
|
76
|
+
previous_row
|
|
77
|
+
next_col
|
|
78
|
+
previous_col
|
|
79
|
+
|
|
80
|
+
next_rows(n)
|
|
81
|
+
previous_rows(n)
|
|
82
|
+
next_cols(n)
|
|
83
|
+
previous_cols(n)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- Rows are **1-based**
|
|
87
|
+
- Columns use **Excel notation** (`A`, `Z`, `AA`, `BA`, etc.)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## Dynamic templates
|
|
91
|
+
|
|
92
|
+
The main idea behind XlsxComposer is **that the same spreadsheet template can generate different shapes of data.**
|
|
93
|
+
|
|
94
|
+
### Example: contracts with variable durations
|
|
95
|
+
|
|
96
|
+
Imagine a `Contract` entity that produces yearly results:
|
|
97
|
+
- some contracts last 3 years
|
|
98
|
+
- others last 5, 10, or more
|
|
99
|
+
- the layout is the same, only the number of rows changes
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
class ContractWorksheet < XlsxComposer::Base
|
|
103
|
+
def worksheet_name
|
|
104
|
+
"Contract Summary"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def run(contract)
|
|
108
|
+
write_row(["Year", "Value"], bold)
|
|
109
|
+
|
|
110
|
+
contract.years.each do |year|
|
|
111
|
+
next_row
|
|
112
|
+
write_row([year.number, year.value], thousands_mark)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The same template works regardless of how many years the contract has.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
## Formatting
|
|
122
|
+
|
|
123
|
+
### Built-in formats
|
|
124
|
+
|
|
125
|
+
XlsxComposer ships with a set of common, reusable formats:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
bold
|
|
129
|
+
bold_center
|
|
130
|
+
bold_title
|
|
131
|
+
bold_percent
|
|
132
|
+
|
|
133
|
+
thousands_mark
|
|
134
|
+
currency_brl
|
|
135
|
+
|
|
136
|
+
font_size_ten
|
|
137
|
+
font_size_ten_thousands_mark
|
|
138
|
+
font_size_ten_currency_brl
|
|
139
|
+
font_size_ten_percent
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Formats are cached per worksheet and reused internally by WriteXLSX.
|
|
143
|
+
|
|
144
|
+
Usage example:
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
write_row(["Total"], bold)
|
|
148
|
+
write_row([1000], currency_brl)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
## Adding custom formats
|
|
153
|
+
|
|
154
|
+
You can define additional formats per worksheet class using `add_format`.
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
class ReportWorksheet < XlsxComposer::Base
|
|
158
|
+
add_format :header, bold: 1, size: 14, align: "center"
|
|
159
|
+
add_format :highlight, bold: 1, align: "center", bg_color: "yellow"
|
|
160
|
+
|
|
161
|
+
def worksheet_name
|
|
162
|
+
"Report"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def run
|
|
166
|
+
write_row(["Report"], header)
|
|
167
|
+
next_row
|
|
168
|
+
write_row(["Important"], highlight)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Dynamic formats
|
|
174
|
+
|
|
175
|
+
Formats can also be defined using a block:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
add_format(:conditional) do
|
|
179
|
+
if some_condition?
|
|
180
|
+
{ bold: 1, color: "red" }
|
|
181
|
+
else
|
|
182
|
+
{ bold: 1 }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
## Global vs class-specific formats
|
|
189
|
+
|
|
190
|
+
- **Global formats** live in `XlsxComposer::Formatter` and are available everywhere.
|
|
191
|
+
- **Class-specific formats** are defined via `add_format` and scoped to that worksheet composer.
|
|
192
|
+
|
|
193
|
+
Both are cached on the underlying worksheet and backed by WriteXLSX `Format` objects.
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
## Why not just WriteXLSX?
|
|
197
|
+
|
|
198
|
+
You absolutely can — and should — use WriteXLSX directly for simple spreadsheets.
|
|
199
|
+
|
|
200
|
+
XlsxComposer becomes valuable when:
|
|
201
|
+
|
|
202
|
+
- spreadsheets are generated from templates
|
|
203
|
+
- layouts are dynamic
|
|
204
|
+
- rows and columns are added conditionally or iteratively
|
|
205
|
+
- formatting logic starts spreading across the codebase
|
|
206
|
+
- readability and maintainability matter
|
|
207
|
+
|
|
208
|
+
Think of XlsxComposer as a **composition layer**, not a replacement.
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
## Contributing
|
|
212
|
+
|
|
213
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hugopassos/xlsx_composer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/hugopassos/xlsx_composer/blob/main/CODE_OF_CONDUCT.md).
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
## Code of Conduct
|
|
222
|
+
|
|
223
|
+
Everyone interacting in the XlsxComposer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hugopassos/xlsx_composer/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
5
|
+
module XlsxComposer
|
|
6
|
+
class Base
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def extra_formats
|
|
11
|
+
@extra_formats ||= {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def add_format(name, override: false, **args, &block)
|
|
15
|
+
name = name.to_sym
|
|
16
|
+
raise ArgumentError, "Invalid format name: #{name.inspect}" unless name.match?(/\A[a-z_]\w*\z/i)
|
|
17
|
+
|
|
18
|
+
if !override && (instance_methods.include?(name) || private_instance_methods.include?(name))
|
|
19
|
+
raise ArgumentError, "Method already defined: #{name} (use override: true)"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
extra_formats[name] = block || args
|
|
23
|
+
|
|
24
|
+
define_method(name) do
|
|
25
|
+
composer_worksheet.get_format(name)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def initialize(workbook: nil, worksheet: nil)
|
|
31
|
+
raise ArgumentError, "Provide workbook: or worksheet:" if workbook.nil? && worksheet.nil?
|
|
32
|
+
|
|
33
|
+
if worksheet
|
|
34
|
+
@composer_worksheet = worksheet
|
|
35
|
+
else
|
|
36
|
+
raise "Method `worksheet_name` must be defined" unless respond_to?(:worksheet_name, true)
|
|
37
|
+
@composer_worksheet = XlsxComposer::Worksheet.new(workbook, worksheet_name)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
define_class_formats!
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def compose(&block)
|
|
44
|
+
instance_exec(&block)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def close_workbook
|
|
48
|
+
workbook.close
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
attr_reader :composer_worksheet
|
|
54
|
+
|
|
55
|
+
def define_class_formats!
|
|
56
|
+
self.class.extra_formats.each do |name, spec|
|
|
57
|
+
args = spec.is_a?(Proc) ? instance_exec(&spec) : spec
|
|
58
|
+
composer_worksheet.format(name, **args)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def_delegators :@composer_worksheet,
|
|
63
|
+
:workbook, :worksheet,
|
|
64
|
+
:write_row, :write_col, :merge_rows, :merge_cols,
|
|
65
|
+
:row_index, :col_index, :go_to, :go_to_row, :go_to_col,
|
|
66
|
+
:next_row, :next_col, :previous_row, :previous_col,
|
|
67
|
+
:reset_row, :reset_col, :next_rows, :next_cols,
|
|
68
|
+
:previous_rows, :previous_cols,
|
|
69
|
+
:row_height, :col_width, :bold, :bold_center,
|
|
70
|
+
:bold_title, :bold_percent, :bold_rotation_ninety,
|
|
71
|
+
:thousands_mark, :currency_brl,
|
|
72
|
+
:font_size_ten, :font_size_ten_thousands_mark,
|
|
73
|
+
:font_size_ten_currency_brl, :font_size_ten_percent
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module XlsxComposer
|
|
4
|
+
module Formatter
|
|
5
|
+
def bold = format(:bold, bold: 1)
|
|
6
|
+
|
|
7
|
+
def bold_center = format(:bold_center, bold: 1, align: "center")
|
|
8
|
+
|
|
9
|
+
def bold_title = format(:font_size_sixteen_bold, bold: 1, size: 16)
|
|
10
|
+
|
|
11
|
+
def bold_percent = format(:percent_bold, bold: 1, num_format: "0%")
|
|
12
|
+
|
|
13
|
+
def bold_rotation_ninety = format(bold: 1, rotation: 90, align: "vcenter")
|
|
14
|
+
|
|
15
|
+
def thousands_mark = format(:thousands_mark, num_format: "#,##0")
|
|
16
|
+
|
|
17
|
+
def currency_brl = format(:currency_brl, num_format: "R$ #,##0.00")
|
|
18
|
+
|
|
19
|
+
def font_size_ten = format(:font_size_ten, size: 10)
|
|
20
|
+
|
|
21
|
+
def font_size_ten_thousands_mark = format(:font_size_ten_thousands_mark, size: 10, num_format: "#,##0")
|
|
22
|
+
|
|
23
|
+
def font_size_ten_currency_brl = format(:font_size_ten_currency_brl, size: 10, num_format: "R$ #,##0.00")
|
|
24
|
+
|
|
25
|
+
def font_size_ten_percent = format(:font_size_ten_percent, size: 10, num_format: "0%")
|
|
26
|
+
|
|
27
|
+
def row_height(value)
|
|
28
|
+
worksheet.set_row(row_index, value)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def col_width(value)
|
|
32
|
+
worksheet.set_column(col_index, col_index, value)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def format(name, **args)
|
|
36
|
+
name = name.to_sym
|
|
37
|
+
@__formats_cache ||= {}
|
|
38
|
+
@__formats_cache[name] ||= workbook.add_format(**args)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def get_format(name)
|
|
42
|
+
name = name.to_sym
|
|
43
|
+
@__formats_cache ||= {}
|
|
44
|
+
@__formats_cache.fetch(name) do
|
|
45
|
+
raise KeyError, "Format not defined: #{name}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module XlsxComposer
|
|
4
|
+
module Indexer
|
|
5
|
+
def next_row = @row_index += 1
|
|
6
|
+
|
|
7
|
+
def next_col = @col_index += 1
|
|
8
|
+
|
|
9
|
+
def previous_row = @row_index -= 1
|
|
10
|
+
|
|
11
|
+
def previous_col = @col_index -= 1
|
|
12
|
+
|
|
13
|
+
def reset_row = @row_index = 0
|
|
14
|
+
|
|
15
|
+
def reset_col = @col_index = 0
|
|
16
|
+
|
|
17
|
+
def next_rows(quantity) = @row_index += quantity
|
|
18
|
+
|
|
19
|
+
def next_cols(quantity) = @col_index += quantity
|
|
20
|
+
|
|
21
|
+
def previous_rows(quantity) = @row_index -= quantity
|
|
22
|
+
|
|
23
|
+
def previous_cols(quantity) = @col_index -= quantity
|
|
24
|
+
|
|
25
|
+
def go_to(row, col)
|
|
26
|
+
@row_index = row.to_i - 1
|
|
27
|
+
@col_index = col_to_index(col)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def go_to_row(row)
|
|
31
|
+
@row_index = row.to_i - 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def go_to_col(col)
|
|
35
|
+
@col_index = col_to_index(col)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# "A" => 0, "Z" => 25, "AA" => 26, "AB" => 27, ..., "BA" => 52 ...
|
|
41
|
+
def col_to_index(col)
|
|
42
|
+
str = col.to_s.strip.upcase
|
|
43
|
+
raise ArgumentError, "Invalid column: #{col.inspect}" unless str.match?(/\A[A-Z]+\z/)
|
|
44
|
+
|
|
45
|
+
str.chars.reduce(0) { |acc, ch| acc * 26 + (ch.ord - 64) } - 1
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module XlsxComposer
|
|
4
|
+
class Worksheet
|
|
5
|
+
include XlsxComposer::Indexer
|
|
6
|
+
include XlsxComposer::Formatter
|
|
7
|
+
|
|
8
|
+
attr_reader :row_index, :col_index, :workbook, :worksheet
|
|
9
|
+
|
|
10
|
+
def initialize(workbook, worksheet_name)
|
|
11
|
+
@workbook = workbook
|
|
12
|
+
@worksheet = workbook.add_worksheet(worksheet_name)
|
|
13
|
+
@row_index = 0
|
|
14
|
+
@col_index = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def write_row(content, format = nil)
|
|
18
|
+
worksheet.write_row(*current_index, content, format)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def write_col(content, format = nil)
|
|
22
|
+
worksheet.write_col(*current_index, content, format)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def merge_rows(number_of_rows, content, format = nil)
|
|
26
|
+
worksheet.merge_range(
|
|
27
|
+
row_index,
|
|
28
|
+
col_index,
|
|
29
|
+
row_index + number_of_rows - 1,
|
|
30
|
+
col_index,
|
|
31
|
+
content,
|
|
32
|
+
format
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def merge_cols(number_of_cols, content, format = nil)
|
|
37
|
+
worksheet.merge_range(
|
|
38
|
+
row_index,
|
|
39
|
+
col_index,
|
|
40
|
+
row_index,
|
|
41
|
+
col_index + number_of_cols - 1,
|
|
42
|
+
content,
|
|
43
|
+
format
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def current_index
|
|
50
|
+
[row_index, col_index]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "nkf"
|
|
2
|
+
require "write_xlsx"
|
|
3
|
+
require_relative "xlsx_composer/version"
|
|
4
|
+
require_relative "xlsx_composer/indexer"
|
|
5
|
+
require_relative "xlsx_composer/formatter"
|
|
6
|
+
require_relative "xlsx_composer/worksheet"
|
|
7
|
+
require_relative "xlsx_composer/base"
|
|
8
|
+
|
|
9
|
+
module XlsxComposer
|
|
10
|
+
def self.workbook(path, **opts)
|
|
11
|
+
WriteXLSX.new(path, **opts)
|
|
12
|
+
end
|
|
13
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: xlsx_composer
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Hugo Passos
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: write_xlsx
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.12'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.12'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: nkf
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rspec
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
description: XlsxComposer provides cursor-based navigation and reusable templates
|
|
55
|
+
for generating dynamic Excel spreadsheets using WriteXLSX.
|
|
56
|
+
email:
|
|
57
|
+
- hugo.passos@hotmail.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- CHANGELOG.md
|
|
63
|
+
- CODE_OF_CONDUCT.md
|
|
64
|
+
- LICENSE.txt
|
|
65
|
+
- README.md
|
|
66
|
+
- Rakefile
|
|
67
|
+
- lib/xlsx_composer.rb
|
|
68
|
+
- lib/xlsx_composer/base.rb
|
|
69
|
+
- lib/xlsx_composer/formatter.rb
|
|
70
|
+
- lib/xlsx_composer/indexer.rb
|
|
71
|
+
- lib/xlsx_composer/version.rb
|
|
72
|
+
- lib/xlsx_composer/worksheet.rb
|
|
73
|
+
- sig/xlsx_composer.rbs
|
|
74
|
+
homepage: https://github.com/hugopassos/xlsx_composer
|
|
75
|
+
licenses:
|
|
76
|
+
- MIT
|
|
77
|
+
metadata:
|
|
78
|
+
homepage_uri: https://github.com/hugopassos/xlsx_composer
|
|
79
|
+
source_code_uri: https://github.com/hugopassos/xlsx_composer
|
|
80
|
+
changelog_uri: https://github.com/hugopassos/xlsx_composer/blob/main/CHANGELOG.md
|
|
81
|
+
rdoc_options: []
|
|
82
|
+
require_paths:
|
|
83
|
+
- lib
|
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: 3.2.0
|
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0'
|
|
94
|
+
requirements: []
|
|
95
|
+
rubygems_version: 4.0.3
|
|
96
|
+
specification_version: 4
|
|
97
|
+
summary: A composition layer on top of WriteXLSX for dynamic spreadsheets
|
|
98
|
+
test_files: []
|