Class: Rbpptx::Shape
- Inherits:
-
Object
- Object
- Rbpptx::Shape
- Defined in:
- lib/rbpptx/shape.rb
Overview
A single shape (+<p:sp>+) on a slide.
Two layers of text access are exposed:
-
#text / #text= — bulldozer-level: read the entire concatenated text body, or replace it wholesale. The setter cleans the text body’s <a:p> children and rebuilds them, cloning the first existing <a:rPr> onto each new run so template formatting carries through.
-
#paragraphs / #runs — surgical: walk into individual Paragraph and Run wrappers and mutate run text via Run#text=, which only rewrites <a:t> content. Run properties, hyperlinks, soft line breaks, paragraph properties, and any unknown OOXML extensions on the shape are preserved.
In addition, #placeholder_type reads the shape’s placeholder role from <p:nvSpPr>/<p:nvPr>/<p:ph type=“…”> so callers can target shapes by semantic role (e.g. :ctrTitle, :subTitle, :body) instead of by index.
Constant Summary collapse
- P_NS =
"http://schemas.openxmlformats.org/presentationml/2006/main".freeze
- A_NS =
"http://schemas.openxmlformats.org/drawingml/2006/main".freeze
Instance Method Summary collapse
-
#initialize(node:, slide: nil) ⇒ Shape
constructor
A new instance of Shape.
-
#name ⇒ String?
Value of <p:cNvPr name=“…”>, the human-readable shape name set by the authoring tool.
-
#paragraphs ⇒ Array<Paragraph>
Paragraphs in the shape’s text body, in document order.
-
#placeholder_type ⇒ Symbol?
The placeholder type as a Symbol (e.g.
:ctrTitle,:subTitle,:title,:body,:obj,:ftr,:dt,:sldNum,:pic), ornilif the shape is not a placeholder. -
#runs ⇒ Array<Run>
All runs in the shape’s text body, flattened across paragraphs in document order.
-
#text ⇒ String
Concatenated text of the shape’s text body.
-
#text=(new_text) ⇒ String
Replaces the shape’s text body.
Constructor Details
#initialize(node:, slide: nil) ⇒ Shape
Returns a new instance of Shape.
29 30 31 32 |
# File 'lib/rbpptx/shape.rb', line 29 def initialize(node:, slide: nil) @node = node @slide = end |
Instance Method Details
#name ⇒ String?
Returns value of <p:cNvPr name=“…”>, the human-readable shape name set by the authoring tool.
36 37 38 |
# File 'lib/rbpptx/shape.rb', line 36 def name @node.at_xpath("./p:nvSpPr/p:cNvPr/@name", "p" => P_NS)&.value end |
#paragraphs ⇒ Array<Paragraph>
Returns paragraphs in the shape’s text body, in document order. Returns [] if the shape has no <p:txBody> (e.g. picture or group shapes).
56 57 58 59 60 61 |
# File 'lib/rbpptx/shape.rb', line 56 def paragraphs txbody = @node.at_xpath("./p:txBody", "p" => P_NS) return [] unless txbody txbody.xpath("./a:p", "a" => A_NS).map { |p| Paragraph.new(node: p, slide: @slide) } end |
#placeholder_type ⇒ Symbol?
Returns the placeholder type as a Symbol (e.g. :ctrTitle, :subTitle, :title, :body, :obj, :ftr, :dt, :sldNum, :pic), or nil if the shape is not a placeholder. Returns :body when the shape has a <p:ph> element with no type attribute, matching the OOXML default.
45 46 47 48 49 50 51 |
# File 'lib/rbpptx/shape.rb', line 45 def placeholder_type ph = @node.at_xpath("./p:nvSpPr/p:nvPr/p:ph", "p" => P_NS) return nil unless ph type = ph["type"] type ? type.to_sym : :body end |
#runs ⇒ Array<Run>
Returns all runs in the shape’s text body, flattened across paragraphs in document order.
65 66 67 |
# File 'lib/rbpptx/shape.rb', line 65 def runs paragraphs.flat_map(&:runs) end |
#text ⇒ String
Concatenated text of the shape’s text body. Paragraphs are joined with “n”; soft line breaks (+<a:br>+) inside a paragraph are also rendered as “n”.
74 75 76 |
# File 'lib/rbpptx/shape.rb', line 74 def text paragraphs.map(&:text).join("\n") end |
#text=(new_text) ⇒ String
Replaces the shape’s text body. Lines (separated by “n”) become individual <a:p> paragraphs. Run properties from the first existing <a:rPr> (font, size, color, language) are cloned onto each new run so template formatting carries through.
This is the bulldozer-level setter; for edits that need to preserve individual run formatting (e.g. replacing a placeholder inside a multi-run paragraph), use #runs or #paragraphs and Run#text= instead.
Shapes without a <p:txBody> (e.g. picture or group shapes) cannot accept text and will raise.
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/rbpptx/shape.rb', line 94 def text=(new_text) txbody = @node.at_xpath("./p:txBody", "p" => P_NS) raise Error, "shape has no <p:txBody>; cannot set text" unless txbody template_rpr = txbody.at_xpath(".//a:r/a:rPr", "a" => A_NS) txbody.xpath("./a:p", "a" => A_NS).each(&:remove) lines = new_text.to_s.empty? ? [""] : new_text.to_s.split("\n", -1) txbody.add_child(build_paragraphs_xml(lines)) if template_rpr txbody.xpath("./a:p/a:r", "a" => A_NS).each do |run| first_child = run.children.first first_child ? first_child.add_previous_sibling(template_rpr.dup) : run.add_child(template_rpr.dup) end end @slide&.mark_dirty! new_text end |