oxml_maker 0.1.1 → 0.1.2
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/CHANGELOG.md +14 -0
- data/README.md +150 -0
- data/lib/oxml_maker/docx/word/document.xml +82 -6
- data/lib/oxml_maker/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8a34e4889ab877b4ffd10572cdf45d54cf1f860d1980e74fb20840190cd5b6f7
|
|
4
|
+
data.tar.gz: 81315caa4bf153a02f3045e0248c87348a0c8f0eb3984fec30253c3fb0d92bd7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f67753dcad5da06668f027ac73cb93f77bf64a587d1ec2c63c305fcfba3340bf8e978ebf7f40e143865411547ce95035a706b381a8ccd749bdb26b4549fe295
|
|
7
|
+
data.tar.gz: 6b6cf09d9f221b644dc6308a6ae9503ebbb6e94e782367d1337af12bd9800e02733d5cca1e08906a82f70f1c3b5a82205d846170b0b03a91ec859de72a6a6b1d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.1.2] - 2025-10-21
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Advanced table features: `v_merge` and `new_line` functionality
|
|
7
|
+
- Comprehensive test suite for advanced table features (4 new tests)
|
|
8
|
+
- Support for vertical cell merging in tables
|
|
9
|
+
- Multi-line cell content with comma-separated value splitting
|
|
10
|
+
- Test coverage for complex table scenarios with real-world data examples
|
|
11
|
+
|
|
12
|
+
### Enhanced
|
|
13
|
+
- Table functionality with advanced formatting capabilities
|
|
14
|
+
- Test suite expanded to 67 tests with 344 assertions
|
|
15
|
+
- Documentation of table feature limitations and implementation details
|
|
16
|
+
|
|
3
17
|
## [0.1.1] - 2025-10-20
|
|
4
18
|
|
|
5
19
|
### Added
|
data/README.md
CHANGED
|
@@ -276,6 +276,156 @@ end
|
|
|
276
276
|
- `refute condition` - Test falsiness
|
|
277
277
|
- `assert_kind_of Class, object` - Test object type
|
|
278
278
|
|
|
279
|
+
## Why OxmlMaker is Different: The Ruby Object Revolution
|
|
280
|
+
|
|
281
|
+
### The Problem with Traditional DOCX Gems
|
|
282
|
+
|
|
283
|
+
Most Ruby DOCX libraries force you into rigid patterns:
|
|
284
|
+
|
|
285
|
+
```ruby
|
|
286
|
+
# Traditional approach - manual, inflexible
|
|
287
|
+
builder.table do |t|
|
|
288
|
+
t.row ["Name", "Age"] # Static arrays only
|
|
289
|
+
t.row ["John", "30"] # Manual string building
|
|
290
|
+
t.row ["Jane", "25"] # Can't use objects directly
|
|
291
|
+
end
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### OxmlMaker's Revolutionary Approach
|
|
295
|
+
|
|
296
|
+
**Direct Ruby Object Mapping** - Use ANY Ruby object with methods:
|
|
297
|
+
|
|
298
|
+
```ruby
|
|
299
|
+
# Revolutionary - works with ANY objects!
|
|
300
|
+
data: {
|
|
301
|
+
0 => [
|
|
302
|
+
OpenStruct.new(name: "John", age: 30), # OpenStruct
|
|
303
|
+
User.find(1), # ActiveRecord model
|
|
304
|
+
JSON.parse('{"name": "Jane"}'), # JSON object
|
|
305
|
+
api_response.data, # API response
|
|
306
|
+
custom_object # Any object with methods
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Table automatically calls methods dynamically
|
|
311
|
+
{ value: :name } # Calls object.name on each object
|
|
312
|
+
{ value: :email } # Calls object.email on each object
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Perfect for Modern Architectures
|
|
316
|
+
|
|
317
|
+
#### 1. **JSON-Native Design**
|
|
318
|
+
Built for API-first and headless architectures:
|
|
319
|
+
|
|
320
|
+
```ruby
|
|
321
|
+
# HTML → JSON → DOCX pipeline
|
|
322
|
+
html_content = "<div><h1>Title</h1><table>...</table></div>"
|
|
323
|
+
json_data = html_to_json_parser(html_content)
|
|
324
|
+
|
|
325
|
+
# Direct consumption - no transformation needed!
|
|
326
|
+
doc = OxmlMaker::Document.new(
|
|
327
|
+
filename: "converted.docx",
|
|
328
|
+
params: json_data # Pure JSON input
|
|
329
|
+
)
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### 2. **Polymorphic Data Handling**
|
|
333
|
+
Mix any data sources in the same document:
|
|
334
|
+
|
|
335
|
+
```ruby
|
|
336
|
+
# Different object types in the same table!
|
|
337
|
+
data: {
|
|
338
|
+
0 => [
|
|
339
|
+
user_model, # ActiveRecord object
|
|
340
|
+
{ name: "Jane" }, # Hash
|
|
341
|
+
OpenStruct.new(name: "Bob"), # OpenStruct
|
|
342
|
+
json_api_response # JSON object
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
#### 3. **Configuration-Driven Architecture**
|
|
348
|
+
Documents are pure data structures - serializable and cacheable:
|
|
349
|
+
|
|
350
|
+
```ruby
|
|
351
|
+
# Store templates as JSON in database
|
|
352
|
+
template = DocumentTemplate.find_by(name: "invoice")
|
|
353
|
+
live_data = Invoice.includes(:line_items).find(params[:id])
|
|
354
|
+
|
|
355
|
+
# Merge template with live data
|
|
356
|
+
params = template.structure.deep_merge({
|
|
357
|
+
sections: [{
|
|
358
|
+
table: {
|
|
359
|
+
data: { 0 => live_data.line_items.to_a } # Direct AR relation!
|
|
360
|
+
}
|
|
361
|
+
}]
|
|
362
|
+
})
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Comparison with Other Ruby DOCX Gems
|
|
366
|
+
|
|
367
|
+
| Feature | OxmlMaker | Caracal | ruby-docx | docx | sablon |
|
|
368
|
+
|---------|-----------|---------|-----------|------|--------|
|
|
369
|
+
| **Ruby Object Mapping** | ✅ Dynamic | ❌ Manual | ❌ Manual | ❌ Template | ❌ Template |
|
|
370
|
+
| **JSON Serializable** | ✅ 100% | ❌ Code-based | ❌ Code-based | ❌ Template | ❌ Template |
|
|
371
|
+
| **Any Ruby Object** | ✅ Polymorphic | ❌ Arrays only | ❌ Limited | ❌ Static | ❌ Mail merge |
|
|
372
|
+
| **HTML→JSON→DOCX** | ✅ Native | ❌ Complex | ❌ N/A | ❌ N/A | ❌ Template only |
|
|
373
|
+
| **API-Friendly** | ✅ Pure data | ❌ Code required | ❌ Code required | ❌ Files | ❌ Templates |
|
|
374
|
+
| **Microservices Ready** | ✅ Stateless | ❌ Complex | ❌ Complex | ❌ File-based | ❌ Template-based |
|
|
375
|
+
|
|
376
|
+
### Perfect Use Cases
|
|
377
|
+
|
|
378
|
+
#### **CMS/Blog Export**
|
|
379
|
+
```ruby
|
|
380
|
+
# Blog post with mixed content types
|
|
381
|
+
post_json = {
|
|
382
|
+
sections: [
|
|
383
|
+
{ paragraph: { text: post.title } },
|
|
384
|
+
{ table: {
|
|
385
|
+
data: { 0 => post.comments.approved } # Direct relation!
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### **API Report Generation**
|
|
393
|
+
```ruby
|
|
394
|
+
# Consume external APIs directly
|
|
395
|
+
api_response = HTTParty.get("https://api.example.com/reports/#{id}")
|
|
396
|
+
json_data = JSON.parse(api_response.body, object_class: OpenStruct)
|
|
397
|
+
|
|
398
|
+
# No transformation needed!
|
|
399
|
+
doc = OxmlMaker::Document.new(params: { sections: json_data.sections })
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
#### **Dynamic Form Processing**
|
|
403
|
+
```ruby
|
|
404
|
+
# Form submission → DOCX
|
|
405
|
+
form_data = params[:form_responses] # Frontend JSON
|
|
406
|
+
|
|
407
|
+
document_params = {
|
|
408
|
+
sections: [{
|
|
409
|
+
table: {
|
|
410
|
+
data: { 0 => form_data.map { |item| OpenStruct.new(item) } }
|
|
411
|
+
}
|
|
412
|
+
}]
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### The Architectural Advantage
|
|
417
|
+
|
|
418
|
+
**Zero Impedance Mismatch** - Your data flows directly into documents without transformation layers, making OxmlMaker perfect for:
|
|
419
|
+
|
|
420
|
+
- **Headless CMS** systems
|
|
421
|
+
- **API-first** applications
|
|
422
|
+
- **Microservice** architectures
|
|
423
|
+
- **HTML→DOCX** conversion pipelines
|
|
424
|
+
- **Real-time report** generation
|
|
425
|
+
- **JSON-driven** document templates
|
|
426
|
+
|
|
427
|
+
This isn't just a different API - it's a **fundamentally superior architecture** for modern Ruby applications.
|
|
428
|
+
|
|
279
429
|
## Dependencies
|
|
280
430
|
|
|
281
431
|
- **rubyzip (~> 3.2)** - For ZIP file creation and DOCX generation
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<w:body>
|
|
4
4
|
<w:p>
|
|
5
5
|
<w:r>
|
|
6
|
-
<w:t>Test
|
|
6
|
+
<w:t>Test Document Content</w:t>
|
|
7
7
|
</w:r>
|
|
8
8
|
</w:p>
|
|
9
9
|
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
<w:tblLook w:val="0600"/>
|
|
25
25
|
</w:tblPr>
|
|
26
26
|
<w:tblGrid>
|
|
27
|
-
<w:gridCol w:w="
|
|
27
|
+
<w:gridCol w:w="2000"/>
|
|
28
|
+
<w:gridCol w:w="1500"/>
|
|
28
29
|
</w:tblGrid>
|
|
29
30
|
<w:tr>
|
|
30
31
|
<w:tblPrEx>
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
</w:trPr>
|
|
39
40
|
<w:tc>
|
|
40
41
|
<w:tcPr>
|
|
41
|
-
<w:tcW w:w="
|
|
42
|
+
<w:tcW w:w="2000"/>
|
|
42
43
|
</w:tcPr>
|
|
43
44
|
<w:p>
|
|
44
45
|
<w:pPr>
|
|
@@ -52,7 +53,28 @@
|
|
|
52
53
|
<w:b/>
|
|
53
54
|
<w:sz w:val="22"/>
|
|
54
55
|
</w:rPr>
|
|
55
|
-
<w:t>
|
|
56
|
+
<w:t>Name</w:t>
|
|
57
|
+
</w:r>
|
|
58
|
+
</w:p>
|
|
59
|
+
</w:tc>
|
|
60
|
+
|
|
61
|
+
<w:tc>
|
|
62
|
+
<w:tcPr>
|
|
63
|
+
<w:tcW w:w="1500"/>
|
|
64
|
+
</w:tcPr>
|
|
65
|
+
<w:p>
|
|
66
|
+
<w:pPr>
|
|
67
|
+
<w:jc w:val="center"/>
|
|
68
|
+
<w:rPr>
|
|
69
|
+
<w:b/>
|
|
70
|
+
</w:rPr>
|
|
71
|
+
</w:pPr>
|
|
72
|
+
<w:r>
|
|
73
|
+
<w:rPr>
|
|
74
|
+
<w:b/>
|
|
75
|
+
<w:sz w:val="22"/>
|
|
76
|
+
</w:rPr>
|
|
77
|
+
<w:t>Value</w:t>
|
|
56
78
|
</w:r>
|
|
57
79
|
</w:p>
|
|
58
80
|
</w:tc>
|
|
@@ -61,7 +83,61 @@
|
|
|
61
83
|
<w:tr>
|
|
62
84
|
<w:tc>
|
|
63
85
|
<w:tcPr>
|
|
64
|
-
<w:tcW w:w='
|
|
86
|
+
<w:tcW w:w='2000' w:type='dxa'/>
|
|
87
|
+
|
|
88
|
+
<w:vAlign w:val="center"/>
|
|
89
|
+
</w:tcPr>
|
|
90
|
+
<w:p>
|
|
91
|
+
<w:pPr>
|
|
92
|
+
<w:jc w:val='center'/>
|
|
93
|
+
</w:pPr>
|
|
94
|
+
<w:r>
|
|
95
|
+
<w:rPr><w:sz w:val='22'/></w:rPr>
|
|
96
|
+
<w:t>Item 1</w:t>
|
|
97
|
+
</w:r>
|
|
98
|
+
</w:p>
|
|
99
|
+
</w:tc>
|
|
100
|
+
|
|
101
|
+
<w:tc>
|
|
102
|
+
<w:tcPr>
|
|
103
|
+
<w:tcW w:w='1500' w:type='dxa'/>
|
|
104
|
+
|
|
105
|
+
<w:vAlign w:val="center"/>
|
|
106
|
+
</w:tcPr>
|
|
107
|
+
<w:p>
|
|
108
|
+
<w:pPr>
|
|
109
|
+
<w:jc w:val='center'/>
|
|
110
|
+
</w:pPr>
|
|
111
|
+
<w:r>
|
|
112
|
+
<w:rPr><w:sz w:val='22'/></w:rPr>
|
|
113
|
+
<w:t>100</w:t>
|
|
114
|
+
</w:r>
|
|
115
|
+
</w:p>
|
|
116
|
+
</w:tc>
|
|
117
|
+
|
|
118
|
+
</w:tr>
|
|
119
|
+
|
|
120
|
+
<w:tr>
|
|
121
|
+
<w:tc>
|
|
122
|
+
<w:tcPr>
|
|
123
|
+
<w:tcW w:w='2000' w:type='dxa'/>
|
|
124
|
+
|
|
125
|
+
<w:vAlign w:val="center"/>
|
|
126
|
+
</w:tcPr>
|
|
127
|
+
<w:p>
|
|
128
|
+
<w:pPr>
|
|
129
|
+
<w:jc w:val='center'/>
|
|
130
|
+
</w:pPr>
|
|
131
|
+
<w:r>
|
|
132
|
+
<w:rPr><w:sz w:val='22'/></w:rPr>
|
|
133
|
+
<w:t>Item 2</w:t>
|
|
134
|
+
</w:r>
|
|
135
|
+
</w:p>
|
|
136
|
+
</w:tc>
|
|
137
|
+
|
|
138
|
+
<w:tc>
|
|
139
|
+
<w:tcPr>
|
|
140
|
+
<w:tcW w:w='1500' w:type='dxa'/>
|
|
65
141
|
|
|
66
142
|
<w:vAlign w:val="center"/>
|
|
67
143
|
</w:tcPr>
|
|
@@ -71,7 +147,7 @@
|
|
|
71
147
|
</w:pPr>
|
|
72
148
|
<w:r>
|
|
73
149
|
<w:rPr><w:sz w:val='22'/></w:rPr>
|
|
74
|
-
<w:t>
|
|
150
|
+
<w:t>200</w:t>
|
|
75
151
|
</w:r>
|
|
76
152
|
</w:p>
|
|
77
153
|
</w:tc>
|
data/lib/oxml_maker/version.rb
CHANGED