coradoc 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +48 -5
  3. data/coradoc-docx/lib/coradoc/docx/transform/context.rb +1 -1
  4. data/coradoc-docx/lib/coradoc/docx/transform/from_core_model.rb +13 -6
  5. data/coradoc-docx/lib/coradoc/docx/transform/numbering_resolver.rb +9 -7
  6. data/coradoc-docx/lib/coradoc/docx/transform/ordered_content.rb +2 -2
  7. data/coradoc-docx/lib/coradoc/docx/transform/rules/image_rule.rb +4 -1
  8. data/coradoc-docx/lib/coradoc/docx/transform/rules/math_rule.rb +2 -1
  9. data/coradoc-docx/lib/coradoc/docx/transform/rules/run_rule.rb +17 -30
  10. data/coradoc-docx/lib/coradoc/docx/transform/rules/simple_field_rule.rb +3 -5
  11. data/coradoc-docx/lib/coradoc/docx/transform/rules/table_rule.rb +3 -4
  12. data/coradoc-docx/lib/coradoc/docx/transform/style_resolver.rb +19 -24
  13. data/coradoc-docx/lib/coradoc/docx/transform/to_core_model.rb +18 -11
  14. data/coradoc-html/lib/coradoc/html/base.rb +3 -7
  15. data/coradoc-html/lib/coradoc/html/converter_base.rb +5 -15
  16. data/coradoc-html/lib/coradoc/html/converters/base.rb +18 -27
  17. data/coradoc-html/lib/coradoc/html/converters/comment_line.rb +2 -2
  18. data/coradoc-html/lib/coradoc/html/converters/link.rb +1 -1
  19. data/coradoc-html/lib/coradoc/html/converters/list_item.rb +3 -3
  20. data/coradoc-html/lib/coradoc/html/converters/ordered.rb +1 -1
  21. data/coradoc-html/lib/coradoc/html/converters/span.rb +2 -2
  22. data/coradoc-html/lib/coradoc/html/converters/table.rb +3 -3
  23. data/coradoc-html/lib/coradoc/html/converters/table_cell.rb +14 -28
  24. data/coradoc-html/lib/coradoc/html/converters/table_row.rb +2 -2
  25. data/coradoc-html/lib/coradoc/html/converters/text_element.rb +1 -5
  26. data/coradoc-html/lib/coradoc/html/input/converters/a.rb +2 -2
  27. data/coradoc-html/lib/coradoc/html/input/converters/dl.rb +1 -1
  28. data/coradoc-html/lib/coradoc/html/input/converters/figure.rb +2 -2
  29. data/coradoc-html/lib/coradoc/html/input/converters/markup.rb +3 -3
  30. data/coradoc-html/lib/coradoc/html/input/converters/p.rb +1 -1
  31. data/coradoc-html/lib/coradoc/html/input/converters/td.rb +1 -1
  32. data/coradoc-html/lib/coradoc/html/input/converters.rb +1 -2
  33. data/coradoc-html/lib/coradoc/html/input/html_converter.rb +3 -3
  34. data/coradoc-html/lib/coradoc/html/input/plugin.rb +2 -2
  35. data/coradoc-html/lib/coradoc/html/renderer.rb +4 -6
  36. data/coradoc-html/lib/coradoc/html/theme/base.rb +2 -3
  37. data/coradoc-html/lib/coradoc/html/theme/classic_renderer.rb +9 -12
  38. data/coradoc-html/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +3 -3
  39. data/coradoc-markdown/lib/coradoc/markdown/model/base.rb +6 -5
  40. data/coradoc-markdown/lib/coradoc/markdown/serializer.rb +2 -2
  41. data/coradoc-markdown/lib/coradoc/markdown/toc_generator.rb +4 -5
  42. data/coradoc-markdown/lib/coradoc/markdown/transformer.rb +5 -3
  43. data/lib/coradoc/version.rb +1 -1
  44. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2a167bf671c487f25b37d0df4019bee6bd324636fdf9a681b799764f4a14b2d
4
- data.tar.gz: 89345da1186b5ad1fc3ed0315b536a09e445015b1744094fd3ff187382023818
3
+ metadata.gz: 7f2699bddcd303d5c58e2f3e6a7d4c4341a8f06dc06df44785a97aa48ad7e055
4
+ data.tar.gz: 8e696cec10f047229d67806d5d93d21bcd02465ef57da243295f13906ccfc91d
5
5
  SHA512:
6
- metadata.gz: 5a7ead748469ceecbe303de9fd0e65b0081c4765cb8cda371f11cdd76173dcb60372f89ff2c5fc1d30b74fab0bff349fd0149b62ddd65df5b944a350dea14cc9
7
- data.tar.gz: 41c5de35c416b7bfcc74ba8043bc26771e4bc8a332f59211de6f0c7f6bae7019fa096458ab705bd7e54b0c248c352df70c04467679f156c315e02c00ef4fdf5d
6
+ metadata.gz: 8b313846dc7365da7c399117c33119c28009df2009d478345157839c29e9bf30a152fb0000ab56c7202ea7cb784e661ba2a3b61bfa7a40f7616440182994f718
7
+ data.tar.gz: 42118e1947a3c609110786b7f906412080a79e518b02e101a4cc19d696e790849d93cdc049334829837a44a18308a34a03e3d6caf8fac83628a8119c1d35cfcc
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-06 19:17:34 UTC using RuboCop version 1.75.8.
3
+ # on 2026-05-07 12:19:03 UTC using RuboCop version 1.75.8.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -15,6 +15,28 @@ Gemspec/RequiredRubyVersion:
15
15
  - 'coradoc-html/coradoc-html.gemspec'
16
16
  - 'coradoc.gemspec'
17
17
 
18
+ # Offense count: 1
19
+ # This cop supports safe autocorrection (--autocorrect).
20
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
21
+ # SupportedStyles: with_first_argument, with_fixed_indentation
22
+ Layout/ArgumentAlignment:
23
+ Exclude:
24
+ - 'coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/document.rb'
25
+
26
+ # Offense count: 1
27
+ # This cop supports safe autocorrection (--autocorrect).
28
+ Layout/ClosingParenthesisIndentation:
29
+ Exclude:
30
+ - 'lib/coradoc/document_manipulator.rb'
31
+
32
+ # Offense count: 1
33
+ # This cop supports safe autocorrection (--autocorrect).
34
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
35
+ # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
36
+ Layout/FirstArgumentIndentation:
37
+ Exclude:
38
+ - 'lib/coradoc/document_manipulator.rb'
39
+
18
40
  # Offense count: 6
19
41
  # This cop supports safe autocorrection (--autocorrect).
20
42
  # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
@@ -22,6 +44,21 @@ Gemspec/RequiredRubyVersion:
22
44
  Layout/LineLength:
23
45
  Max: 235
24
46
 
47
+ # Offense count: 1
48
+ # This cop supports safe autocorrection (--autocorrect).
49
+ # Configuration parameters: EnforcedStyle.
50
+ # SupportedStyles: symmetrical, new_line, same_line
51
+ Layout/MultilineMethodCallBraceLayout:
52
+ Exclude:
53
+ - 'lib/coradoc/document_manipulator.rb'
54
+
55
+ # Offense count: 1
56
+ # This cop supports safe autocorrection (--autocorrect).
57
+ # Configuration parameters: AllowInHeredoc.
58
+ Layout/TrailingWhitespace:
59
+ Exclude:
60
+ - 'coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/document.rb'
61
+
25
62
  # Offense count: 1
26
63
  Lint/BinaryOperatorWithIdenticalOperands:
27
64
  Exclude:
@@ -96,7 +133,7 @@ Lint/Void:
96
133
  Exclude:
97
134
  - 'coradoc-html/lib/coradoc/html.rb'
98
135
 
99
- # Offense count: 237
136
+ # Offense count: 236
100
137
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
101
138
  Metrics/AbcSize:
102
139
  Max: 178
@@ -117,12 +154,12 @@ Metrics/BlockNesting:
117
154
  Metrics/ClassLength:
118
155
  Max: 556
119
156
 
120
- # Offense count: 186
157
+ # Offense count: 181
121
158
  # Configuration parameters: AllowedMethods, AllowedPatterns.
122
159
  Metrics/CyclomaticComplexity:
123
160
  Max: 32
124
161
 
125
- # Offense count: 383
162
+ # Offense count: 384
126
163
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
127
164
  Metrics/MethodLength:
128
165
  Max: 246
@@ -138,7 +175,7 @@ Metrics/ParameterLists:
138
175
  Max: 7
139
176
  MaxOptionalParameters: 4
140
177
 
141
- # Offense count: 125
178
+ # Offense count: 123
142
179
  # Configuration parameters: AllowedMethods, AllowedPatterns.
143
180
  Metrics/PerceivedComplexity:
144
181
  Max: 27
@@ -380,6 +417,12 @@ Style/HashLikeCase:
380
417
  - 'coradoc-html/lib/coradoc/html/input/converters/table.rb'
381
418
  - 'coradoc-html/lib/coradoc/html/input/converters/td.rb'
382
419
 
420
+ # Offense count: 1
421
+ # This cop supports safe autocorrection (--autocorrect).
422
+ Style/MultilineIfModifier:
423
+ Exclude:
424
+ - 'coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/document.rb'
425
+
383
426
  # Offense count: 1
384
427
  # This cop supports unsafe autocorrection (--autocorrect-all).
385
428
  # Configuration parameters: EnforcedStyle.
@@ -62,7 +62,7 @@ module Coradoc
62
62
  private
63
63
 
64
64
  def extract_paragraph_text(paragraph)
65
- return '' unless paragraph.respond_to?(:text)
65
+ return '' unless paragraph.is_a?(Uniword::Wordprocessingml::Paragraph) || paragraph.is_a?(Uniword::Wordprocessingml::Run)
66
66
 
67
67
  paragraph.text.to_s
68
68
  end
@@ -242,11 +242,19 @@ module Coradoc
242
242
  end
243
243
 
244
244
  def add_list_to_builder(list_block, builder)
245
- method = list_block.marker_type == 'numbered' ? :numbered_list : :bullet_list
245
+ list_method = list_block.marker_type == 'numbered' ? :numbered_list : :bullet_list
246
246
 
247
- builder.send(method) do |list|
248
- list_block.items.each do |item|
249
- list.item(item.flat_text)
247
+ if list_method == :numbered_list
248
+ builder.numbered_list do |list|
249
+ list_block.items.each do |item|
250
+ list.item(item.flat_text)
251
+ end
252
+ end
253
+ else
254
+ builder.bullet_list do |list|
255
+ list_block.items.each do |item|
256
+ list.item(item.flat_text)
257
+ end
250
258
  end
251
259
  end
252
260
  end
@@ -334,8 +342,7 @@ module Coradoc
334
342
  va.value = 'superscript'
335
343
  props.vertical_align = va
336
344
  when 'monospace'
337
- # Monospace via font
338
- props.font = 'Courier New' if props.respond_to?(:font=)
345
+ props.fonts = Uniword::Wordprocessingml::RFonts.new(ascii: 'Courier New')
339
346
  when 'link'
340
347
  # Links need to be at the paragraph level (w:hyperlink)
341
348
  # Return the run; caller should wrap in Hyperlink
@@ -61,8 +61,8 @@ module Coradoc
61
61
  def build_num_map(config)
62
62
  return {} unless config
63
63
 
64
- instances = config.respond_to?(:instances) ? config.instances : []
65
- return {} if instances.empty?
64
+ instances = config.instances
65
+ return {} if instances.nil? || instances.empty?
66
66
 
67
67
  map = {}
68
68
  instances.each do |inst|
@@ -73,8 +73,8 @@ module Coradoc
73
73
  definition = find_definition(config, abstract_num_id)
74
74
  next unless definition
75
75
 
76
- levels = definition.respond_to?(:levels) ? definition.levels : []
77
- level = levels.first
76
+ levels = definition.levels
77
+ level = levels&.first
78
78
  next unless level
79
79
 
80
80
  fmt = extract_num_fmt(level)
@@ -93,11 +93,13 @@ module Coradoc
93
93
  aid = instance.abstract_num_id
94
94
  return nil unless aid
95
95
 
96
- aid.respond_to?(:value) ? aid.value : aid
96
+ aid.is_a?(Uniword::Wordprocessingml::AbstractNumId) ? aid.val : aid
97
97
  end
98
98
 
99
99
  def find_definition(config, abstract_num_id)
100
- defs = config.respond_to?(:definitions) ? config.definitions : []
100
+ defs = config.definitions
101
+ return [] unless defs
102
+
101
103
  defs.find { |d| d.abstract_num_id == abstract_num_id }
102
104
  end
103
105
 
@@ -105,7 +107,7 @@ module Coradoc
105
107
  nf = level.numFmt
106
108
  return 'bullet' unless nf
107
109
 
108
- nf.respond_to?(:val) ? nf.val.to_s : nf.to_s
110
+ nf.is_a?(Uniword::Wordprocessingml::NumFmt) ? nf.val.to_s : nf.to_s
109
111
  end
110
112
 
111
113
  def marker_type_for(fmt)
@@ -18,7 +18,7 @@ module Coradoc
18
18
  # @param context [Context] transform context with registry
19
19
  # @return [Array] transformed content (Strings, InlineElements, etc.)
20
20
  def transform_paragraph_content(paragraph, context)
21
- order = paragraph.respond_to?(:element_order) ? paragraph.element_order : nil
21
+ order = paragraph.is_a?(Uniword::Wordprocessingml::Paragraph) ? paragraph.element_order : nil
22
22
 
23
23
  if order && !order.empty?
24
24
  transform_ordered(paragraph, order, context)
@@ -49,7 +49,7 @@ module Coradoc
49
49
 
50
50
  result = []
51
51
  order.each do |entry|
52
- name = entry.respond_to?(:name) ? entry.name : entry.to_s
52
+ name = entry.is_a?(String) ? entry : entry.name
53
53
  idx = counters[name]
54
54
  counters[name] = idx + 1
55
55
 
@@ -109,7 +109,10 @@ module Coradoc
109
109
  def extent_to_px(extent, dimension)
110
110
  return nil unless extent
111
111
 
112
- value = extent.respond_to?(dimension) ? extent.send(dimension) : nil
112
+ value = case dimension
113
+ when :cx then extent.cx
114
+ when :cy then extent.cy
115
+ end
113
116
  return nil unless value
114
117
 
115
118
  px = value.to_i / EMU_PER_PX
@@ -66,7 +66,8 @@ module Coradoc
66
66
  end
67
67
 
68
68
  def element_to_xml(element)
69
- return '' unless element.respond_to?(:to_xml)
69
+ return '' unless element.is_a?(Uniword::Wordprocessingml::AlternateContent) ||
70
+ element.is_a?(Uniword::Wordprocessingml::OMath)
70
71
 
71
72
  element.to_xml
72
73
  end
@@ -45,10 +45,8 @@ module Coradoc
45
45
  private
46
46
 
47
47
  def effective_props(run)
48
- if run.respond_to?(:effective_run_properties)
49
- ep = run.effective_run_properties
50
- return ep if ep
51
- end
48
+ ep = run.effective_run_properties
49
+ return ep if ep
52
50
 
53
51
  run.properties
54
52
  end
@@ -66,15 +64,12 @@ module Coradoc
66
64
  result << context.transform(drawing)
67
65
  end
68
66
 
69
- # Tab character
70
- result << "\t" if run.respond_to?(:tab) && run.tab
67
+ result << "\t" if run.tab
71
68
 
72
- # Inline math (m:oMath within a run)
73
- result << context.transform(run.o_math) if run.respond_to?(:o_math) && run.o_math
69
+ result << context.transform(run.o_math) if run.class.attributes.key?(:o_math) && run.o_math
74
70
 
75
- # Deleted text (tracked changes)
76
- if run.respond_to?(:del_text) && run.del_text
77
- text = run.del_text.respond_to?(:content) ? run.del_text.content.to_s : run.del_text.to_s
71
+ if run.del_text
72
+ text = run.del_text.is_a?(Uniword::Wordprocessingml::DeletedText) ? run.del_text.content.to_s : run.del_text.to_s
78
73
  unless text.empty?
79
74
  result << CoreModel::InlineElement.new(
80
75
  format_type: 'strikethrough',
@@ -83,24 +78,18 @@ module Coradoc
83
78
  end
84
79
  end
85
80
 
86
- # Symbol (w:sym)
87
- if run.respond_to?(:sym) && run.sym
88
- sym = run.sym
89
- char = sym.respond_to?(:char) ? sym.char : nil
81
+ if run.sym
82
+ char = run.sym.char
90
83
  result << char.to_s if char && !char.empty?
91
84
  end
92
85
 
93
- # No-break hyphen (U+2011)
94
- result << "\u2011" if run.respond_to?(:no_break_hyphen) && run.no_break_hyphen
86
+ result << "\u2011" if run.no_break_hyphen
95
87
 
96
- # Soft hyphen (U+00AD)
97
- result << "\u00AD" if run.respond_to?(:soft_hyphen) && run.soft_hyphen
88
+ result << "\u00AD" if run.class.attributes.key?(:soft_hyphen) && run.soft_hyphen
98
89
 
99
- # Carriage return (w:cr) treat as line break
100
- result << CoreModel::InlineElement.new(format_type: 'hard_line_break') if run.respond_to?(:carriage_return) && run.carriage_return
90
+ result << CoreModel::InlineElement.new(format_type: 'hard_line_break') if run.class.attributes.key?(:carriage_return) && run.carriage_return
101
91
 
102
- # Alternate content — extract preferred/fallback content
103
- if run.respond_to?(:alternate_content) && run.alternate_content
92
+ if run.alternate_content
104
93
  result << extract_alternate_content(run.alternate_content,
105
94
  context)
106
95
  end
@@ -109,19 +98,17 @@ module Coradoc
109
98
  end
110
99
 
111
100
  def extract_alternate_content(ac, context)
112
- # Prefer the fallback content (wc:w:bdoContent or mc:Fallback)
113
- content = if ac.respond_to?(:fallback) && ac.fallback
101
+ content = if ac.fallback
114
102
  ac.fallback
115
- elsif ac.respond_to?(:choice) && ac.choice
103
+ elsif ac.choice
116
104
  ac.choice
117
105
  end
118
106
 
119
107
  return nil unless content
120
108
 
121
- # If the fallback/choice has paragraphs or runs, transform them
122
- if content.respond_to?(:runs)
109
+ if content.is_a?(Uniword::Wordprocessingml::Run)
123
110
  content.runs&.each { |r| context.transform(r) }
124
- elsif content.respond_to?(:paragraphs)
111
+ elsif content.is_a?(Uniword::Wordprocessingml::Paragraph)
125
112
  content.paragraphs&.flat_map { |p| context.transform(p) }
126
113
  end
127
114
  end
@@ -147,7 +134,7 @@ module Coradoc
147
134
  return nil unless props
148
135
 
149
136
  # Check rStyle for semantic role
150
- if context.style_resolver.respond_to?(:run_semantic_role)
137
+ if context.style_resolver.is_a?(Coradoc::Docx::Transform::StyleResolver)
151
138
  role = context.style_resolver.run_semantic_role(run)
152
139
  case role
153
140
  when :monospace then return 'monospace'
@@ -62,19 +62,17 @@ module Coradoc
62
62
  private
63
63
 
64
64
  def field_text(field)
65
- # SimpleField may have runs with resolved text
66
- if field.respond_to?(:runs) && field.runs && !field.runs.empty?
65
+ if field.runs && !field.runs.empty?
67
66
  return field.runs.map do |r|
68
67
  r.text&.content.to_s
69
68
  end.join
70
69
  end
71
70
 
72
- # Fall back to text attribute
73
- field.respond_to?(:text) ? field.text.to_s : nil
71
+ nil
74
72
  end
75
73
 
76
74
  def field_instruction(field)
77
- instr = field.respond_to?(:instr) ? field.instr : nil
75
+ instr = field.instr
78
76
  instr.to_s
79
77
  end
80
78
 
@@ -32,7 +32,7 @@ module Coradoc
32
32
  def transform_row(row, context)
33
33
  CoreModel::TableRow.new(
34
34
  cells: row.cells.map { |c| transform_cell(c, context) },
35
- header: row.respond_to?(:header?) ? row.header? : false
35
+ header: row.header?
36
36
  )
37
37
  end
38
38
 
@@ -69,15 +69,14 @@ module Coradoc
69
69
  end
70
70
 
71
71
  def cell_paragraphs(cell)
72
- cell.respond_to?(:paragraphs) ? (cell.paragraphs || []) : []
72
+ cell.paragraphs || []
73
73
  end
74
74
 
75
75
  def header_cell?(cell)
76
76
  return false unless cell.properties
77
- return false unless cell.properties.respond_to?(:v_merge)
78
77
 
79
78
  vm = cell.properties.v_merge
80
- vm.respond_to?(:value) ? vm.value.to_s == 'restart' : false
79
+ vm&.value.to_s == 'restart'
81
80
  end
82
81
  end
83
82
  end
@@ -51,18 +51,16 @@ module Coradoc
51
51
  style_name = resolve_style_name(paragraph)
52
52
  return true if style_name && HEADING_PATTERN.match?(style_name)
53
53
 
54
- # Check outline_level on paragraph properties
55
54
  ol = paragraph.properties.outline_level
56
55
  if ol
57
- ol_level = ol.respond_to?(:value) ? ol.value.to_i : ol.to_i
56
+ ol_level = ol.is_a?(Uniword::Wordprocessingml::OutlineLevel) ? ol.value.to_i : ol.to_i
58
57
  return true if ol_level.positive?
59
58
  end
60
59
 
61
- # Check outline_level from style definition
62
60
  style = find_style_for_paragraph(paragraph)
63
- if style.respond_to?(:outline_level) && style.outline_level
61
+ if style&.outline_level
64
62
  ol_val = style.outline_level
65
- ol_val = ol_val.respond_to?(:value) ? ol_val.value.to_i : ol_val.to_i
63
+ ol_val = ol_val.is_a?(Uniword::Wordprocessingml::OutlineLevel) ? ol_val.value.to_i : ol_val.to_i
66
64
  return true if ol_val.positive?
67
65
  end
68
66
 
@@ -82,7 +80,7 @@ module Coradoc
82
80
  # Check outline_level on paragraph properties
83
81
  ol = paragraph.properties&.outline_level
84
82
  if ol
85
- level = ol.respond_to?(:value) ? ol.value.to_i : ol.to_i
83
+ level = ol.is_a?(Uniword::Wordprocessingml::OutlineLevel) ? ol.value.to_i : ol.to_i
86
84
  return level if level.positive?
87
85
  end
88
86
 
@@ -138,10 +136,9 @@ module Coradoc
138
136
  style_ref = paragraph.properties&.style
139
137
  return nil unless style_ref
140
138
 
141
- value = style_ref.respond_to?(:value) ? style_ref.value : style_ref.to_s
139
+ value = style_ref.is_a?(Uniword::Wordprocessingml::PStyle) ? style_ref.val : style_ref.to_s
142
140
  return nil unless value
143
141
 
144
- # Check local style map first (for custom style aliases)
145
142
  mapped = @style_map[value]
146
143
  return mapped if mapped
147
144
 
@@ -152,7 +149,7 @@ module Coradoc
152
149
  style_ref = run.properties.style
153
150
  return nil unless style_ref
154
151
 
155
- value = style_ref.respond_to?(:value) ? style_ref.value : style_ref.to_s
152
+ value = style_ref.is_a?(Uniword::Wordprocessingml::PStyle) ? style_ref.val : style_ref.to_s
156
153
  return nil unless value
157
154
 
158
155
  mapped = @style_map[value]
@@ -165,23 +162,21 @@ module Coradoc
165
162
  style_id = style_id_from_paragraph(paragraph)
166
163
  return nil unless style_id
167
164
 
168
- if @config.respond_to?(:style_by_id)
169
- @config.style_by_id(style_id)
170
- elsif @config.respond_to?(:styles)
171
- @config.styles.find { |s| s.styleId == style_id }
172
- end
165
+ return unless @config.is_a?(Uniword::Wordprocessingml::StylesConfiguration)
166
+
167
+ @config.style_by_id(style_id)
173
168
  end
174
169
 
175
170
  def style_id_from_paragraph(paragraph)
176
171
  style_ref = paragraph.properties&.style
177
172
  return nil unless style_ref
178
173
 
179
- style_ref.respond_to?(:value) ? style_ref.value : style_ref.to_s
174
+ style_ref.is_a?(Uniword::Wordprocessingml::PStyle) ? style_ref.val : style_ref.to_s
180
175
  end
181
176
 
182
177
  def build_style_map(config)
183
178
  return {} unless config
184
- return {} unless config.respond_to?(:styles)
179
+ return {} unless config.is_a?(Uniword::Wordprocessingml::StylesConfiguration)
185
180
 
186
181
  map = {}
187
182
  config.styles.each do |style|
@@ -191,7 +186,6 @@ module Coradoc
191
186
 
192
187
  map[id] = name
193
188
 
194
- # Detect custom heading styles by basedOn chain
195
189
  if heading_by_based_on?(config, style)
196
190
  level = heading_level_from_chain(config, style)
197
191
  map[id] = "Heading#{level}"
@@ -202,26 +196,27 @@ module Coradoc
202
196
  end
203
197
 
204
198
  def extract_style_name(style)
205
- return style.style_name if style.respond_to?(:style_name)
199
+ sn = style.style_name
200
+ return sn if sn
206
201
 
207
202
  name = style.name
208
203
  return nil unless name
209
204
 
210
- name.respond_to?(:val) ? name.val.to_s : name.to_s
205
+ name.is_a?(Uniword::Wordprocessingml::StyleName) ? name.val.to_s : name.to_s
211
206
  end
212
207
 
213
208
  def heading_by_based_on?(config, style)
214
- based_on = style.respond_to?(:based_on) ? style.based_on : nil
209
+ based_on = style.based_on
215
210
  return false unless based_on
216
211
 
217
212
  visited = Set.new
218
213
  current = style
219
214
  while current && !visited.include?(current.styleId)
220
215
  visited << current.styleId
221
- parent_id = current.respond_to?(:based_on) ? current.based_on : nil
216
+ parent_id = current.based_on
222
217
  return true if parent_id && HEADING_PATTERN.match?(parent_id)
223
218
 
224
- break unless parent_id && config.respond_to?(:styles)
219
+ break unless parent_id
225
220
 
226
221
  current = config.styles.find { |s| s.styleId == parent_id }
227
222
  end
@@ -240,8 +235,8 @@ module Coradoc
240
235
  return match[2].to_i if match
241
236
  end
242
237
 
243
- parent_id = current.respond_to?(:based_on) ? current.based_on : nil
244
- break unless parent_id && config.respond_to?(:styles)
238
+ parent_id = current.based_on
239
+ break unless parent_id
245
240
 
246
241
  current = config.styles.find { |s| s.styleId == parent_id }
247
242
  end
@@ -129,14 +129,13 @@ module Coradoc
129
129
  end
130
130
 
131
131
  def section_break?(paragraph)
132
- return false unless paragraph.respond_to?(:properties)
132
+ return false unless paragraph.is_a?(Uniword::Wordprocessingml::Paragraph)
133
133
  return false unless paragraph.properties
134
134
 
135
135
  sect_pr = paragraph.properties.section_properties
136
136
  return false unless sect_pr
137
137
 
138
- # A section break exists if sectPr has a type (nextPage, continuous, etc.)
139
- sect_pr.respond_to?(:type) && sect_pr.type
138
+ sect_pr.type ? true : false
140
139
  end
141
140
 
142
141
  def section_break_element(paragraph, context)
@@ -182,12 +181,12 @@ module Coradoc
182
181
  end
183
182
 
184
183
  def body_ordered_elements(body)
185
- order = body.respond_to?(:element_order) ? body.element_order : nil
184
+ order = body.is_a?(Uniword::Wordprocessingml::Body) ? body.element_order : nil
186
185
  return body.elements if order.nil? || order.empty?
187
186
 
188
187
  p_idx = tbl_idx = sdt_idx = 0
189
188
  order.filter_map do |entry|
190
- name = entry.respond_to?(:name) ? entry.name : entry.to_s
189
+ name = entry.is_a?(String) ? entry : entry.name
191
190
  case name
192
191
  when 'p'
193
192
  para = body.paragraphs[p_idx]
@@ -216,7 +215,7 @@ module Coradoc
216
215
  doc_footnotes = document.footnotes
217
216
  if doc_footnotes.is_a?(Hash)
218
217
  doc_footnotes.each do |id, fn|
219
- paragraphs = fn.respond_to?(:content) ? fn.content : []
218
+ paragraphs = fn.is_a?(Uniword::Wordprocessingml::Footnote) ? fn.paragraphs : fn[:content]
220
219
  footnotes[id.to_s] = Array(paragraphs)
221
220
  end
222
221
  end
@@ -280,7 +279,10 @@ module Coradoc
280
279
  end
281
280
 
282
281
  def extract_from_parts(document, method, prefix, core_doc)
283
- parts = document.respond_to?(method) ? document.send(method) : nil
282
+ parts = case method
283
+ when :headers then document.headers
284
+ when :footers then document.footers
285
+ end
284
286
  return unless parts
285
287
 
286
288
  Array(parts).each_with_index do |part, idx|
@@ -288,13 +290,18 @@ module Coradoc
288
290
  next if text.nil? || text.strip.empty?
289
291
  next if layout_only_text?(text)
290
292
 
291
- core_doc.set_metadata("docx.#{prefix}.#{part.respond_to?(:type) ? part.type : idx}",
292
- text.strip)
293
+ part_type = if part.is_a?(Uniword::Wordprocessingml::Header) ||
294
+ part.is_a?(Uniword::Wordprocessingml::Footer)
295
+ part.type
296
+ else
297
+ idx
298
+ end
299
+ core_doc.set_metadata("docx.#{prefix}.#{part_type}", text.strip)
293
300
  end
294
301
  end
295
302
 
296
303
  def extract_part_text(part)
297
- paragraphs = part.respond_to?(:paragraphs) ? part.paragraphs : []
304
+ paragraphs = part.paragraphs || []
298
305
  return nil unless paragraphs
299
306
 
300
307
  paragraphs.map do |para|
@@ -303,7 +310,7 @@ module Coradoc
303
310
  end
304
311
 
305
312
  def extract_paragraph_text_content(para)
306
- runs = para.respond_to?(:runs) ? para.runs : []
313
+ runs = para.runs || []
307
314
  return nil unless runs
308
315
 
309
316
  runs.map { |r| r.text&.content.to_s }.join
@@ -125,14 +125,10 @@ module Coradoc
125
125
  def extract_attributes(model)
126
126
  attrs = {}
127
127
 
128
- # Extract ID if available
129
- attrs[:id] = model.id if model.respond_to?(:id) && model.id
128
+ attrs[:id] = model.id if model.id
129
+ attrs[:title] = model.title if model.title
130
130
 
131
- # Extract title if available
132
- attrs[:title] = model.title if model.respond_to?(:title) && model.title
133
-
134
- # Extract class/role if available
135
- if model.respond_to?(:metadata) && model.metadata
131
+ if model.is_a?(Coradoc::CoreModel::StructuralElement) && model.metadata
136
132
  attrs[:class] = model.metadata[:class] || model.metadata[:role]
137
133
  attrs.merge!(model.metadata.except(:class, :role))
138
134
  end