Skip to content

Commit 06e5ad8

Browse files
satoryuclaude
andcommitted
Decouple load_rels from load_styles (#158)
Previously load_rels was called from inside load_styles, so when a document had no word/styles.xml, load_styles raised Errno::ENOENT, was rescued, and load_rels never ran -- leaving @RELS nil. Any later call to #hyperlinks then crashed with "undefined method 'xpath' for nil". load_rels is now called independently from initialize and handles a missing rels file gracefully, so relationships load regardless of whether styles.xml is present. Adds a regression fixture (no_styles_with_hyperlink.docx: a document with a hyperlink relationship but no styles.xml) and a spec asserting #hyperlinks works in that case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 7297e19 commit 06e5ad8

3 files changed

Lines changed: 20 additions & 1 deletion

File tree

lib/docx/document.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def initialize(path_or_io, options = {})
4040
@document_xml = document.get_input_stream.read
4141
@doc = Nokogiri::XML(@document_xml)
4242
load_styles
43+
load_rels
4344
load_headers
4445
load_footers
4546
yield(self) if block_given?
@@ -226,18 +227,22 @@ def load_footers
226227
def load_styles
227228
@styles_xml = @zip.read('word/styles.xml')
228229
@styles = Nokogiri::XML(@styles_xml)
229-
load_rels
230230
rescue Errno::ENOENT => e
231231
warn e.message
232232
nil
233233
end
234234

235+
# Loaded independently of styles so that a document without word/styles.xml
236+
# still initializes @rels (see #158).
235237
def load_rels
236238
rels_entry = @zip.glob('word/_rels/document*.xml.rels').first
237239
raise Errno::ENOENT unless rels_entry
238240

239241
@rels_xml = rels_entry.get_input_stream.read
240242
@rels = Nokogiri::XML(@rels_xml)
243+
rescue Errno::ENOENT => e
244+
warn e.message
245+
nil
241246
end
242247

243248
#--

spec/docx/document_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,20 @@
612612
end
613613
end
614614

615+
# Regression test for #158: relationships (and therefore hyperlinks) must be
616+
# loaded independently of styles, so a document without word/styles.xml does
617+
# not leave @rels uninitialized.
618+
describe 'reading relationships when styles.xml is missing' do
619+
before do
620+
@doc = Docx::Document.open(@fixtures_path + '/no_styles_with_hyperlink.docx')
621+
end
622+
623+
it 'still loads hyperlink relationships' do
624+
expect { @doc.hyperlinks }.to_not raise_error
625+
expect(@doc.hyperlinks).to eq('rId4' => 'http://www.google.com/')
626+
end
627+
end
628+
615629
describe 'replacing contents' do
616630
let(:replacement_file_path) { @fixtures_path + '/replacement.png' }
617631
let(:temp_file_path) { Tempfile.new(['docx_gem', '.docx']).path }
8.88 KB
Binary file not shown.

0 commit comments

Comments
 (0)