From dd286425f5715b3c343f0e4df51508063bb56f64 Mon Sep 17 00:00:00 2001 From: Tatsuya Sato Date: Sun, 18 Oct 2026 01:03:56 +0900 Subject: [PATCH] Fix Element#prepend_to calling a missing Nokogiri method (#189) prepend_to called element.node.properties, which does not exist on a Nokogiri node, so it always raised NoMethodError. Use the container's properties (w:pPr etc.) when present and insert after them; otherwise insert the node as the first child. Co-Authored-By: Claude Opus 5.5 --- lib/docx/elements/element.rb | 3 ++- spec/docx/elements/element_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/docx/elements/element.rb b/lib/docx/elements/element.rb index fbe786c..039dda6 100755 --- a/lib/docx/elements/element.rb +++ b/lib/docx/elements/element.rb @@ -42,7 +42,8 @@ def append_to(element) # Insert node as first child (after properties) def prepend_to(element) - @node = element.node.properties.add_next_sibling(@node) + properties = element.properties if element.respond_to?(:properties) + @node = properties ? properties.add_next_sibling(@node) : element.node.prepend_child(@node) self end diff --git a/spec/docx/elements/element_spec.rb b/spec/docx/elements/element_spec.rb index a255415..ab852ef 100644 --- a/spec/docx/elements/element_spec.rb +++ b/spec/docx/elements/element_spec.rb @@ -98,6 +98,36 @@ def texts end end + # Regression tests for #189 + describe '#prepend_to' do + let(:run) { element_class.new(w_node('new ')) } + + it 'inserts the node right after the properties of a container' do + paragraph = Docx::Elements::Containers::Paragraph.new( + w_node('text') + ) + + expect(run.prepend_to(paragraph)).to equal(run) + expect(paragraph.node.element_children.map(&:name)).to eq(%w[pPr r r]) + expect(paragraph.text).to eq('new text') + expect(run.node.parent).to equal(paragraph.node) + end + + it 'inserts the node as the first child of a container without properties' do + paragraph = Docx::Elements::Containers::Paragraph.new(w_node('text')) + + run.prepend_to(paragraph) + + expect(paragraph.text).to eq('new text') + end + + it 'inserts the node as the first child of a non-container element' do + run.prepend_to(first) + + expect(texts).to eq(%w[new\ first second]) + end + end + describe '.create_with' do it 'builds a detached element from the class tag in the same XML document' do created = element_class.create_with(first)