The Ruby API is the primary interface for working with Uniword. It provides four layers of abstraction for creating, reading, and modifying OOXML documents.

1. Document lifecycle

Every Uniword workflow follows one of two paths:

Create from scratch — Build a new document using Document.new or the fluent Builder API, then save it.

Load and modify — Open an existing DOCX or MHTML file with DocumentFactory.from_file, modify the content, and save it back.

# Create
doc = Uniword::Document.new
doc.add_paragraph("Hello World")
doc.save("output.docx")

# Load and modify
doc = Uniword::DocumentFactory.from_file("input.docx")
doc.add_paragraph("Appended paragraph")
doc.save("modified.docx")

2. Builder API

The Builder provides a fluent, declarative interface for constructing documents. Each method returns the builder, allowing method chaining.

doc = Uniword::Builder.new
  .add_heading("My Document", level: 1)
  .add_paragraph("Introduction paragraph")
  .add_table do
    row do
      cell "Header 1", bold: true
      cell "Header 2", bold: true
    end
    row do
      cell "Data 1"
      cell "Data 2"
    end
  end
  .build

See Builder API for the full reference.

3. Model classes

Beneath the Builder, Uniword exposes a complete set of OOXML model classes representing 760 elements across 22 namespaces. Every class inherits from Lutaml::Model::Serializable and supports automatic XML serialization.

# Direct model manipulation
para = Uniword::Paragraph.new
para.add_text("Bold text", bold: true)

table = Uniword::Table.new
row = Uniword::TableRow.new
cell = Uniword::TableCell.new
cell.add_paragraph("Cell content")
row.add_cell(cell)
table.add_row(row)

4. Resource system

Uniword ships with open-source resources that replace proprietary Microsoft Word assets:

  • Themes — 29 bundled color and font schemes (.thmx or YAML)

  • StyleSets — 12 bundled style definitions (.dotx or YAML)

  • Document elements — 240 templates across 30 locales

# Apply a theme and styleset
doc.apply_theme("celestial")
doc.apply_styleset("distinctive")

5. Feature API

DocumentRoot provides convenience methods for common document operations. All mutator methods return self for chaining.

5.1. Review (comments & tracked changes)

doc.list_comments                          # => Array<Comment>
doc.add_comment(text: "Fix", author: "Al") # => self
doc.accept_all_changes                     # => self
doc.reject_all_changes                     # => self
doc.clear_comments                         # => self

5.2. Document comparison

# Document-level: content, formatting, structure, metadata, styles
result = doc.diff(other_doc)
result = doc.diff(other_doc, text_only: true)
# => DiffResult with text_changes, format_changes, structure_changes,
#    metadata_changes, style_changes

# Package-level: ZIP parts, XML content, OPC validation
require "uniword/diff/package_differ"
result = Uniword::Diff::PackageDiffer.new("old.docx", "new.docx",
  canon: true).diff
# => PackageDiffResult with added/removed/modified parts,
#    zip_metadata_changes, opc_issues, canon equivalence

5.3. Spell and grammar checking

result = doc.spellcheck              # default: en_US
result = doc.spellcheck(language: "en_GB")
# => SpellcheckResult with misspellings, grammar_issues, clean?

5.4. Image management

doc.list_images                    # => Array<ImageInfo>
doc.extract_images("/tmp/imgs")    # => Integer (count)
doc.insert_image("photo.png",
      width: "6in", height: "4in") # => self
doc.remove_image("image1.png")     # => self

5.5. Watermarks

doc.add_watermark("DRAFT",
      color: "#FF0000", font_size: 96)  # => self
doc.remove_watermark                      # => self
doc.watermark?                            # => true/false
doc.list_watermarks                       # => Array<String>

5.6. Table of Contents

entries = doc.generate_toc(max_level: 3)
# => Array<TocEntry> with level, text, style_name, paragraph_index

doc.insert_toc(position: 0, max_level: 3) # => self
doc.update_toc(max_level: 6)              # => self

5.7. Headers & footers

doc.list_headers                   # => Array<Hash>
doc.list_footers                   # => Array<Hash>
doc.add_header("Confidential",
      type: "default")             # => self
doc.add_footer("Page 1")          # => self
doc.remove_headers(type: "first") # => self
doc.remove_footers(type: "even")  # => self

5.8. Document protection

doc.protect(:read_only, password: "secret")  # => self
doc.protect(:tracked_changes)                # => self
doc.protection_active?                       # => true/false
doc.protection_info                          # => Hash or nil
doc.unprotect                                # => self

5.9. Chaining

All mutator methods return self, enabling fluent chains:

doc = Uniword.load("report.docx")
doc.add_comment(text: "Reviewed", author: "QA")
    .add_watermark("APPROVED", color: "#008000")
    .insert_toc(max_level: 3)
    .protect(:comments)
    .save("final.docx")

6. Document styling API

These methods on DocumentRoot (extracted to Wordprocessingml::DocumentStyling internally in 1.4.0; signatures unchanged) apply themes, StyleSets, and scheme-level font and color replacements:

doc.apply_theme("meridian")                # full theme (colors + fonts + formats)
doc.apply_theme_file("Atlas.thmx")         # from a .thmx file
doc.apply_styleset("signature")            # StyleSet (paragraph/char/table styles)
doc.apply_color_scheme("emerald")          # Design → Colors gallery
doc.apply_font_scheme("carlito_sans")      # Design → Fonts gallery
doc.auto_transition_theme                  # MS theme → Uniword equivalent

7. Styles API

Inspect and manage the document’s styles. The CLI surfaces these via uniword styles (see styles command).

doc.styles_configuration.styles.each do |style|
  puts "#{style.styleId} (#{style.type})"
end

doc.rename_style("Heading1", "Chapter Title")  # returns true / false
doc.remove_style("ObsoleteStyle")              # returns the Style or nil (1.4+)

cleanup = Uniword::Wordprocessingml::StyleCleanup.new(doc)
cleanup.unused_ids       # => Array<String> of unreferenced style ids
cleanup.remove_unused    # removes them; returns the removed ids

8. Find-and-replace API

Method Replaces

doc.replace_font(from:, to:)

One font family throughout body, styles, headers/footers, notes, comments, numbering (Word’s Replace Fonts)

doc.apply_page_setup(size:, orientation:, margins:, top:, right:, bottom:, left:)

Page size, orientation, and margins on every section (Word’s Page Setup dialog)

doc.replace_font(from: "Calibri", to: "Carlito")

doc.apply_page_setup(
  size:        "a4",
  orientation: "landscape",
  margins:     "1in",
  top:         "1.5in"
)

9. Comments API (1.3+)

Comments are anchored to a paragraph and round-trip through word/comments.xml.

doc.add_comment(text: "Fix this", author: "Al")           # at end of body
doc.list_comments                                        # => Array<Comment>
doc.clear_comments                                       # remove all

# Anchored comments via Builder
builder.add_paragraph("Claim").comment(
  text: "Citation needed", author: "QA", on: :paragraph
)

10. Verification, validation, and repair

Three layers of correctness checking, all scriptable:

# In-memory model rules -- DOC-200/201/202/203/204/205
issues = Uniword::Validation::Engine.run(
  Uniword::Validation::Rules::ModelContext.new(doc)
)
issues.each { |i| puts "#{i.code}: #{i.message}" }

# Three-layer pipeline: OPC + XSD + semantic
result = Uniword::Verification.verify("report.docx", xsd: true)
puts result.valid?
puts result.issues.count

The Reconciler runs automatically on every save. To see what was repaired:

# Saves always reconcile; capture issues by hooking save:
begin
  doc.save("output.docx")
rescue Uniword::ValidationError => e
  e.issues.each { |i| puts "#{i.code}: #{i.message}" }
end

11. Topics


Table of contents