Class: Docx::Elements::Containers::Paragraph

Inherits:
Object
  • Object
show all
Includes:
Container, Element
Defined in:
lib/docx/containers/paragraph.rb

Constant Summary

Constants included from Element

Element::DEFAULT_TAG

Instance Attribute Summary

Attributes included from Element

#node

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Element

#append_to, #at_xpath, #copy, #html_tag, included, #insert_after, #insert_before, #parent, #parent_paragraph, #prepend_to, #xpath

Methods included from Container

#blank!, #properties, #remove!

Constructor Details

#initialize(node, document_properties = {}, doc = nil) ⇒ Paragraph

Child elements: pPr, r, fldSimple, hlink, subDoc msdn.microsoft.com/en-us/library/office/ee364458(v=office.11).aspx



18
19
20
21
22
23
24
# File 'lib/docx/containers/paragraph.rb', line 18

def initialize(node, document_properties = {}, doc = nil)
  @node = node
  @properties_tag = 'pPr'
  @document_properties = document_properties
  @font_size = @document_properties[:font_size]
  @document = doc
end

Class Method Details

.tagObject



11
12
13
# File 'lib/docx/containers/paragraph.rb', line 11

def self.tag
  'p'
end

Instance Method Details

#aligned_center?Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/docx/containers/paragraph.rb', line 129

def aligned_center?
  alignment == 'center'
end

#aligned_left?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/docx/containers/paragraph.rb', line 121

def aligned_left?
  ['left', nil].include?(alignment)
end

#aligned_right?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/docx/containers/paragraph.rb', line 125

def aligned_right?
  alignment == 'right'
end

#each_text_runObject

Iterate over each text run within a paragraph



64
65
66
# File 'lib/docx/containers/paragraph.rb', line 64

def each_text_run
  text_runs.each { |tr| yield(tr) }
end

#font_colorObject



141
142
143
144
# File 'lib/docx/containers/paragraph.rb', line 141

def font_color
  color_tag = @node.xpath('w:r//w:rPr//w:color').first
  color_tag ? color_tag.attributes['val']&.value : nil
end

#font_sizeObject



133
134
135
136
137
138
139
# File 'lib/docx/containers/paragraph.rb', line 133

def font_size
  size_attribute = @node.at_xpath('w:pPr//w:sz//@w:val')

  return @font_size unless size_attribute

  size_attribute.value.to_i / 2
end

#styleObject



146
147
148
149
150
151
# File 'lib/docx/containers/paragraph.rb', line 146

def style
  return nil unless @document

  @document.style_name_of(style_id) ||
    @document.default_paragraph_style
end

#style=(identifier) ⇒ Object Also known as: style_id=



157
158
159
160
161
# File 'lib/docx/containers/paragraph.rb', line 157

def style=(identifier)
  id = @document.styles_configuration.style_of(identifier).id

  style_property.set_attribute('w:val', id)
end

#style_idObject



153
154
155
# File 'lib/docx/containers/paragraph.rb', line 153

def style_id
  style_property.get_attribute('w:val')
end

#substitute(pattern, replacement) ⇒ Object

Substitute text within the paragraph, even when a match spans multiple text runs (e.g. a “{placeholder}” that Word split across several runs, such as ““rst_na”, “me}”). The per-run TextRun#substitute cannot match those, but this can, because it joins the runs first.

The matched region is collapsed into the first run it touches, so that run’s formatting is kept while the other spanned runs are emptied; runs outside the match are left untouched.

pattern may be a String or a Regexp; replacement follows String#sub semantics, so capture-group backreferences (e.g. ‘1’) work with a Regexp.

# given a paragraph reading "Hello {{first_name}}!"
paragraph.substitute('{{first_name}}', 'Jane')   # => "Hello Jane!"
paragraph.substitute(/\{\{(\w+)\}\}/, 'value of \1')

See github.com/ruby-docx/docx/issues/147



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/docx/containers/paragraph.rb', line 85

def substitute(pattern, replacement)
  search_from = 0
  loop do
    runs = text_runs
    break if runs.empty?

    offsets = []
    cursor = 0
    runs.each do |run|
      offsets << cursor
      cursor += run.text.length
    end
    full_text = runs.map(&:text).join

    match = full_text.match(pattern, search_from)
    break unless match
    break if match.end(0) == match.begin(0) # ignore empty matches

    match_start = match.begin(0)
    match_end   = match.end(0) # exclusive
    first = offsets.rindex { |offset| offset <= match_start }
    last  = offsets.rindex { |offset| offset < match_end }

    combined = runs[first..last].map(&:text).join
    local_start = match_start - offsets[first]
    local_end   = match_end - offsets[first]
    replaced = combined[local_start...local_end].sub(pattern, replacement)
    runs[first].text = combined[0...local_start] + replaced + combined[local_end..-1]
    ((first + 1)..last).each { |index| runs[index].text = '' }

    # advance past the inserted replacement so it is not re-matched
    search_from = match_start + replaced.length
  end
  self
end

#text=(content) ⇒ Object

Set text of paragraph



27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/docx/containers/paragraph.rb', line 27

def text=(content)
  if text_runs.size == 1
    text_runs.first.text = content
  elsif text_runs.size == 0
    new_r = TextRun.create_within(self)
    new_r.text = content
  else
    text_runs.each {|r| r.node.remove }
    new_r = TextRun.create_within(self)
    new_r.text = content
  end
end

#text_runsObject

Array of text runs contained within paragraph



59
60
61
# File 'lib/docx/containers/paragraph.rb', line 59

def text_runs
  @node.xpath('w:r|w:hyperlink').map { |r_node| Containers::TextRun.new(r_node, @document_properties) }
end

#to_htmlObject

Return paragraph as a <p></p> HTML fragment with formatting based on properties.



46
47
48
49
50
51
52
53
54
55
# File 'lib/docx/containers/paragraph.rb', line 46

def to_html
  html = +''
  text_runs.each do |text_run|
    html << text_run.to_html
  end
  styles = { 'font-size' => "#{font_size}pt" }
  styles['color'] = "##{font_color}" if font_color
  styles['text-align'] = alignment if alignment
  html_tag(:p, content: html, styles: styles)
end

#to_sObject Also known as: text

Return text of paragraph



41
42
43
# File 'lib/docx/containers/paragraph.rb', line 41

def to_s
  text_runs.map(&:text).join('')
end