Module: Uniword::Wordprocessingml::DocumentStyling

Included in:
DocumentRoot
Defined in:
lib/uniword/wordprocessingml/document_styling.rb

Overview

Theme and style application for DocumentRoot — Word's Design/Layout/Styles surfaces as document-level API.

Extracted from DocumentRoot to keep the document model focused: bundled and file-based theme application, stylesets, font and color schemes, font replacement, page setup, and style management (rename/remove).

Instance Method Summary collapse

Instance Method Details

#apply_color_scheme(name) ⇒ self

Apply a bundled color scheme to the document's theme

Mirrors Word's Design → Colors gallery: replaces only the theme's clrScheme — fonts and formats are untouched. Creates the theme part from the bundled Office theme when the document has none.

Parameters:

  • name (String, Symbol)

    Color scheme slug (data/color_schemes/)

Returns:

  • (self)

    For method chaining

Raises:

  • (ArgumentError)

    if the scheme is unknown



97
98
99
100
101
102
103
104
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 97

def apply_color_scheme(name)
  colors = Resource::ColorSchemeLoader.load(name.to_s)
  transformation = Themes::ThemeTransformation.new
  ensure_theme!(transformation)
  theme.theme_elements.clr_scheme =
    transformation.build_color_scheme(colors)
  self
end

#apply_font_scheme(name) ⇒ self

Apply a bundled font scheme to the document's theme

Mirrors Word's Design → Fonts gallery: replaces only the theme's fontScheme — colors and formats are untouched. Creates the theme part from the bundled Office theme when the document has none.

Parameters:

  • name (String, Symbol)

    Font scheme slug (data/font_schemes/)

Returns:

  • (self)

    For method chaining

Raises:

  • (ArgumentError)

    if the scheme is unknown



79
80
81
82
83
84
85
86
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 79

def apply_font_scheme(name)
  fonts = Resource::FontSchemeLoader.load(name.to_s)
  transformation = Themes::ThemeTransformation.new
  ensure_theme!(transformation)
  theme.theme_elements.font_scheme =
    transformation.build_font_scheme(fonts)
  self
end

#apply_page_setup(size: nil, orientation: nil, margins: nil, top: nil, right: nil, bottom: nil, left: nil) ⇒ Integer

Apply uniform page setup to every section of the document

Mirrors Word's Layout dialog: named paper sizes, orientation (with Word-style dimension swap), and margins.

Parameters:

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

    Paper size: letter, legal, a4, a5, executive

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

    "portrait" or "landscape"

  • margins (Integer, String, nil) (defaults to: nil)

    Uniform margin for all sides (twips, or "1in" / "2.5cm" / "25mm")

  • top,

    right, bottom, left [Integer, String, nil] Per-side margin overrides

Returns:

  • (Integer)

    Number of sections updated



135
136
137
138
139
140
141
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 135

def apply_page_setup(size: nil, orientation: nil, margins: nil,
                     top: nil, right: nil, bottom: nil, left: nil)
  setup = PageSetup.new(size: size, orientation: orientation,
                        margins: margins, top: top, right: right,
                        bottom: bottom, left: left)
  setup.apply(self)
end

#apply_styles_from(source_path, strategy: :keep_existing) ⇒ self

Apply styles from another document

Parameters:

  • source_path (String)

    Path to source .docx file

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

    Conflict resolution strategy

Returns:

  • (self)

    For method chaining



211
212
213
214
215
216
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 211

def apply_styles_from(source_path, strategy: :keep_existing)
  source_doc = Uniword.load(source_path)
  styles_configuration.merge(source_doc.styles_configuration,
                             conflict_resolution: strategy)
  self
end

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

Apply StyleSet to document

Parameters:

  • name (String, Symbol)

    StyleSet slug (e.g., 'signature', 'heritage')

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

    Application strategy (:keep_existing, :replace, :rename)

Returns:

  • (self)

    For method chaining



63
64
65
66
67
68
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 63

def apply_styleset(name, strategy: :keep_existing)
  styleset = Uniword::Stylesets::YamlStyleSetLoader
    .load_bundled(name.to_s)
  styleset.apply_to(self, strategy: strategy)
  self
end

#apply_template(template_path, strategy: :keep_existing) ⇒ self

Apply both theme and styles from a template document

Parameters:

  • template_path (String)

    Path to template .docx file

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

    Conflict resolution strategy for styles

Returns:

  • (self)

    For method chaining



223
224
225
226
227
228
229
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 223

def apply_template(template_path, strategy: :keep_existing)
  template_doc = Uniword.load(template_path)
  self.theme = template_doc.theme.dup if template_doc.theme
  styles_configuration.merge(template_doc.styles_configuration,
                             conflict_resolution: strategy)
  self
end

#apply_theme(name, **options) ⇒ self

Applies a Uniword theme by name, updating doc defaults and built-in heading/hyperlink styles to reference the theme.

Parameters:

  • name (String, Symbol)

    Theme slug (e.g., 'meridian', 'corporate')

  • options (Hash)

    optional overrides

Options Hash (**options):

  • :colors (Hash)

    override specific color keys

  • :major_font (String)

    override major font

  • :minor_font (String)

    override minor font

Returns:

  • (self)

    For method chaining



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 23

def apply_theme(name, **options)
  friendly = Themes::Theme.load(name.to_s)

  options[:colors]&.each do |key, value|
    friendly.color_scheme[key.to_s] = value
  end
  if options[:major_font]
    friendly.font_scheme.major_font = options[:major_font]
  end
  if options[:minor_font]
    friendly.font_scheme.minor_font = options[:minor_font]
  end

  word_theme = Themes::ThemeTransformation.new.to_word(friendly)
  Themes::ThemeApplicator.new.apply(word_theme, self)
  self
end

#apply_theme_file(path, variant: nil) ⇒ self

Apply theme from .thmx file

Parameters:

  • path (String)

    Path to .thmx file

  • variant (String, Integer, nil) (defaults to: nil)

    Optional variant

Returns:

  • (self)

    For method chaining



46
47
48
49
50
51
52
53
54
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 46

def apply_theme_file(path, variant: nil)
  loader = Themes::ThemeLoader.new
  self.theme = if variant
                 loader.load_with_variant(path, variant)
               else
                 loader.load(path)
               end
  self
end

#apply_theme_from(source_path) ⇒ self

Apply theme from another document

Parameters:

  • source_path (String)

    Path to source .docx file

Returns:

  • (self)

    For method chaining



200
201
202
203
204
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 200

def apply_theme_from(source_path)
  source_doc = Uniword.load(source_path)
  self.theme = source_doc.theme.dup if source_doc.theme
  self
end

#auto_transition_themeHash?

Auto-transition from MS theme to Uniword equivalent

Detects the MS theme in the document's embedded theme and replaces it with the corresponding Uniword theme (font-substituted, renamed).

Examples:

result = doc.auto_transition_theme
puts "Transitioned from " \
     "#{result[:ms_name]} to #{result[:uniword_slug]}"

Returns:

  • (Hash, nil)

    { uniword_slug:, ms_name: } or nil if no match



192
193
194
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 192

def auto_transition_theme
  Resource::ThemeTransition.auto_transition!(self)
end

#remove_style(style_id) ⇒ Style?

Remove one style from the document's style definitions

Default styles (w:default="1") are never removed.

Parameters:

  • style_id (String)

    Style id (w:styleId)

Returns:

  • (Style, nil)

    The removed style, or nil when not removed (absent or protected)



150
151
152
153
154
155
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 150

def remove_style(style_id)
  style = styles_configuration.style(style_id)
  return unless StyleCleanup.new(self).remove?(style_id)

  style
end

#remove_unused_stylesArray<String>

Remove every style that no content references — Word's Styles-pane decluttering as one call. Default styles are kept.

Returns:

  • (Array<String>)

    Ids of removed styles



177
178
179
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 177

def remove_unused_styles
  StyleCleanup.new(self).remove_unused
end

#rename_style(identifier, new_name) ⇒ Style?

Rename a style's display name (w:name) — Word's style rename. References (pStyle/rStyle/tblStyle) target the styleId, so they keep working unchanged.

Parameters:

  • identifier (String)

    Style id (w:styleId) or current display name (w:name)

  • new_name (String)

    New display name

Returns:

  • (Style, nil)

    The renamed style, or nil when not found



165
166
167
168
169
170
171
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 165

def rename_style(identifier, new_name)
  style = styles_configuration.style(identifier)
  return unless style

  style.name = StyleName.new(val: new_name)
  style
end

#replace_font(from:, to:) ⇒ Integer

Replace one font family with another across the document

Mirrors Word's Home → Replace → Replace Fonts: rewrites rFonts references in styles and defaults, body content, headers, footers, notes, comments, and numbering. Theme font references (asciiTheme etc.) are untouched — use #apply_font_scheme for those.

Parameters:

  • from (String)

    Font family to replace (exact match)

  • to (String)

    Replacement font family

Returns:

  • (Integer)

    Number of rFonts attribute values rewritten



117
118
119
120
# File 'lib/uniword/wordprocessingml/document_styling.rb', line 117

def replace_font(from:, to:)
  replacer = FontReplacer.new(from: from, to: to)
  replacer.replace(self)
end