notare 0.0.3 → 0.0.4
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 +4 -4
- data/README.md +88 -1
- data/lib/notare/builder.rb +9 -2
- data/lib/notare/document.rb +19 -1
- data/lib/notare/nodes/table.rb +4 -3
- data/lib/notare/package.rb +1 -1
- data/lib/notare/table_style.rb +83 -0
- data/lib/notare/version.rb +1 -1
- data/lib/notare/xml/document_xml.rb +7 -3
- data/lib/notare/xml/styles_xml.rb +65 -1
- data/lib/notare.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1dd4e9ab394b198d4a9ddd59eb40fac35c865159e527fe14a90113bba1071fd0
|
|
4
|
+
data.tar.gz: e10d211085e797c80850ab3433b8802270df96bc01cd3d2ac348da6f17c675ec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ba2c27ab7d6ad5a6f5b5239f54504e8352a5fee52374685f7e09d61284781ba93e9353a0c75f07a3e047571cc55d598c3764beb3c1d08663e54d11119e515fa5
|
|
7
|
+
data.tar.gz: b42bc57c20a639882a8912b1da7759b2c131443ce840f3d901a1a29a70a86e4f8238ce0b9d38ed688e0332fb99b77f7c5edcebffc611302273ede404c2a72197
|
data/README.md
CHANGED
|
@@ -105,6 +105,21 @@ Notare includes built-in styles and supports custom style definitions.
|
|
|
105
105
|
|
|
106
106
|
#### Built-in Styles
|
|
107
107
|
|
|
108
|
+
| Style | Properties |
|
|
109
|
+
|-------|------------|
|
|
110
|
+
| `:title` | 26pt, bold, centered |
|
|
111
|
+
| `:subtitle` | 15pt, italic, gray (#666666) |
|
|
112
|
+
| `:quote` | italic, gray (#666666), indented |
|
|
113
|
+
| `:code` | Courier New, 10pt |
|
|
114
|
+
| `:heading1` | 24pt, bold |
|
|
115
|
+
| `:heading2` | 18pt, bold |
|
|
116
|
+
| `:heading3` | 14pt, bold |
|
|
117
|
+
| `:heading4` | 12pt, bold |
|
|
118
|
+
| `:heading5` | 11pt, bold, italic |
|
|
119
|
+
| `:heading6` | 10pt, bold, italic |
|
|
120
|
+
|
|
121
|
+
Note: `h1` through `h6` methods use the corresponding heading styles automatically.
|
|
122
|
+
|
|
108
123
|
```ruby
|
|
109
124
|
Notare::Document.create("output.docx") do |doc|
|
|
110
125
|
doc.p "This is a title", style: :title
|
|
@@ -246,6 +261,77 @@ Notare::Document.create("output.docx") do |doc|
|
|
|
246
261
|
end
|
|
247
262
|
```
|
|
248
263
|
|
|
264
|
+
#### Table Styles
|
|
265
|
+
|
|
266
|
+
Define reusable table styles with borders, shading, cell margins, and alignment:
|
|
267
|
+
|
|
268
|
+
```ruby
|
|
269
|
+
Notare::Document.create("output.docx") do |doc|
|
|
270
|
+
# Define a custom table style
|
|
271
|
+
doc.define_table_style :fancy,
|
|
272
|
+
borders: { style: "double", color: "0066CC", size: 6 },
|
|
273
|
+
shading: "E6F2FF",
|
|
274
|
+
cell_margins: 100,
|
|
275
|
+
align: :center
|
|
276
|
+
|
|
277
|
+
# Apply the style to a table
|
|
278
|
+
doc.table(style: :fancy) do
|
|
279
|
+
doc.tr do
|
|
280
|
+
doc.td "Product"
|
|
281
|
+
doc.td "Price"
|
|
282
|
+
end
|
|
283
|
+
doc.tr do
|
|
284
|
+
doc.td "Widget"
|
|
285
|
+
doc.td "$10.00"
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### Table Style Properties
|
|
292
|
+
|
|
293
|
+
| Property | Description | Example |
|
|
294
|
+
|----------|-------------|---------|
|
|
295
|
+
| `borders` | Border configuration | `{ style: "single", color: "000000", size: 4 }` |
|
|
296
|
+
| `shading` | Background color (hex) | `"EEEEEE"` |
|
|
297
|
+
| `cell_margins` | Cell padding (twips) | `100` or `{ top: 50, bottom: 50, left: 100, right: 100 }` |
|
|
298
|
+
| `align` | Table alignment | `:left`, `:center`, `:right` |
|
|
299
|
+
|
|
300
|
+
**Border styles:** `single`, `double`, `dotted`, `dashed`, `triple`, `none`
|
|
301
|
+
|
|
302
|
+
**Border configuration options:**
|
|
303
|
+
|
|
304
|
+
```ruby
|
|
305
|
+
# All borders the same
|
|
306
|
+
borders: { style: "single", color: "000000", size: 4 }
|
|
307
|
+
|
|
308
|
+
# Per-edge borders
|
|
309
|
+
borders: {
|
|
310
|
+
top: { style: "double", color: "FF0000", size: 8 },
|
|
311
|
+
bottom: { style: "single", color: "000000", size: 4 },
|
|
312
|
+
left: { style: "none" },
|
|
313
|
+
right: { style: "none" },
|
|
314
|
+
insideH: { style: "dotted", color: "CCCCCC", size: 2 },
|
|
315
|
+
insideV: { style: "dotted", color: "CCCCCC", size: 2 }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
# No borders
|
|
319
|
+
borders: :none
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Built-in Table Styles
|
|
323
|
+
|
|
324
|
+
| Style | Description |
|
|
325
|
+
|-------|-------------|
|
|
326
|
+
| `:grid` | Standard black single-line borders |
|
|
327
|
+
| `:borderless` | No borders |
|
|
328
|
+
|
|
329
|
+
```ruby
|
|
330
|
+
doc.table(style: :borderless) do
|
|
331
|
+
doc.tr { doc.td "No borders here" }
|
|
332
|
+
end
|
|
333
|
+
```
|
|
334
|
+
|
|
249
335
|
### Images
|
|
250
336
|
|
|
251
337
|
Images can be added to paragraphs, table cells, and list items. Supports PNG and JPEG formats.
|
|
@@ -434,12 +520,13 @@ end
|
|
|
434
520
|
| `link(url, text)` | Hyperlink with custom text |
|
|
435
521
|
| `link(url) { }` | Hyperlink with block content |
|
|
436
522
|
| `define_style(name, **props)` | Define a custom style |
|
|
523
|
+
| `define_table_style(name, **props)` | Define a custom table style |
|
|
437
524
|
| `ul { }` | Bullet list (can be nested) |
|
|
438
525
|
| `ol { }` | Numbered list (can be nested) |
|
|
439
526
|
| `li(text)` | List item with text |
|
|
440
527
|
| `li { }` | List item with block content |
|
|
441
528
|
| `li(text) { }` | List item with text and nested content |
|
|
442
|
-
| `table { }` | Table |
|
|
529
|
+
| `table(style:) { }` | Table with optional style |
|
|
443
530
|
| `tr { }` | Table row |
|
|
444
531
|
| `td(text)` | Table cell with text |
|
|
445
532
|
| `td { }` | Table cell with block content |
|
data/lib/notare/builder.rb
CHANGED
|
@@ -100,8 +100,8 @@ module Notare
|
|
|
100
100
|
@current_list.add_item(item)
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
-
def table(&block)
|
|
104
|
-
tbl = Nodes::Table.new
|
|
103
|
+
def table(style: nil, &block)
|
|
104
|
+
tbl = Nodes::Table.new(style: resolve_table_style(style))
|
|
105
105
|
previous_table = @current_table
|
|
106
106
|
@current_table = tbl
|
|
107
107
|
block.call
|
|
@@ -198,5 +198,12 @@ module Notare
|
|
|
198
198
|
|
|
199
199
|
style(style_or_name) || raise(ArgumentError, "Unknown style: #{style_or_name}")
|
|
200
200
|
end
|
|
201
|
+
|
|
202
|
+
def resolve_table_style(style_or_name)
|
|
203
|
+
return nil if style_or_name.nil?
|
|
204
|
+
return style_or_name if style_or_name.is_a?(TableStyle)
|
|
205
|
+
|
|
206
|
+
table_style(style_or_name) || raise(ArgumentError, "Unknown table style: #{style_or_name}")
|
|
207
|
+
end
|
|
201
208
|
end
|
|
202
209
|
end
|
data/lib/notare/document.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Notare
|
|
|
4
4
|
class Document
|
|
5
5
|
include Builder
|
|
6
6
|
|
|
7
|
-
attr_reader :nodes, :styles, :hyperlinks
|
|
7
|
+
attr_reader :nodes, :styles, :table_styles, :hyperlinks
|
|
8
8
|
|
|
9
9
|
def self.create(path, &block)
|
|
10
10
|
doc = new
|
|
@@ -25,7 +25,9 @@ module Notare
|
|
|
25
25
|
@images = {}
|
|
26
26
|
@hyperlinks = []
|
|
27
27
|
@styles = {}
|
|
28
|
+
@table_styles = {}
|
|
28
29
|
register_built_in_styles
|
|
30
|
+
register_built_in_table_styles
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
def define_style(name, **properties)
|
|
@@ -36,6 +38,14 @@ module Notare
|
|
|
36
38
|
@styles[name]
|
|
37
39
|
end
|
|
38
40
|
|
|
41
|
+
def define_table_style(name, **properties)
|
|
42
|
+
@table_styles[name] = TableStyle.new(name, **properties)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def table_style(name)
|
|
46
|
+
@table_styles[name]
|
|
47
|
+
end
|
|
48
|
+
|
|
39
49
|
def save(path)
|
|
40
50
|
Package.new(self).save(path)
|
|
41
51
|
end
|
|
@@ -104,5 +114,13 @@ module Notare
|
|
|
104
114
|
define_style :quote, italic: true, color: "666666", indent: 720
|
|
105
115
|
define_style :code, font: "Courier New", size: 10
|
|
106
116
|
end
|
|
117
|
+
|
|
118
|
+
def register_built_in_table_styles
|
|
119
|
+
define_table_style :grid,
|
|
120
|
+
borders: { style: "single", color: "000000", size: 4 }
|
|
121
|
+
|
|
122
|
+
define_table_style :borderless,
|
|
123
|
+
borders: :none
|
|
124
|
+
end
|
|
107
125
|
end
|
|
108
126
|
end
|
data/lib/notare/nodes/table.rb
CHANGED
data/lib/notare/package.rb
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Notare
|
|
4
|
+
class TableStyle
|
|
5
|
+
attr_reader :name, :borders, :shading, :cell_margins, :align
|
|
6
|
+
|
|
7
|
+
BORDER_STYLES = %w[single double dotted dashed triple none nil].freeze
|
|
8
|
+
BORDER_POSITIONS = %i[top bottom left right insideH insideV].freeze
|
|
9
|
+
ALIGNMENTS = %i[left center right].freeze
|
|
10
|
+
|
|
11
|
+
def initialize(name, borders: nil, shading: nil, cell_margins: nil, align: nil)
|
|
12
|
+
@name = name
|
|
13
|
+
@borders = normalize_borders(borders)
|
|
14
|
+
@shading = normalize_color(shading)
|
|
15
|
+
@cell_margins = normalize_cell_margins(cell_margins)
|
|
16
|
+
@align = validate_align(align)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def style_id
|
|
20
|
+
name.to_s.split("_").map(&:capitalize).join
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def display_name
|
|
24
|
+
name.to_s.split("_").map(&:capitalize).join(" ")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def normalize_borders(borders)
|
|
30
|
+
return nil if borders.nil?
|
|
31
|
+
return :none if borders == :none
|
|
32
|
+
|
|
33
|
+
# Check if it's a per-edge configuration
|
|
34
|
+
if borders.keys.any? { |k| BORDER_POSITIONS.include?(k) }
|
|
35
|
+
borders.transform_values { |v| normalize_single_border(v) }
|
|
36
|
+
else
|
|
37
|
+
# Single border config applied to all edges
|
|
38
|
+
normalize_single_border(borders)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def normalize_single_border(border)
|
|
43
|
+
return :none if border == :none || border[:style] == "none"
|
|
44
|
+
|
|
45
|
+
style = border[:style] || "single"
|
|
46
|
+
unless BORDER_STYLES.include?(style)
|
|
47
|
+
raise ArgumentError, "Invalid border style: #{style}. Use #{BORDER_STYLES.join(", ")}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
style: style,
|
|
52
|
+
color: normalize_color(border[:color]) || "000000",
|
|
53
|
+
size: border[:size] || 4
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def normalize_color(color)
|
|
58
|
+
return nil if color.nil?
|
|
59
|
+
|
|
60
|
+
hex = color.to_s.sub(/^#/, "").upcase
|
|
61
|
+
return hex if hex.match?(/\A[0-9A-F]{6}\z/)
|
|
62
|
+
|
|
63
|
+
raise ArgumentError, "Invalid color: #{color}. Use 6-digit hex (e.g., 'FF0000')"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def normalize_cell_margins(margins)
|
|
67
|
+
return nil if margins.nil?
|
|
68
|
+
|
|
69
|
+
if margins.is_a?(Hash)
|
|
70
|
+
margins.slice(:top, :bottom, :left, :right)
|
|
71
|
+
else
|
|
72
|
+
margins.to_i
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def validate_align(align)
|
|
77
|
+
return nil if align.nil?
|
|
78
|
+
return align if ALIGNMENTS.include?(align)
|
|
79
|
+
|
|
80
|
+
raise ArgumentError, "Invalid alignment: #{align}. Use #{ALIGNMENTS.join(", ")}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
data/lib/notare/version.rb
CHANGED
|
@@ -169,9 +169,13 @@ module Notare
|
|
|
169
169
|
xml["w"].tbl do
|
|
170
170
|
xml["w"].tblPr do
|
|
171
171
|
xml["w"].tblW("w:w" => "5000", "w:type" => "pct")
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
if table.style
|
|
173
|
+
xml["w"].tblStyle("w:val" => table.style.style_id)
|
|
174
|
+
else
|
|
175
|
+
xml["w"].tblBorders do
|
|
176
|
+
%w[top left bottom right insideH insideV].each do |border|
|
|
177
|
+
xml["w"].send(border, "w:val" => "single", "w:sz" => "4", "w:space" => "0", "w:color" => "000000")
|
|
178
|
+
end
|
|
175
179
|
end
|
|
176
180
|
end
|
|
177
181
|
end
|
|
@@ -12,8 +12,15 @@ module Notare
|
|
|
12
12
|
justify: "both"
|
|
13
13
|
}.freeze
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
TABLE_ALIGNMENT_MAP = {
|
|
16
|
+
left: "left",
|
|
17
|
+
center: "center",
|
|
18
|
+
right: "right"
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
def initialize(styles, table_styles = {})
|
|
16
22
|
@styles = styles
|
|
23
|
+
@table_styles = table_styles
|
|
17
24
|
end
|
|
18
25
|
|
|
19
26
|
def to_xml
|
|
@@ -24,6 +31,10 @@ module Notare
|
|
|
24
31
|
@styles.each_value do |style|
|
|
25
32
|
render_style(xml, style)
|
|
26
33
|
end
|
|
34
|
+
|
|
35
|
+
@table_styles.each_value do |style|
|
|
36
|
+
render_table_style(xml, style)
|
|
37
|
+
end
|
|
27
38
|
end
|
|
28
39
|
end
|
|
29
40
|
builder.to_xml
|
|
@@ -63,6 +74,59 @@ module Notare
|
|
|
63
74
|
xml["w"].highlight("w:val" => style.highlight) if style.highlight
|
|
64
75
|
end
|
|
65
76
|
end
|
|
77
|
+
|
|
78
|
+
def render_table_style(xml, style)
|
|
79
|
+
xml["w"].style("w:type" => "table", "w:styleId" => style.style_id) do
|
|
80
|
+
xml["w"].name("w:val" => style.display_name)
|
|
81
|
+
|
|
82
|
+
xml["w"].tblPr do
|
|
83
|
+
render_table_borders(xml, style.borders) if style.borders
|
|
84
|
+
render_table_shading(xml, style.shading) if style.shading
|
|
85
|
+
render_table_cell_margins(xml, style.cell_margins) if style.cell_margins
|
|
86
|
+
xml["w"].jc("w:val" => TABLE_ALIGNMENT_MAP[style.align]) if style.align
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def render_table_borders(xml, borders)
|
|
92
|
+
xml["w"].tblBorders do
|
|
93
|
+
%i[top left bottom right insideH insideV].each do |pos|
|
|
94
|
+
border = borders == :none ? :none : (borders[pos] || borders)
|
|
95
|
+
render_single_border(xml, pos, border)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def render_single_border(xml, position, border)
|
|
101
|
+
if border == :none
|
|
102
|
+
xml["w"].send(position, "w:val" => "nil")
|
|
103
|
+
else
|
|
104
|
+
xml["w"].send(position,
|
|
105
|
+
"w:val" => border[:style],
|
|
106
|
+
"w:sz" => border[:size].to_s,
|
|
107
|
+
"w:space" => "0",
|
|
108
|
+
"w:color" => border[:color])
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def render_table_shading(xml, color)
|
|
113
|
+
xml["w"].shd("w:val" => "clear", "w:color" => "auto", "w:fill" => color)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def render_table_cell_margins(xml, margins)
|
|
117
|
+
xml["w"].tblCellMar do
|
|
118
|
+
if margins.is_a?(Hash)
|
|
119
|
+
xml["w"].top("w:w" => margins[:top].to_s, "w:type" => "dxa") if margins[:top]
|
|
120
|
+
xml["w"].left("w:w" => margins[:left].to_s, "w:type" => "dxa") if margins[:left]
|
|
121
|
+
xml["w"].bottom("w:w" => margins[:bottom].to_s, "w:type" => "dxa") if margins[:bottom]
|
|
122
|
+
xml["w"].right("w:w" => margins[:right].to_s, "w:type" => "dxa") if margins[:right]
|
|
123
|
+
else
|
|
124
|
+
%i[top left bottom right].each do |side|
|
|
125
|
+
xml["w"].send(side, "w:w" => margins.to_s, "w:type" => "dxa")
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
66
130
|
end
|
|
67
131
|
end
|
|
68
132
|
end
|
data/lib/notare.rb
CHANGED
|
@@ -16,6 +16,7 @@ require_relative "notare/nodes/table_row"
|
|
|
16
16
|
require_relative "notare/nodes/table_cell"
|
|
17
17
|
require_relative "notare/image_dimensions"
|
|
18
18
|
require_relative "notare/style"
|
|
19
|
+
require_relative "notare/table_style"
|
|
19
20
|
require_relative "notare/xml/content_types"
|
|
20
21
|
require_relative "notare/xml/relationships"
|
|
21
22
|
require_relative "notare/xml/document_xml"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: notare
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mathias
|
|
@@ -133,6 +133,7 @@ files:
|
|
|
133
133
|
- lib/notare/nodes/table_row.rb
|
|
134
134
|
- lib/notare/package.rb
|
|
135
135
|
- lib/notare/style.rb
|
|
136
|
+
- lib/notare/table_style.rb
|
|
136
137
|
- lib/notare/version.rb
|
|
137
138
|
- lib/notare/xml/content_types.rb
|
|
138
139
|
- lib/notare/xml/document_xml.rb
|