Class: Uniword::Builder::DocumentBuilder

Inherits:
BaseBuilder show all
Defined in:
lib/uniword/builder/document_builder.rb

Overview

Builds and configures DocumentRoot objects.

Top-level builder for creating Word documents.

Examples:

Create a new document

doc = DocumentBuilder.new
doc.paragraph { |p| p << 'Hello World' }
doc.heading('Title', level: 1)
doc.save('output.docx')

Load and modify a document

doc = DocumentBuilder.from_file('template.docx')
doc.paragraph { |p| p << 'New content' }
doc.save('modified.docx')

Complete document

doc = DocumentBuilder.new
doc.title('Report').author('Author')
doc.theme('atlas')
doc.toc
doc.heading('Introduction', level: 1)
doc.paragraph { |p| p << 'Content...' }
doc.bullet_list { |l| l.item('First'); l.item('Second') }
doc.page_break
doc.footer { |f| f << Builder.page_number_field }
doc.save('report.docx')

Instance Attribute Summary

Attributes inherited from BaseBuilder

#model

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseBuilder

#build, from_model

Constructor Details

#initialize(model = nil) ⇒ DocumentBuilder

Returns a new instance of DocumentBuilder.



36
37
38
39
40
41
# File 'lib/uniword/builder/document_builder.rb', line 36

def initialize(model = nil)
  super
  @bookmark_counter = 0
  @footnote_builder = FootnoteBuilder.new(self)
  @comment_counter = 0
end

Class Method Details

.default_model_classObject



32
33
34
# File 'lib/uniword/builder/document_builder.rb', line 32

def self.default_model_class
  Wordprocessingml::DocumentRoot
end

.from_file(path) ⇒ DocumentBuilder

Load a document from file for manipulation

Parameters:

  • path (String)

    Path to .docx file

Returns:



47
48
49
# File 'lib/uniword/builder/document_builder.rb', line 47

def self.from_file(path)
  new(Uniword.load(path))
end

Instance Method Details

#<<(element) ⇒ self

Append a top-level element (paragraph or table)

Parameters:

Returns:

  • (self)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/uniword/builder/document_builder.rb', line 55

def <<(element)
  case element
  when Wordprocessingml::Paragraph
    @model.body.paragraphs << element
  when Wordprocessingml::Table
    @model.body.tables << element
  when ParagraphBuilder
    @model.body.paragraphs << element.build
  when TableBuilder
    @model.body.tables << element.build
  else
    raise ArgumentError, "Cannot add #{element.class} to document"
  end
  self
end

#apply_styleset(name, strategy: :keep_existing) ⇒ self

Apply a bundled styleset to the document

Parameters:

  • name (String)

    Styleset name (e.g., ‘formal’, ‘modern’, ‘elegant’)

  • strategy (Symbol) (defaults to: :keep_existing)

    Conflict resolution (:keep_existing, :replace, :rename)

Returns:

  • (self)


297
298
299
300
# File 'lib/uniword/builder/document_builder.rb', line 297

def apply_styleset(name, strategy: :keep_existing)
  @model.apply_styleset(name, strategy: strategy)
  self
end

#author(value) ⇒ Object



262
263
264
265
# File 'lib/uniword/builder/document_builder.rb', line 262

def author(value)
  @model.core_properties.creator = value
  self
end

#bibliography(style: "APA") {|BibliographyBuilder| ... } ⇒ BibliographyBuilder

Create and configure bibliography sources

Parameters:

  • style (String) (defaults to: "APA")

    Citation style (default ‘APA’)

Yields:

Returns:



426
427
428
429
430
431
# File 'lib/uniword/builder/document_builder.rb', line 426

def bibliography(style: "APA", &block)
  bib = BibliographyBuilder.new(style: style)
  block.call(bib) if block_given?
  bib.attach(self)
  bib
end

#bibliography_placeholderself

Insert a bibliography placeholder (SDT content control)

Returns:

  • (self)


436
437
438
439
440
441
442
# File 'lib/uniword/builder/document_builder.rb', line 436

def bibliography_placeholder
  sdt = SdtBuilder.bibliography.build
  para = Wordprocessingml::Paragraph.new
  para.sdts << sdt
  @model.body.paragraphs << para
  self
end

#bookmark(name) {|ParagraphBuilder| ... } ⇒ ParagraphBuilder

Create a bookmark wrapping the next content

Parameters:

  • name (String)

    Bookmark name

Yields:

Returns:



200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/uniword/builder/document_builder.rb', line 200

def bookmark(name, &block)
  @bookmark_counter += 1
  id = @bookmark_counter.to_s

  para = ParagraphBuilder.new
  para.model.bookmark_starts <<
    Wordprocessingml::BookmarkStart.new(id: id, name: name)
  block.call(para) if block_given?
  para.model.bookmark_ends <<
    Wordprocessingml::BookmarkEnd.new(id: id)
  @model.body.paragraphs << para.build
  para
end

#bullet_list {|ListBuilder| ... } ⇒ ListBuilder

Shorthand: create a bullet list

Yields:

Returns:



191
192
193
# File 'lib/uniword/builder/document_builder.rb', line 191

def bullet_list(&)
  list(type: :bullet, &)
end

#chart(type: :bar, width: nil, height: nil) {|ChartBuilder| ... } ⇒ ChartBuilder

Insert a chart into the document

Parameters:

  • type (Symbol) (defaults to: :bar)

    Chart type (:bar, :line, :pie, default :bar)

  • width (Integer) (defaults to: nil)

    Width in EMU (default 5486400 ≈ 6 inches)

  • height (Integer) (defaults to: nil)

    Height in EMU (default 3200400 ≈ 3.5 inches)

Yields:

Returns:



451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/uniword/builder/document_builder.rb', line 451

def chart(type: :bar, width: nil, height: nil, &block)
  cb = ChartBuilder.new(chart_type: type)
  cb.dimensions(width: width, height: height) if width || height
  block.call(cb) if block_given?

  drawing = cb.build_drawing(self)
  run = Wordprocessingml::Run.new
  run.drawings << drawing
  para = Wordprocessingml::Paragraph.new
  para.runs << run
  @model.body.paragraphs << para
  cb
end

#comment(author:, text: nil, initials: nil) {|CommentBuilder| ... } ⇒ Comment

Create a comment and store it in the document’s comments collection.

Parameters:

  • author (String)

    Comment author name

  • text (String, nil) (defaults to: nil)

    Comment text

  • initials (String, nil) (defaults to: nil)

    Author initials

Yields:

Returns:

  • (Comment)

    The created Comment model



391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/uniword/builder/document_builder.rb', line 391

def comment(author:, text: nil, initials: nil, &block)
  @comment_counter += 1
  cb = CommentBuilder.new(
    author: author,
    comment_id: @comment_counter.to_s,
    initials: initials
  )
  cb << text if text
  block.call(cb) if block_given?
  comment_obj = cb.build
  @model.comments ||= []
  @model.comments << comment_obj
  comment_obj
end

#content_control(tag: nil, alias_name: nil, placeholder_text: nil) ⇒ SdtBuilder

Create a text content control paragraph

Parameters:

  • tag (String, nil) (defaults to: nil)

    Developer tag

  • alias_name (String, nil) (defaults to: nil)

    Display name

  • placeholder_text (String, nil) (defaults to: nil)

    Placeholder text

Returns:



412
413
414
415
416
417
418
419
# File 'lib/uniword/builder/document_builder.rb', line 412

def content_control(tag: nil, alias_name: nil, placeholder_text: nil)
  sdt = SdtBuilder.text(
    tag: tag, alias_name: alias_name,
    placeholder_text: placeholder_text
  )
  @model.body.paragraphs.last&.sdts&.<<(sdt.build)
  sdt
end

#created(value) ⇒ Object



282
283
284
285
# File 'lib/uniword/builder/document_builder.rb', line 282

def created(value)
  @model.core_properties.created = value
  self
end

#date_field(format: "M/d/yyyy") ⇒ self

Insert a date paragraph

Parameters:

  • format (String) (defaults to: "M/d/yyyy")

    Date format (default ‘M/d/yyyy’)

Returns:

  • (self)


485
486
487
488
# File 'lib/uniword/builder/document_builder.rb', line 485

def date_field(format: "M/d/yyyy")
  @model.body.paragraphs << Builder.date_field(format: format)
  self
end

#define_style(name, base_on: "Normal") {|StyleBuilder| ... } ⇒ StyleBuilder

Define a paragraph style

Parameters:

  • name (String)

    Style name

  • base_on (String) (defaults to: "Normal")

    Base style (default ‘Normal’)

Yields:

Returns:



250
251
252
253
254
255
# File 'lib/uniword/builder/document_builder.rb', line 250

def define_style(name, base_on: "Normal", &block)
  style = StyleBuilder.new(name, base_on: base_on)
  block.call(style) if block_given?
  @model.styles_configuration.add_style(style.build)
  style
end

#description(value) ⇒ Object



267
268
269
270
# File 'lib/uniword/builder/document_builder.rb', line 267

def description(value)
  @model.core_properties.description = value
  self
end

#endnote(text = nil) {|ParagraphBuilder| ... } ⇒ Wordprocessingml::Run

Create an endnote and return a Run with an endnoteReference.

Parameters:

  • text (String) (defaults to: nil)

    Endnote text

Yields:

Returns:



228
229
230
# File 'lib/uniword/builder/document_builder.rb', line 228

def endnote(text = nil, &)
  @footnote_builder.endnote(text, &)
end

#floating_image(path, width: nil, height: nil, alt_text: nil, align: nil, vertical_align: nil, wrap: :square, behind_text: false) ⇒ self

Insert a floating image paragraph

Parameters:

  • path (String)

    Path to image file

  • width (Integer, nil) (defaults to: nil)

    Width in EMU

  • height (Integer, nil) (defaults to: nil)

    Height in EMU

  • alt_text (String, nil) (defaults to: nil)

    Alternative text

  • align (Symbol, nil) (defaults to: nil)

    Horizontal alignment (:left, :center, :right)

  • vertical_align (Symbol, nil) (defaults to: nil)

    Vertical alignment (:top, :middle, :bottom)

  • wrap (Symbol) (defaults to: :square)

    Text wrapping (:square, :none, :top_and_bottom)

  • behind_text (Boolean) (defaults to: false)

    Place image behind text

Returns:

  • (self)


345
346
347
348
349
350
351
352
353
354
355
# File 'lib/uniword/builder/document_builder.rb', line 345

def floating_image(path, width: nil, height: nil, alt_text: nil,
                   align: nil, vertical_align: nil, wrap: :square,
                   behind_text: false)
  para = Wordprocessingml::Paragraph.new
  para.runs << ImageBuilder.create_floating_run(
    self, path, width: width, height: height, alt_text: alt_text,
                align: align, wrap: wrap, behind_text: behind_text
  )
  @model.body.paragraphs << para
  self
end

Configure a footer

Parameters:

  • type (String) (defaults to: "default")

    Footer type (‘default’, ‘first’, ‘even’)

Yields:

Returns:



149
150
151
152
153
154
# File 'lib/uniword/builder/document_builder.rb', line 149

def footer(type: "default", &block)
  hf = HeaderFooterBuilder.new(:footer, type: type)
  block.call(hf) if block_given?
  (@model.footers ||= {})[type] = hf.build
  hf
end

#footnote(text = nil) {|ParagraphBuilder| ... } ⇒ Wordprocessingml::Run

Create a footnote and return a Run with a footnoteReference.

Parameters:

  • text (String) (defaults to: nil)

    Footnote text

Yields:

Returns:



219
220
221
# File 'lib/uniword/builder/document_builder.rb', line 219

def footnote(text = nil, &)
  @footnote_builder.footnote(text, &)
end

#header(type: "default") {|HeaderFooterBuilder| ... } ⇒ HeaderFooterBuilder

Configure a header

Parameters:

  • type (String) (defaults to: "default")

    Header type (‘default’, ‘first’, ‘even’)

Yields:

Returns:



137
138
139
140
141
142
# File 'lib/uniword/builder/document_builder.rb', line 137

def header(type: "default", &block)
  hf = HeaderFooterBuilder.new(:header, type: type)
  block.call(hf) if block_given?
  (@model.headers ||= {})[type] = hf.build
  hf
end

#heading(text, level: 1) {|ParagraphBuilder| ... } ⇒ ParagraphBuilder

Create and add a heading paragraph

Parameters:

  • text (String)

    Heading text

  • level (Integer) (defaults to: 1)

    Heading level (1-9, default 1)

Yields:

Returns:



90
91
92
93
94
95
96
# File 'lib/uniword/builder/document_builder.rb', line 90

def heading(text, level: 1)
  para = ParagraphBuilder.new
  para.style = "Heading#{level}"
  para << text
  @model.body.paragraphs << para.build
  para
end

#horizontal_rule(style: "single", color: "auto", size: 6) ⇒ self

Insert a horizontal rule (paragraph with bottom border)

Parameters:

  • style (String) (defaults to: "single")

    Border style (default ‘single’)

  • color (String) (defaults to: "auto")

    Border color (default ‘auto’)

  • size (Integer) (defaults to: 6)

    Border size in eighths of a point (default 6)

Returns:

  • (self)


308
309
310
311
312
313
314
315
316
# File 'lib/uniword/builder/document_builder.rb', line 308

def horizontal_rule(style: "single", color: "auto", size: 6)
  para = ParagraphBuilder.new
  para.borders(
    bottom: { style: style, color: color, size: size }
  )
  para.spacing(after: 0)
  @model.body.paragraphs << para.build
  self
end

#image(path, width: nil, height: nil, alt_text: nil) ⇒ self

Insert an inline image paragraph

Parameters:

  • path (String)

    Path to image file

  • width (Integer, nil) (defaults to: nil)

    Width in EMU (914400 = 1 inch)

  • height (Integer, nil) (defaults to: nil)

    Height in EMU

  • alt_text (String, nil) (defaults to: nil)

    Alternative text

Returns:

  • (self)


325
326
327
328
329
330
331
332
# File 'lib/uniword/builder/document_builder.rb', line 325

def image(path, width: nil, height: nil, alt_text: nil)
  para = Wordprocessingml::Paragraph.new
  para.runs << ImageBuilder.create_run(
    self, path, width: width, height: height, alt_text: alt_text
  )
  @model.body.paragraphs << para
  self
end

#keywords(value) ⇒ Object



277
278
279
280
# File 'lib/uniword/builder/document_builder.rb', line 277

def keywords(value)
  @model.core_properties.keywords = value
  self
end

#list(type: :bullet) {|ListBuilder| ... } ⇒ ListBuilder

Create a list (bulleted or numbered)

Parameters:

  • type (Symbol) (defaults to: :bullet)

    List type (:bullet, :decimal, :roman, :letter)

Yields:

Returns:



173
174
175
176
177
# File 'lib/uniword/builder/document_builder.rb', line 173

def list(type: :bullet, &block)
  lb = ListBuilder.new(self, type: type)
  block.call(lb) if block_given?
  lb
end

#modified(value) ⇒ Object



287
288
289
290
# File 'lib/uniword/builder/document_builder.rb', line 287

def modified(value)
  @model.core_properties.modified = value
  self
end

#numbered_list {|ListBuilder| ... } ⇒ ListBuilder

Shorthand: create a numbered list

Yields:

Returns:



183
184
185
# File 'lib/uniword/builder/document_builder.rb', line 183

def numbered_list(&)
  list(type: :decimal, &)
end

#page_breakself

Insert a page break

Returns:

  • (self)


101
102
103
104
105
106
# File 'lib/uniword/builder/document_builder.rb', line 101

def page_break
  @model.body.paragraphs << Wordprocessingml::Paragraph.new(
    runs: [Builder.page_break]
  )
  self
end

#page_numberself

Insert a page number paragraph

Returns:

  • (self)


468
469
470
471
# File 'lib/uniword/builder/document_builder.rb', line 468

def page_number
  @model.body.paragraphs << Builder.page_number_field
  self
end

#paragraph(text = nil) {|ParagraphBuilder| ... } ⇒ ParagraphBuilder

Create and add a paragraph to the document

Parameters:

  • text (String, nil) (defaults to: nil)

    Optional text content

Yields:

Returns:



76
77
78
79
80
81
82
# File 'lib/uniword/builder/document_builder.rb', line 76

def paragraph(text = nil, &block)
  para = ParagraphBuilder.new
  para << text if text
  block.call(para) if block_given?
  @model.body.paragraphs << para.build
  para
end

#save(path) ⇒ Object

Save document to file

Parameters:

  • path (String)

    Output file path



502
503
504
# File 'lib/uniword/builder/document_builder.rb', line 502

def save(path)
  @model.to_file(path)
end

#section(type: "nextPage") {|SectionBuilder| ... } ⇒ SectionBuilder

Configure section properties

Parameters:

  • type (String) (defaults to: "nextPage")

    Section break type (‘nextPage’, ‘continuous’, ‘evenPage’, ‘oddPage’)

Yields:

Returns:



124
125
126
127
128
129
130
# File 'lib/uniword/builder/document_builder.rb', line 124

def section(type: "nextPage", &block)
  sec = SectionBuilder.new
  sec.type = type
  block.call(sec) if block_given?
  @model.body.section_properties ||= sec.build
  sec
end

#subject(value) ⇒ Object



272
273
274
275
# File 'lib/uniword/builder/document_builder.rb', line 272

def subject(value)
  @model.core_properties.subject = value
  self
end

#table {|TableBuilder| ... } ⇒ TableBuilder

Create and add a table to the document

Yields:

Returns:



112
113
114
115
116
117
# File 'lib/uniword/builder/document_builder.rb', line 112

def table(&block)
  tbl = TableBuilder.new
  block.call(tbl) if block_given?
  @model.body.tables << tbl.build
  tbl
end

#theme(name = nil) {|ThemeBuilder| ... } ⇒ ThemeBuilder

Apply or configure a document theme

Parameters:

  • name (String, nil) (defaults to: nil)

    Theme name to apply

Yields:

Returns:



237
238
239
240
241
242
# File 'lib/uniword/builder/document_builder.rb', line 237

def theme(name = nil, &block)
  tb = ThemeBuilder.new(self)
  tb.apply(name) if name
  block.call(tb) if block_given?
  tb
end

#time_field(format: "h:mm:ss am/pm") ⇒ self

Insert a time paragraph

Parameters:

  • format (String) (defaults to: "h:mm:ss am/pm")

    Time format (default ‘h:mm:ss am/pm’)

Returns:

  • (self)


494
495
496
497
# File 'lib/uniword/builder/document_builder.rb', line 494

def time_field(format: "h:mm:ss am/pm")
  @model.body.paragraphs << Builder.time_field(format: format)
  self
end

#title(value) ⇒ Object



257
258
259
260
# File 'lib/uniword/builder/document_builder.rb', line 257

def title(value)
  @model.core_properties.title = value
  self
end

#toc(title: "Table of Contents", styles: nil) ⇒ self

Insert a Table of Contents

Parameters:

  • title (String) (defaults to: "Table of Contents")

    TOC title (default ‘Table of Contents’)

  • styles (Array<String>, nil) (defaults to: nil)

    Heading styles to include

Returns:

  • (self)


161
162
163
164
165
166
# File 'lib/uniword/builder/document_builder.rb', line 161

def toc(title: "Table of Contents", styles: nil)
  TocBuilder.build(title: title, styles: styles).each do |para|
    @model.body.paragraphs << para
  end
  self
end

#total_pagesself

Insert a total pages paragraph

Returns:

  • (self)


476
477
478
479
# File 'lib/uniword/builder/document_builder.rb', line 476

def total_pages
  @model.body.paragraphs << Builder.total_pages_field
  self
end

#watermark(text, font: "Calibri", size: 60, color: nil, opacity: "0.3", angle: -45)) ⇒ self

Add a watermark to the document header

Parameters:

  • text (String, nil)

    Watermark text (nil to clear)

  • font (String) (defaults to: "Calibri")

    Font name (default ‘Calibri’)

  • size (Integer) (defaults to: 60)

    Font size in points (default 60)

  • color (String) (defaults to: nil)

    Fill color hex (default ‘D0D0D0’)

  • opacity (String) (defaults to: "0.3")

    Opacity ‘0.0’ to ‘1.0’ (default ‘0.3’)

  • angle (Integer) (defaults to: -45))

    Rotation angle in degrees (default -45)

Returns:

  • (self)


366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/uniword/builder/document_builder.rb', line 366

def watermark(text, font: "Calibri", size: 60, color: nil,
              opacity: "0.3", angle: -45)
  if text.nil?
    (@model.headers ||= {}).delete("default")
    return self
  end

  para = WatermarkBuilder.build_paragraph(
    text, font: font, size: size, color: color,
          opacity: opacity, angle: angle
  )

  header = Wordprocessingml::Header.new
  header.paragraphs << para
  (@model.headers ||= {})["default"] = header
  self
end