oxml_maker 0.1.1 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04e8ffba5e41ae76da239d31522428b1b0ea32f66f6ecf7cbf2a5c81c742a158
4
- data.tar.gz: 44b680d0515bc4081474d741a90ef4e75bb1baac4140dc25f94e54d91d4fa94c
3
+ metadata.gz: 244909709648e421faeca989cd00ef0d58f3de0917b606c36581059781cee835
4
+ data.tar.gz: cabce2d33245226176e2df74efb63a6fc9ae67edbd0f3a660da01dc017dd0996
5
5
  SHA512:
6
- metadata.gz: e861ef91354f8eae531c3863fe24051e5083de602a3f4ba5968affe66c2c8b0f41c229cc6c1b987d7f1b07961827d29610d0ad23d82f175257b98c2f92a785d4
7
- data.tar.gz: 565441a6e469752394a08bde5dd1baf50cb7d4bfc7e8d6d8f07fc9164f1f6354a6450fda223579421c961a9a67091f39578ad29595edd8a891abb877e0e0b494
6
+ metadata.gz: a3ce1886f3d9ef3a8d466e6979f505581bc6b211fd941b28b8bb975dec39f1c8eee90efc1a23919e64d9a9509ab9124644c0a887d9e4c2d182543978bcd1add1
7
+ data.tar.gz: b015b2ef222fe7c4485fd5be0d2c8751bbea8bd3eb98a4151a20910f64e352ce3ee3d26b5dfe44c2f63c406821eb8a92c9a94d5ff59288b21047d1d1940ec0ed
@@ -0,0 +1,5 @@
1
+ {
2
+ "recommendations": [
3
+ "redhat.vscode-xml"
4
+ ]
5
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "xml.format.enabled": true,
3
+ "xml.format.splitAttributes": "preserve",
4
+ "xml.format.joinCDATALines": false,
5
+ "xml.format.joinCommentLines": false,
6
+ "xml.format.joinContentLines": false,
7
+ "xml.format.spaceBeforeEmptyCloseTag": true,
8
+ "xml.format.splitAttributesIndentSize": 2,
9
+ "xml.format.maxLineWidth": 120,
10
+ "xml.format.preservedNewlines": 2,
11
+ "xml.preferences.includeSchemaLocation": "onValidationError",
12
+ "xml.validation.enabled": true,
13
+ "xml.validation.namespaces.enabled": "always",
14
+ "[xml]": {
15
+ "editor.formatOnSave": true,
16
+ "editor.insertSpaces": true,
17
+ "editor.tabSize": 2,
18
+ "editor.indentSize": 2,
19
+ "editor.wordWrap": "on",
20
+ "editor.defaultFormatter": "redhat.vscode-xml"
21
+ },
22
+ "files.associations": {
23
+ "*.xml": "xml"
24
+ },
25
+ "emmet.includeLanguages": {
26
+ "xml": "html"
27
+ }
28
+ }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.3] - 2025-10-21
4
+
5
+ ### Added
6
+ - VS Code development environment configuration
7
+ - `.vscode/settings.json` with XML formatting rules and auto-format on save
8
+ - `.vscode/extensions.json` with recommended XML language support extensions
9
+ - Automatic test artifact cleanup functionality
10
+ - Enhanced development documentation in README
11
+
12
+ ### Enhanced
13
+ - XML template files properly formatted with consistent indentation
14
+ - Development workflow with automatic cleanup of `.docx` and `.zip` files
15
+ - Contributor onboarding experience with VS Code integration
16
+ - Documentation structure for better developer experience
17
+
18
+ ### Developer Experience
19
+ - Cross-platform XML formatting without additional gem dependencies
20
+ - Automatic cleanup of test artifacts from `lib/`, `public/`, and root directories
21
+ - Consistent 2-space indentation for XML files matching Ruby code style
22
+ - Real-time XML validation and IntelliSense support in VS Code
23
+
24
+ ## [0.1.2] - 2025-10-21
25
+
26
+ ### Added
27
+ - Advanced table features: `v_merge` and `new_line` functionality
28
+ - Comprehensive test suite for advanced table features (4 new tests)
29
+ - Support for vertical cell merging in tables
30
+ - Multi-line cell content with comma-separated value splitting
31
+ - Test coverage for complex table scenarios with real-world data examples
32
+
33
+ ### Enhanced
34
+ - Table functionality with advanced formatting capabilities
35
+ - Test suite expanded to 67 tests with 344 assertions
36
+ - Documentation of table feature limitations and implementation details
37
+
3
38
  ## [0.1.1] - 2025-10-20
4
39
 
5
40
  ### Added
data/README.md CHANGED
@@ -6,6 +6,7 @@ A Ruby gem for generating Microsoft Word DOCX files using OpenXML. Create profes
6
6
 
7
7
  - ✅ **Generate Valid DOCX Files**: Creates Microsoft Word-compatible documents
8
8
  - ✅ **Tables with Dynamic Data**: Populate tables from Ruby objects
9
+ - ✅ **Advanced Table Features**: Vertical cell merging (v_merge) and multi-line content (new_line)
9
10
  - ✅ **Paragraphs and Text**: Simple text content with proper XML structure
10
11
  - ✅ **Page Configuration**: Control page size, margins, headers/footers
11
12
  - ✅ **Rails Integration**: Automatically detects Rails environment for file placement
@@ -124,6 +125,46 @@ params = {
124
125
  }
125
126
  ```
126
127
 
128
+ ### Advanced Table Features
129
+
130
+ #### Vertical Cell Merging and Multi-line Content
131
+
132
+ ```ruby
133
+ # Advanced table with v_merge and new_line features
134
+ advanced_table = {
135
+ columns: [
136
+ { name: "Category", width: 1500 },
137
+ { name: "Items", width: 3000 }
138
+ ],
139
+ rows: [
140
+ {
141
+ cells: [
142
+ { value: :category, width: 1500, v_merge: true },
143
+ { value: :items, width: 3000, new_line: true }
144
+ ]
145
+ }
146
+ ],
147
+ data: {
148
+ 0 => [
149
+ OpenStruct.new(category: "Electronics", items: "iPhone, Samsung, Google"),
150
+ OpenStruct.new(category: "Electronics", items: "MacBook, ThinkPad, Dell"),
151
+ OpenStruct.new(category: "Books", items: "Fiction, Non-fiction, Science")
152
+ ]
153
+ },
154
+ font_size: 12
155
+ }
156
+
157
+ # v_merge: true - Merges cells with same values vertically
158
+ # new_line: true - Splits comma-separated values into separate lines
159
+ params = {
160
+ sections: [
161
+ { table: advanced_table }
162
+ ],
163
+ page_size: { width: 12240, height: 15840 },
164
+ page_margin: { top: 1440, right: 1440, bottom: 1440, left: 1440, header: 720, footer: 720, gutter: 0 }
165
+ }
166
+ ```
167
+
127
168
  ### Adding Paragraphs
128
169
 
129
170
  Simple text content with proper XML formatting:
@@ -150,10 +191,227 @@ The gem intelligently handles output location:
150
191
 
151
192
  ## Development
152
193
 
194
+ ### Setup
195
+
153
196
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
154
197
 
155
198
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
156
199
 
200
+ ### 🔧 VS Code Setup for XML Development
201
+
202
+ **Important for Contributors**: This project includes XML template files that benefit from proper formatting and validation.
203
+
204
+ 📖 **See [DEVELOPMENT.md](DEVELOPMENT.md) for detailed contributor guidelines and XML formatting standards.**
205
+
206
+ #### Recommended VS Code Extensions
207
+
208
+ When you open this project in VS Code, you'll be prompted to install recommended extensions:
209
+
210
+ - **XML Language Support** (`redhat.vscode-xml`) - Provides XML formatting, validation, and IntelliSense
211
+ - **JSON Language Features** (`ms-vscode.vscode-json`) - Enhanced JSON editing for configuration files
212
+
213
+ #### Automatic Configuration
214
+
215
+ The project includes `.vscode/settings.json` with pre-configured XML formatting rules:
216
+
217
+ - ✅ **Auto-format on save** for XML files
218
+ - ✅ **2-space indentation** (consistent with Ruby code)
219
+ - ✅ **Line width limit** of 120 characters
220
+ - ✅ **XML validation** enabled
221
+ - ✅ **Attribute splitting** for better readability
222
+
223
+ #### XML File Formatting
224
+
225
+ To format XML files manually:
226
+ 1. Open any `.xml` file in `lib/oxml_maker/docx/`
227
+ 2. Press `Shift+Alt+F` (or `Cmd+Shift+P` → "Format Document")
228
+ 3. Files will auto-format on save when configured
229
+
230
+ This ensures consistent XML formatting across all contributors without additional gem dependencies! 🎨
231
+
232
+ ### 📁 Project Structure
233
+
234
+ ```
235
+ lib/oxml_maker/docx/ # XML template files - keep these formatted!
236
+ ├── [Content_Types].xml
237
+ ├── _rels/
238
+ └── word/
239
+ └── document.xml # Main document template
240
+ ```
241
+
242
+ ### 🧹 Development Cleanup
243
+
244
+ The project includes automatic cleanup of test artifacts:
245
+
246
+ ```bash
247
+ # Run tests with automatic cleanup
248
+ bundle exec rake test_clean
249
+
250
+ # Manual cleanup of .docx and .zip files
251
+ bundle exec rake clean
252
+
253
+ # Regular test run (includes automatic cleanup)
254
+ bundle exec rake test
255
+ ```
256
+
257
+ Test artifacts are automatically removed from:
258
+ - `lib/oxml_maker/` directory
259
+ - `public/` directory
260
+ - Root directory
261
+
262
+ This keeps your workspace clean during development! ✨
263
+
264
+
265
+ ## Why OxmlMaker is Different: The Ruby Object Revolution
266
+
267
+ ### The Problem with Traditional DOCX Gems
268
+
269
+ Most Ruby DOCX libraries force you into rigid patterns:
270
+
271
+ ```ruby
272
+ # Traditional approach - manual, inflexible
273
+ builder.table do |t|
274
+ t.row ["Name", "Age"] # Static arrays only
275
+ t.row ["John", "30"] # Manual string building
276
+ t.row ["Jane", "25"] # Can't use objects directly
277
+ end
278
+ ```
279
+
280
+ ### OxmlMaker's Revolutionary Approach
281
+
282
+ **Direct Ruby Object Mapping** - Use ANY Ruby object with methods:
283
+
284
+ ```ruby
285
+ # Revolutionary - works with ANY objects!
286
+ data: {
287
+ 0 => [
288
+ OpenStruct.new(name: "John", age: 30), # OpenStruct
289
+ User.find(1), # ActiveRecord model
290
+ JSON.parse('{"name": "Jane"}'), # JSON object
291
+ api_response.data, # API response
292
+ custom_object # Any object with methods
293
+ ]
294
+ }
295
+
296
+ # Table automatically calls methods dynamically
297
+ { value: :name } # Calls object.name on each object
298
+ { value: :email } # Calls object.email on each object
299
+ ```
300
+
301
+ ### Perfect for Modern Architectures
302
+
303
+ #### 1. **JSON-Native Design**
304
+ Built for API-first and headless architectures:
305
+
306
+ ```ruby
307
+ # HTML → JSON → DOCX pipeline
308
+ html_content = "<div><h1>Title</h1><table>...</table></div>"
309
+ json_data = html_to_json_parser(html_content)
310
+
311
+ # Direct consumption - no transformation needed!
312
+ doc = OxmlMaker::Document.new(
313
+ filename: "converted.docx",
314
+ params: json_data # Pure JSON input
315
+ )
316
+ ```
317
+
318
+ #### 2. **Polymorphic Data Handling**
319
+ Mix any data sources in the same document:
320
+
321
+ ```ruby
322
+ # Different object types in the same table!
323
+ data: {
324
+ 0 => [
325
+ user_model, # ActiveRecord object
326
+ { name: "Jane" }, # Hash
327
+ OpenStruct.new(name: "Bob"), # OpenStruct
328
+ json_api_response # JSON object
329
+ ]
330
+ }
331
+ ```
332
+
333
+ #### 3. **Configuration-Driven Architecture**
334
+ Documents are pure data structures - serializable and cacheable:
335
+
336
+ ```ruby
337
+ # Store templates as JSON in database
338
+ template = DocumentTemplate.find_by(name: "invoice")
339
+ live_data = Invoice.includes(:line_items).find(params[:id])
340
+
341
+ # Merge template with live data
342
+ params = template.structure.deep_merge({
343
+ sections: [{
344
+ table: {
345
+ data: { 0 => live_data.line_items.to_a } # Direct AR relation!
346
+ }
347
+ }]
348
+ })
349
+ ```
350
+
351
+ ### Comparison with Other Ruby DOCX Gems
352
+
353
+ | Feature | OxmlMaker | Caracal | ruby-docx | docx | sablon |
354
+ |---------|-----------|---------|-----------|------|--------|
355
+ | **Ruby Object Mapping** | ✅ Dynamic | ❌ Manual | ❌ Manual | ❌ Template | ❌ Template |
356
+ | **JSON Serializable** | ✅ 100% | ❌ Code-based | ❌ Code-based | ❌ Template | ❌ Template |
357
+ | **Any Ruby Object** | ✅ Polymorphic | ❌ Arrays only | ❌ Limited | ❌ Static | ❌ Mail merge |
358
+ | **HTML→JSON→DOCX** | ✅ Native | ❌ Complex | ❌ N/A | ❌ N/A | ❌ Template only |
359
+ | **API-Friendly** | ✅ Pure data | ❌ Code required | ❌ Code required | ❌ Files | ❌ Templates |
360
+ | **Microservices Ready** | ✅ Stateless | ❌ Complex | ❌ Complex | ❌ File-based | ❌ Template-based |
361
+
362
+ ### Perfect Use Cases
363
+
364
+ #### **CMS/Blog Export**
365
+ ```ruby
366
+ # Blog post with mixed content types
367
+ post_json = {
368
+ sections: [
369
+ { paragraph: { text: post.title } },
370
+ { table: {
371
+ data: { 0 => post.comments.approved } # Direct relation!
372
+ }
373
+ }
374
+ ]
375
+ }
376
+ ```
377
+
378
+ #### **API Report Generation**
379
+ ```ruby
380
+ # Consume external APIs directly
381
+ api_response = HTTParty.get("https://api.example.com/reports/#{id}")
382
+ json_data = JSON.parse(api_response.body, object_class: OpenStruct)
383
+
384
+ # No transformation needed!
385
+ doc = OxmlMaker::Document.new(params: { sections: json_data.sections })
386
+ ```
387
+
388
+ #### **Dynamic Form Processing**
389
+ ```ruby
390
+ # Form submission → DOCX
391
+ form_data = params[:form_responses] # Frontend JSON
392
+
393
+ document_params = {
394
+ sections: [{
395
+ table: {
396
+ data: { 0 => form_data.map { |item| OpenStruct.new(item) } }
397
+ }
398
+ }]
399
+ }
400
+ ```
401
+
402
+ ### The Architectural Advantage
403
+
404
+ **Zero Impedance Mismatch** - Your data flows directly into documents without transformation layers, making OxmlMaker perfect for:
405
+
406
+ - **Headless CMS** systems
407
+ - **API-first** applications
408
+ - **Microservice** architectures
409
+ - **HTML→DOCX** conversion pipelines
410
+ - **Real-time report** generation
411
+ - **JSON-driven** document templates
412
+
413
+ This isn't just a different API - it's a **fundamentally superior architecture** for modern Ruby applications.
414
+
157
415
  ## Testing
158
416
 
159
417
  ### Test Framework
@@ -166,9 +424,10 @@ The gem uses **Minitest** as its testing framework, which is included in Ruby's
166
424
 
167
425
  ### Current Test Coverage
168
426
 
169
- - **63 tests, 274 assertions, 0 failures, 0 errors**
427
+ - **67 tests, 344 assertions, 0 failures, 0 errors**
170
428
  - Unit tests for all classes (Document, Paragraph, Table)
171
429
  - Integration tests for complete workflows
430
+ - Advanced table feature tests (v_merge, new_line)
172
431
  - ZIP functionality tests with rubyzip
173
432
  - Rails environment detection tests
174
433
  - Error handling and edge case tests
@@ -259,23 +518,6 @@ def test_created_zip_is_valid_docx
259
518
  end
260
519
  ```
261
520
 
262
- ### Testing Best Practices
263
-
264
- 1. **Use Setup and Teardown** for consistent test environments
265
- 2. **Test Edge Cases** including empty inputs, nil values, and special characters
266
- 3. **Use Descriptive Test Names** that explain what is being tested
267
- 4. **Test Both Success and Failure Paths** to ensure robust error handling
268
- 5. **Mock External Dependencies** when needed (Rails environment, file systems)
269
-
270
- ### Common Assertions
271
-
272
- - `assert_equal expected, actual` - Test equality
273
- - `assert_includes collection, item` - Test inclusion
274
- - `assert_raises(ExceptionClass) { code }` - Test exceptions
275
- - `assert condition` - Test truthiness
276
- - `refute condition` - Test falsiness
277
- - `assert_kind_of Class, object` - Test object type
278
-
279
521
  ## Dependencies
280
522
 
281
523
  - **rubyzip (~> 3.2)** - For ZIP file creation and DOCX generation
@@ -284,7 +526,7 @@ end
284
526
 
285
527
  ## Contributing
286
528
 
287
- Bug reports and pull requests are welcome on GitHub at https://github.com/mode-x/oxml_maker. 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/mode-x/oxml_maker/blob/master/CODE_OF_CONDUCT.md).
529
+ Bug reports and pull requests are welcome on GitHub at https://github.com/airbearr/oxml_maker. 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/airbearr/oxml_maker/blob/master/CODE_OF_CONDUCT.md).
288
530
 
289
531
  ## License
290
532
 
@@ -292,4 +534,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
292
534
 
293
535
  ## Code of Conduct
294
536
 
295
- Everyone interacting in the OxmlMaker project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/mode-x/oxml_maker/blob/master/CODE_OF_CONDUCT.md).
537
+ Everyone interacting in the OxmlMaker project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/airbearr/oxml_maker/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -9,4 +9,53 @@ require "rubocop/rake_task"
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
12
+ # Cleanup tasks
13
+ desc "Clean up test artifacts (docx and zip files)"
14
+ task :clean do
15
+ require "fileutils"
16
+
17
+ puts "Cleaning up test artifacts..."
18
+
19
+ # Clean up public directory
20
+ public_dir = File.join(Dir.pwd, "public")
21
+ if Dir.exist?(public_dir)
22
+ docx_files = Dir.glob(File.join(public_dir, "*.docx"))
23
+ zip_files = Dir.glob(File.join(public_dir, "*.zip"))
24
+
25
+ docx_files.each { |f| FileUtils.rm_f(f) }
26
+ zip_files.each { |f| FileUtils.rm_f(f) }
27
+
28
+ removed_count = docx_files.length + zip_files.length
29
+ puts "Removed #{removed_count} files from public directory" if removed_count > 0
30
+ end
31
+
32
+ # Clean up lib/oxml_maker directory
33
+ lib_dir = File.join(Dir.pwd, "lib", "oxml_maker")
34
+ if Dir.exist?(lib_dir)
35
+ lib_docx_files = Dir.glob(File.join(lib_dir, "*.docx"))
36
+ lib_zip_files = Dir.glob(File.join(lib_dir, "*.zip"))
37
+
38
+ lib_docx_files.each { |f| FileUtils.rm_f(f) }
39
+ lib_zip_files.each { |f| FileUtils.rm_f(f) }
40
+
41
+ lib_removed_count = lib_docx_files.length + lib_zip_files.length
42
+ puts "Removed #{lib_removed_count} files from lib/oxml_maker directory" if lib_removed_count > 0
43
+ end
44
+
45
+ # Clean up root directory
46
+ root_docx = Dir.glob("*.docx")
47
+ root_zip = Dir.glob("*.zip")
48
+
49
+ root_docx.each { |f| FileUtils.rm_f(f) }
50
+ root_zip.each { |f| FileUtils.rm_f(f) }
51
+
52
+ root_removed = root_docx.length + root_zip.length
53
+ puts "Removed #{root_removed} files from root directory" if root_removed > 0
54
+
55
+ puts "Cleanup completed!"
56
+ end
57
+
58
+ desc "Run tests with automatic cleanup"
59
+ task test_clean: %i[clean test clean]
60
+
12
61
  task default: %i[test rubocop]
@@ -3,7 +3,7 @@
3
3
  <w:body>
4
4
  <w:p>
5
5
  <w:r>
6
- <w:t>Test with special chars: & < > " '</w:t>
6
+ <w:t>Document Title - Integration Test</w:t>
7
7
  </w:r>
8
8
  </w:p>
9
9
 
@@ -25,6 +25,8 @@
25
25
  </w:tblPr>
26
26
  <w:tblGrid>
27
27
  <w:gridCol w:w="3000"/>
28
+ <w:gridCol w:w="2000"/>
29
+ <w:gridCol w:w="1500"/>
28
30
  </w:tblGrid>
29
31
  <w:tr>
30
32
  <w:tblPrEx>
@@ -50,9 +52,51 @@
50
52
  <w:r>
51
53
  <w:rPr>
52
54
  <w:b/>
53
- <w:sz w:val="22"/>
55
+ <w:sz w:val="24"/>
54
56
  </w:rPr>
55
- <w:t>Data & Info</w:t>
57
+ <w:t>Product</w:t>
58
+ </w:r>
59
+ </w:p>
60
+ </w:tc>
61
+
62
+ <w:tc>
63
+ <w:tcPr>
64
+ <w:tcW w:w="2000"/>
65
+ </w:tcPr>
66
+ <w:p>
67
+ <w:pPr>
68
+ <w:jc w:val="center"/>
69
+ <w:rPr>
70
+ <w:b/>
71
+ </w:rPr>
72
+ </w:pPr>
73
+ <w:r>
74
+ <w:rPr>
75
+ <w:b/>
76
+ <w:sz w:val="24"/>
77
+ </w:rPr>
78
+ <w:t>Price</w:t>
79
+ </w:r>
80
+ </w:p>
81
+ </w:tc>
82
+
83
+ <w:tc>
84
+ <w:tcPr>
85
+ <w:tcW w:w="1500"/>
86
+ </w:tcPr>
87
+ <w:p>
88
+ <w:pPr>
89
+ <w:jc w:val="center"/>
90
+ <w:rPr>
91
+ <w:b/>
92
+ </w:rPr>
93
+ </w:pPr>
94
+ <w:r>
95
+ <w:rPr>
96
+ <w:b/>
97
+ <w:sz w:val="24"/>
98
+ </w:rPr>
99
+ <w:t>Quantity</w:t>
56
100
  </w:r>
57
101
  </w:p>
58
102
  </w:tc>
@@ -70,8 +114,150 @@
70
114
  <w:jc w:val='center'/>
71
115
  </w:pPr>
72
116
  <w:r>
73
- <w:rPr><w:sz w:val='22'/></w:rPr>
74
- <w:t>Content with &lt;tags&gt; &amp; symbols</w:t>
117
+ <w:rPr><w:sz w:val='24'/></w:rPr>
118
+ <w:t>Widget A</w:t>
119
+ </w:r>
120
+ </w:p>
121
+ </w:tc>
122
+
123
+ <w:tc>
124
+ <w:tcPr>
125
+ <w:tcW w:w='2000' w:type='dxa'/>
126
+
127
+ <w:vAlign w:val="center"/>
128
+ </w:tcPr>
129
+ <w:p>
130
+ <w:pPr>
131
+ <w:jc w:val='center'/>
132
+ </w:pPr>
133
+ <w:r>
134
+ <w:rPr><w:sz w:val='24'/></w:rPr>
135
+ <w:t>$10.99</w:t>
136
+ </w:r>
137
+ </w:p>
138
+ </w:tc>
139
+
140
+ <w:tc>
141
+ <w:tcPr>
142
+ <w:tcW w:w='1500' w:type='dxa'/>
143
+
144
+ <w:vAlign w:val="center"/>
145
+ </w:tcPr>
146
+ <w:p>
147
+ <w:pPr>
148
+ <w:jc w:val='center'/>
149
+ </w:pPr>
150
+ <w:r>
151
+ <w:rPr><w:sz w:val='24'/></w:rPr>
152
+ <w:t>5</w:t>
153
+ </w:r>
154
+ </w:p>
155
+ </w:tc>
156
+
157
+ </w:tr>
158
+
159
+ <w:tr>
160
+ <w:tc>
161
+ <w:tcPr>
162
+ <w:tcW w:w='3000' w:type='dxa'/>
163
+
164
+ <w:vAlign w:val="center"/>
165
+ </w:tcPr>
166
+ <w:p>
167
+ <w:pPr>
168
+ <w:jc w:val='center'/>
169
+ </w:pPr>
170
+ <w:r>
171
+ <w:rPr><w:sz w:val='24'/></w:rPr>
172
+ <w:t>Gadget B</w:t>
173
+ </w:r>
174
+ </w:p>
175
+ </w:tc>
176
+
177
+ <w:tc>
178
+ <w:tcPr>
179
+ <w:tcW w:w='2000' w:type='dxa'/>
180
+
181
+ <w:vAlign w:val="center"/>
182
+ </w:tcPr>
183
+ <w:p>
184
+ <w:pPr>
185
+ <w:jc w:val='center'/>
186
+ </w:pPr>
187
+ <w:r>
188
+ <w:rPr><w:sz w:val='24'/></w:rPr>
189
+ <w:t>$25.50</w:t>
190
+ </w:r>
191
+ </w:p>
192
+ </w:tc>
193
+
194
+ <w:tc>
195
+ <w:tcPr>
196
+ <w:tcW w:w='1500' w:type='dxa'/>
197
+
198
+ <w:vAlign w:val="center"/>
199
+ </w:tcPr>
200
+ <w:p>
201
+ <w:pPr>
202
+ <w:jc w:val='center'/>
203
+ </w:pPr>
204
+ <w:r>
205
+ <w:rPr><w:sz w:val='24'/></w:rPr>
206
+ <w:t>3</w:t>
207
+ </w:r>
208
+ </w:p>
209
+ </w:tc>
210
+
211
+ </w:tr>
212
+
213
+ <w:tr>
214
+ <w:tc>
215
+ <w:tcPr>
216
+ <w:tcW w:w='3000' w:type='dxa'/>
217
+
218
+ <w:vAlign w:val="center"/>
219
+ </w:tcPr>
220
+ <w:p>
221
+ <w:pPr>
222
+ <w:jc w:val='center'/>
223
+ </w:pPr>
224
+ <w:r>
225
+ <w:rPr><w:sz w:val='24'/></w:rPr>
226
+ <w:t>Tool C</w:t>
227
+ </w:r>
228
+ </w:p>
229
+ </w:tc>
230
+
231
+ <w:tc>
232
+ <w:tcPr>
233
+ <w:tcW w:w='2000' w:type='dxa'/>
234
+
235
+ <w:vAlign w:val="center"/>
236
+ </w:tcPr>
237
+ <w:p>
238
+ <w:pPr>
239
+ <w:jc w:val='center'/>
240
+ </w:pPr>
241
+ <w:r>
242
+ <w:rPr><w:sz w:val='24'/></w:rPr>
243
+ <w:t>$45.00</w:t>
244
+ </w:r>
245
+ </w:p>
246
+ </w:tc>
247
+
248
+ <w:tc>
249
+ <w:tcPr>
250
+ <w:tcW w:w='1500' w:type='dxa'/>
251
+
252
+ <w:vAlign w:val="center"/>
253
+ </w:tcPr>
254
+ <w:p>
255
+ <w:pPr>
256
+ <w:jc w:val='center'/>
257
+ </w:pPr>
258
+ <w:r>
259
+ <w:rPr><w:sz w:val='24'/></w:rPr>
260
+ <w:t>1</w:t>
75
261
  </w:r>
76
262
  </w:p>
77
263
  </w:tc>
@@ -80,6 +266,12 @@
80
266
 
81
267
  </w:tbl>
82
268
 
269
+ <w:p>
270
+ <w:r>
271
+ <w:t>End of Report</w:t>
272
+ </w:r>
273
+ </w:p>
274
+
83
275
  <w:sectPr>
84
276
  <w:pgSz w:w='12240' w:h='15840'/>
85
277
  <w:pgMar w:top='1440' w:right='1440' w:bottom='1440' w:left='1440' w:header='720' w:footer='720' w:gutter='0'/>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OxmlMaker
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oxml_maker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - airbearr
@@ -33,6 +33,8 @@ extensions: []
33
33
  extra_rdoc_files: []
34
34
  files:
35
35
  - ".rubocop.yml"
36
+ - ".vscode/extensions.json"
37
+ - ".vscode/settings.json"
36
38
  - CHANGELOG.md
37
39
  - CODE_OF_CONDUCT.md
38
40
  - LICENSE.txt
@@ -47,14 +49,14 @@ files:
47
49
  - lib/oxml_maker/table.rb
48
50
  - lib/oxml_maker/version.rb
49
51
  - sig/oxml_maker.rbs
50
- homepage: https://github.com/mode-x/oxml_maker
52
+ homepage: https://github.com/airbearr/oxml_maker
51
53
  licenses:
52
54
  - MIT
53
55
  metadata:
54
56
  allowed_push_host: https://rubygems.org
55
- homepage_uri: https://github.com/mode-x/oxml_maker
56
- source_code_uri: https://github.com/mode-x/oxml_maker
57
- changelog_uri: https://github.com/mode-x/oxml_maker/blob/main/CHANGELOG.md
57
+ homepage_uri: https://github.com/airbearr/oxml_maker
58
+ source_code_uri: https://github.com/airbearr/oxml_maker
59
+ changelog_uri: https://github.com/airbearr/oxml_maker/blob/main/CHANGELOG.md
58
60
  rubygems_mfa_required: 'true'
59
61
  rdoc_options: []
60
62
  require_paths: