coradoc 2.0.1 → 2.0.2

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +55 -167
  3. data/coradoc-adoc/lib/coradoc/asciidoc/model/base.rb +4 -3
  4. data/coradoc-adoc/lib/coradoc/asciidoc/model/document.rb +1 -1
  5. data/coradoc-adoc/lib/coradoc/asciidoc/model/include.rb +1 -1
  6. data/coradoc-adoc/lib/coradoc/asciidoc/model/resolver.rb +2 -2
  7. data/coradoc-adoc/lib/coradoc/asciidoc/model/serialization/asciidoc_transform.rb +3 -3
  8. data/coradoc-adoc/lib/coradoc/asciidoc/model/table_row.rb +1 -1
  9. data/coradoc-adoc/lib/coradoc/asciidoc/model/text_element.rb +4 -8
  10. data/coradoc-adoc/lib/coradoc/asciidoc/parse_error.rb +6 -6
  11. data/coradoc-adoc/lib/coradoc/asciidoc/serializer/adoc_serializer.rb +5 -10
  12. data/coradoc-adoc/lib/coradoc/asciidoc/serializer/formatter.rb +4 -3
  13. data/coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/base.rb +8 -20
  14. data/coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/block/core.rb +1 -1
  15. data/coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/document.rb +3 -6
  16. data/coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/inline/strikethrough.rb +1 -1
  17. data/coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/list/item.rb +5 -9
  18. data/coradoc-adoc/lib/coradoc/asciidoc/transform/from_core_model.rb +26 -34
  19. data/coradoc-adoc/lib/coradoc/asciidoc/transform/from_core_model_registrations.rb +18 -18
  20. data/coradoc-adoc/lib/coradoc/asciidoc/transform/to_core_model.rb +96 -123
  21. data/coradoc-adoc/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +10 -6
  22. data/coradoc-adoc/lib/coradoc/asciidoc/transformer/header_rules.rb +5 -5
  23. data/coradoc-adoc/lib/coradoc/asciidoc/transformer/list_rules.rb +2 -2
  24. data/coradoc-adoc/lib/coradoc/asciidoc/transformer/structural_rules.rb +1 -1
  25. data/coradoc-adoc/lib/coradoc/asciidoc/transformer.rb +5 -5
  26. data/coradoc-adoc/lib/coradoc/asciidoc.rb +1 -1
  27. data/coradoc-adoc/lib/coradoc/util/asciidoc.rb +4 -3
  28. data/coradoc-adoc/spec/coradoc/asciidoc/transform/from_core_model_spec.rb +4 -2
  29. data/coradoc-docx/lib/coradoc/docx/transform/rules/run_rule.rb +4 -1
  30. data/coradoc-docx/lib/coradoc/docx/transform/rules/simple_field_rule.rb +5 -1
  31. data/coradoc-docx/lib/coradoc/docx/transform/rules/table_rule.rb +0 -1
  32. data/coradoc-docx/lib/coradoc/docx.rb +6 -4
  33. data/coradoc-docx/spec/coradoc/docx/transform/from_core_model_spec.rb +5 -2
  34. data/coradoc-docx/spec/coradoc/docx/transform/rules/rule_unit_spec.rb +27 -7
  35. data/coradoc-docx/spec/coradoc/docx/transform/to_core_model_spec.rb +6 -2
  36. data/coradoc-html/lib/coradoc/html/converters/base.rb +4 -1
  37. data/coradoc-html/lib/coradoc/html.rb +1 -1
  38. data/coradoc-markdown/lib/coradoc/markdown/transform/from_core_model.rb +2 -2
  39. data/coradoc-markdown/lib/coradoc/markdown.rb +1 -1
  40. data/lib/coradoc/configurable.rb +6 -2
  41. data/lib/coradoc/coradoc.rb +18 -16
  42. data/lib/coradoc/core_model/base.rb +3 -3
  43. data/lib/coradoc/core_model/list_item.rb +3 -3
  44. data/lib/coradoc/core_model/toc_generator.rb +1 -1
  45. data/lib/coradoc/document_manipulator.rb +9 -13
  46. data/lib/coradoc/format_module.rb +16 -4
  47. data/lib/coradoc/input.rb +1 -1
  48. data/lib/coradoc/output.rb +1 -1
  49. data/lib/coradoc/query.rb +38 -186
  50. data/lib/coradoc/registry.rb +5 -7
  51. data/lib/coradoc/serializer/registry.rb +3 -5
  52. data/lib/coradoc/validation.rb +40 -21
  53. data/lib/coradoc/version.rb +1 -1
  54. metadata +1 -1
@@ -148,7 +148,10 @@ RSpec.describe Coradoc::Docx::Transform::Rules::ParagraphRule do
148
148
  end
149
149
 
150
150
  describe '#apply' do
151
- let(:context) { build_context(registry: build_registry_with(described_class.new, Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new)) }
151
+ let(:context) do
152
+ build_context(registry: build_registry_with(described_class.new, Coradoc::Docx::Transform::Rules::RunRule.new,
153
+ Coradoc::Docx::Transform::Rules::TextRule.new))
154
+ end
152
155
 
153
156
  it 'produces a Block paragraph with text content' do
154
157
  para = build_paragraph('Hello')
@@ -188,7 +191,10 @@ RSpec.describe Coradoc::Docx::Transform::Rules::TableRule do
188
191
  end
189
192
 
190
193
  describe '#apply' do
191
- let(:context) { build_context(registry: build_registry_with(described_class.new, Coradoc::Docx::Transform::Rules::ParagraphRule.new, Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new)) }
194
+ let(:context) do
195
+ build_context(registry: build_registry_with(described_class.new, Coradoc::Docx::Transform::Rules::ParagraphRule.new,
196
+ Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new))
197
+ end
192
198
 
193
199
  it 'produces a CoreModel::Table with rows and cells' do
194
200
  table = build_table([%w[A B], %w[C D]])
@@ -213,7 +219,10 @@ RSpec.describe Coradoc::Docx::Transform::Rules::ListItemRule do
213
219
  end
214
220
 
215
221
  describe '#apply' do
216
- let(:context) { build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new)) }
222
+ let(:context) do
223
+ build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::RunRule.new,
224
+ Coradoc::Docx::Transform::Rules::TextRule.new))
225
+ end
217
226
 
218
227
  it 'produces a ListItem with content' do
219
228
  para = build_list_paragraph('Item 1', num_id: 1)
@@ -242,7 +251,10 @@ RSpec.describe Coradoc::Docx::Transform::Rules::HeadingRule do
242
251
  end
243
252
 
244
253
  describe '#apply' do
245
- let(:context) { build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new)) }
254
+ let(:context) do
255
+ build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::RunRule.new,
256
+ Coradoc::Docx::Transform::Rules::TextRule.new))
257
+ end
246
258
 
247
259
  it 'produces a StructuralElement section with title and level' do
248
260
  para = build_heading('My Title', level: 2)
@@ -363,7 +375,9 @@ RSpec.describe Coradoc::Docx::Transform::Rules::HyperlinkRule do
363
375
 
364
376
  describe '#apply' do
365
377
  let(:run_rule) { Coradoc::Docx::Transform::Rules::RunRule.new }
366
- let(:context) { build_context(registry: build_registry_with(run_rule, Coradoc::Docx::Transform::Rules::TextRule.new)) }
378
+ let(:context) do
379
+ build_context(registry: build_registry_with(run_rule, Coradoc::Docx::Transform::Rules::TextRule.new))
380
+ end
367
381
 
368
382
  it 'produces InlineElement link with external URL' do
369
383
  hl = build_hyperlink(
@@ -419,7 +433,10 @@ RSpec.describe Coradoc::Docx::Transform::Rules::SimpleFieldRule do
419
433
  end
420
434
 
421
435
  describe '#apply' do
422
- let(:context) { build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new)) }
436
+ let(:context) do
437
+ build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::RunRule.new,
438
+ Coradoc::Docx::Transform::Rules::TextRule.new))
439
+ end
423
440
 
424
441
  it 'returns nil for PAGE field (print layout)' do
425
442
  field = Uniword::Wordprocessingml::SimpleField.new
@@ -449,7 +466,10 @@ RSpec.describe Coradoc::Docx::Transform::Rules::StructuredDocumentTagRule do
449
466
  end
450
467
 
451
468
  describe '#apply' do
452
- let(:context) { build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::ParagraphRule.new, Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new)) }
469
+ let(:context) do
470
+ build_context(registry: build_registry_with(Coradoc::Docx::Transform::Rules::ParagraphRule.new,
471
+ Coradoc::Docx::Transform::Rules::RunRule.new, Coradoc::Docx::Transform::Rules::TextRule.new))
472
+ end
453
473
 
454
474
  it 'unwraps SDT content and delegates to paragraph rules' do
455
475
  sdt = Uniword::Wordprocessingml::StructuredDocumentTag.new
@@ -221,7 +221,9 @@ RSpec.describe Coradoc::Docx::Transform::ToCoreModel do
221
221
  core = transform_to_core(doc)
222
222
 
223
223
  blocks = core.children.select { |c| c.is_a?(Coradoc::CoreModel::Block) }
224
- inline = blocks.first.children.find { |c| c.is_a?(Coradoc::CoreModel::InlineElement) && c.format_type == 'subscript' }
224
+ inline = blocks.first.children.find do |c|
225
+ c.is_a?(Coradoc::CoreModel::InlineElement) && c.format_type == 'subscript'
226
+ end
225
227
  expect(inline).not_to be_nil
226
228
  expect(inline.content).to eq('2')
227
229
  end
@@ -241,7 +243,9 @@ RSpec.describe Coradoc::Docx::Transform::ToCoreModel do
241
243
  core = transform_to_core(doc)
242
244
 
243
245
  blocks = core.children.select { |c| c.is_a?(Coradoc::CoreModel::Block) }
244
- inline = blocks.first.children.find { |c| c.is_a?(Coradoc::CoreModel::InlineElement) && c.format_type == 'superscript' }
246
+ inline = blocks.first.children.find do |c|
247
+ c.is_a?(Coradoc::CoreModel::InlineElement) && c.format_type == 'superscript'
248
+ end
245
249
  expect(inline).not_to be_nil
246
250
  expect(inline.content).to eq('2')
247
251
  end
@@ -96,7 +96,10 @@ module Coradoc
96
96
 
97
97
  return render_core_bibliography(content, state) if content.is_a?(Coradoc::CoreModel::Bibliography)
98
98
 
99
- return render_core_bibliography_entry(content, state) if content.is_a?(Coradoc::CoreModel::BibliographyEntry)
99
+ if content.is_a?(Coradoc::CoreModel::BibliographyEntry)
100
+ return render_core_bibliography_entry(content,
101
+ state)
102
+ end
100
103
 
101
104
  # Handle unknown types gracefully
102
105
  handle_unknown_content(content, state)
@@ -14,7 +14,7 @@ module Coradoc
14
14
  # Register with the main coradoc registry
15
15
  Coradoc.register_format(:html, self,
16
16
  aliases: %w[html htm],
17
- extensions: %w[.html .htm]) if Coradoc.respond_to?(:register_format)
17
+ extensions: %w[.html .htm])
18
18
 
19
19
  @registered = true
20
20
  end
@@ -189,13 +189,13 @@ module Coradoc
189
189
 
190
190
  # Check if first row has header cells
191
191
  if first_row_cells.any?(&:header)
192
- headers = first_row_cells.map { |c| c.flat_text }
192
+ headers = first_row_cells.map(&:flat_text)
193
193
  table_rows = table_rows[1..] || []
194
194
  end
195
195
 
196
196
  # Convert remaining rows to pipe-separated strings
197
197
  rows = table_rows.map do |row|
198
- Array(row.cells).map { |c| c.flat_text }.join(' | ')
198
+ Array(row.cells).map(&:flat_text).join(' | ')
199
199
  end
200
200
  end
201
201
 
@@ -186,5 +186,5 @@ module Coradoc
186
186
  # Register the Markdown format with Coradoc
187
187
  register_format(:markdown, Markdown,
188
188
  aliases: %w[md markdown mdown mkd],
189
- extensions: %w[.md .markdown .mdown .mkd]) if respond_to?(:register_format)
189
+ extensions: %w[.md .markdown .mdown .mkd])
190
190
  end
@@ -45,9 +45,12 @@ module Coradoc
45
45
  # @param options [Hash] Configuration options
46
46
  def initialize(options = {})
47
47
  @options = symbolize_keys(options)
48
- after_initialize if respond_to?(:after_initialize)
48
+ after_initialize
49
49
  end
50
50
 
51
+ # Hook for subclass initialization
52
+ def after_initialize; end
53
+
51
54
  # Get a configuration value
52
55
  #
53
56
  # @param key [Symbol] Configuration key
@@ -95,7 +98,8 @@ module Coradoc
95
98
  # Override in subclasses for custom handling
96
99
  def apply_options(options)
97
100
  options.each do |key, value|
98
- instance_variable_set("@#{key}", value) if respond_to?("#{key}=")
101
+ setter = "#{key}="
102
+ instance_variable_set("@#{key}", value) if public_methods.include?(setter.to_sym)
99
103
  end
100
104
  end
101
105
  end
@@ -67,6 +67,7 @@ module Coradoc
67
67
  # @param options [Hash] optional configuration (e.g., extensions: [])
68
68
  # @return [void]
69
69
  def register_format(format_name, format_module, **options)
70
+ format_module.extend(FormatModule::Interface) unless format_module.is_a?(FormatModule::Interface)
70
71
  registry.register(format_name, format_module, options)
71
72
  FormatModule.validate!(format_module, format_name)
72
73
  end
@@ -148,7 +149,7 @@ module Coradoc
148
149
  return model if model.is_a?(CoreModel::Base)
149
150
 
150
151
  registry.each_value do |format_module|
151
- next unless format_module.respond_to?(:handles_model?) && format_module.handles_model?(model)
152
+ next unless format_module.handles_model?(model)
152
153
 
153
154
  return format_module.to_core(model)
154
155
  end
@@ -195,7 +196,7 @@ module Coradoc
195
196
  # Coradoc.detect_format("file.md") # => :markdown
196
197
  def detect_format(filename)
197
198
  ext = File.extname(filename).downcase
198
- registry.each do |name, _mod|
199
+ registry.each_key do |name|
199
200
  opts = registry.options_for(name)
200
201
  return name if opts[:extensions]&.include?(ext)
201
202
  end
@@ -243,7 +244,7 @@ module Coradoc
243
244
  # @example
244
245
  # html = Coradoc.convert_file("document.adoc", to: :html)
245
246
  # adoc = Coradoc.convert_file("report.docx", to: :asciidoc)
246
- def convert_file(path, from: nil, to:, **options)
247
+ def convert_file(path, to:, from: nil, **options)
247
248
  source_format = from || detect_format(path)
248
249
  raise UnsupportedFormatError, "Could not detect format for: #{path}" unless source_format
249
250
 
@@ -270,7 +271,7 @@ module Coradoc
270
271
  return nil unless name
271
272
 
272
273
  key = name.to_s.downcase
273
- registry.each do |fmt_name, _mod|
274
+ registry.each_key do |fmt_name|
274
275
  opts = registry.options_for(fmt_name)
275
276
  return fmt_name if opts[:aliases]&.include?(key)
276
277
  end
@@ -285,9 +286,7 @@ module Coradoc
285
286
  mod = get_format(format)
286
287
  return false unless mod
287
288
 
288
- return mod.serialize? if mod.respond_to?(:serialize?)
289
-
290
- true
289
+ mod.serialize?
291
290
  end
292
291
 
293
292
  # Check if a format supports parsing (reading input)
@@ -296,7 +295,9 @@ module Coradoc
296
295
  # @return [Boolean] true if the format can parse
297
296
  def parse_format?(format)
298
297
  mod = get_format(format)
299
- mod&.respond_to?(:parse_to_core) || mod&.respond_to?(:parse) || false
298
+ return false unless mod
299
+
300
+ mod.public_methods.include?(:parse_to_core) || mod.public_methods.include?(:parse)
300
301
  end
301
302
 
302
303
  # Get capability summary for all registered formats
@@ -361,9 +362,9 @@ module Coradoc
361
362
  def document_stats(doc)
362
363
  stats = {}
363
364
 
364
- stats[:title] = doc.title if doc.respond_to?(:title) && doc.title
365
+ stats[:title] = doc.title if doc.title
365
366
 
366
- if doc.respond_to?(:children)
367
+ if doc.is_a?(CoreModel::StructuralElement)
367
368
  stats[:child_count] = count_elements(doc)
368
369
  stats[:element_counts] = count_element_types(doc)
369
370
  end
@@ -379,9 +380,9 @@ module Coradoc
379
380
  return elem.to_s unless elem.is_a?(CoreModel::Base)
380
381
 
381
382
  type = elem.class.name.split('::').last
382
- if elem.respond_to?(:title) && elem.title
383
+ if elem.title
383
384
  "#{type}: #{elem.title}"
384
- elsif elem.respond_to?(:content) && elem.content
385
+ elsif elem.is_a?(CoreModel::Block) && elem.content
385
386
  preview = elem.content.to_s[0..50]
386
387
  preview += '...' if elem.content.to_s.length > 50
387
388
  "#{type}: #{preview}"
@@ -411,10 +412,10 @@ module Coradoc
411
412
  private
412
413
 
413
414
  def count_elements(doc)
414
- return 0 unless doc.respond_to?(:children)
415
+ return 0 unless doc.is_a?(CoreModel::StructuralElement)
415
416
 
416
417
  doc.children.sum do |child|
417
- 1 + (child.respond_to?(:children) ? count_elements(child) : 0)
418
+ 1 + (child.is_a?(CoreModel::StructuralElement) ? count_elements(child) : 0)
418
419
  end
419
420
  end
420
421
 
@@ -423,11 +424,12 @@ module Coradoc
423
424
  visitor = Class.new(Visitor::Base) do
424
425
  define_method(:visit) do |element|
425
426
  if element.is_a?(CoreModel::Base)
426
- type_key = if element.respond_to?(:element_type) && element.element_type
427
+ has_element_type = element.is_a?(CoreModel::StructuralElement) || element.is_a?(CoreModel::Block)
428
+ type_key = if has_element_type && element.element_type
427
429
  element.element_type
428
430
  else
429
431
  element.class.name.split('::').last
430
- .gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
432
+ .gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
431
433
  end
432
434
  counts[type_key] += 1
433
435
  end
@@ -136,7 +136,7 @@ module Coradoc
136
136
  children_arr.map do |child|
137
137
  if child.is_a?(String)
138
138
  child
139
- elsif child.respond_to?(:to_hash)
139
+ elsif child.is_a?(Lutaml::Model::Serializable)
140
140
  child.to_hash
141
141
  else
142
142
  child.to_s
@@ -156,8 +156,8 @@ module Coradoc
156
156
 
157
157
  # Compare a single attribute between this model and another
158
158
  def compare_attribute(attr, other)
159
- self_value = send(attr)
160
- other_value = other.send(attr)
159
+ self_value = public_send(attr)
160
+ other_value = other.public_send(attr)
161
161
 
162
162
  case self_value
163
163
  when Array
@@ -45,13 +45,13 @@ module Coradoc
45
45
 
46
46
  # Delegate nested to nested_list (lutaml attribute added by list_block.rb)
47
47
  def nested
48
- nested_list if respond_to?(:nested_list)
48
+ nested_list
49
49
  end
50
50
 
51
51
  # Set nested list
52
52
  # @param value [ListBlock, nil] nested list block
53
53
  def nested=(value)
54
- self.nested_list = value if respond_to?(:nested_list=)
54
+ self.nested_list = value
55
55
  end
56
56
 
57
57
  # Convert to hash representation
@@ -62,7 +62,7 @@ module Coradoc
62
62
  marker: marker,
63
63
  content: content,
64
64
  nested_list: nested&.to_h,
65
- children: children&.map { |child| child.respond_to?(:to_h) ? child.to_h : child }
65
+ children: children&.map { |child| child.is_a?(CoreModel::Base) ? child.to_h : child }
66
66
  }.compact
67
67
  end
68
68
 
@@ -71,7 +71,7 @@ module Coradoc
71
71
  # Find all sections in the document within level range
72
72
  def find_sections(element, min_level, max_level)
73
73
  sections = []
74
- return sections unless element.respond_to?(:children)
74
+ return sections unless element.is_a?(CoreModel::StructuralElement)
75
75
 
76
76
  Array(element.children).each do |child|
77
77
  next unless child.is_a?(CoreModel::StructuralElement)
@@ -22,7 +22,7 @@ module Coradoc
22
22
  DocumentManipulator.new(filtered)
23
23
  end
24
24
 
25
- def transform_text(&block)
25
+ def transform_text
26
26
  return self unless block_given?
27
27
 
28
28
  Visitor::Transformer.new do |element|
@@ -36,13 +36,11 @@ module Coradoc
36
36
  self
37
37
  end
38
38
 
39
- def transform_headings(&block)
39
+ def transform_headings
40
40
  return self unless block_given?
41
41
 
42
42
  Visitor::Transformer.new do |element|
43
- if element.is_a?(CoreModel::StructuralElement) && element.title.is_a?(String)
44
- element.title = yield(element.title)
45
- end
43
+ element.title = yield(element.title) if element.is_a?(CoreModel::StructuralElement) && element.title.is_a?(String)
46
44
  end.visit(@document)
47
45
  self
48
46
  end
@@ -64,7 +62,7 @@ module Coradoc
64
62
 
65
63
  def remove_elements(element_type)
66
64
  Visitor::Transformer.new do |element|
67
- next unless element.respond_to?(:children) && element.children
65
+ next unless element.is_a?(CoreModel::StructuralElement) && element.children
68
66
 
69
67
  element.children.reject! do |child|
70
68
  match_element_type?(child, element_type)
@@ -128,15 +126,13 @@ module Coradoc
128
126
  end
129
127
 
130
128
  def filter_sections(element, level: nil, title: nil)
131
- if element.respond_to?(:children) && element.children
129
+ if element.is_a?(CoreModel::StructuralElement) && element.children
132
130
  element.children = element.children
133
131
  .map { |child| filter_sections(child, level: level, title: title) }
134
132
  .compact
135
133
  end
136
134
 
137
- if element.is_a?(CoreModel::StructuralElement) && element.section? && !element.document?
138
- return nil unless section_matches?(element, level: level, title: title)
139
- end
135
+ return nil if element.is_a?(CoreModel::StructuralElement) && element.section? && !element.document? && !section_matches?(element, level: level, title: title)
140
136
 
141
137
  element
142
138
  end
@@ -154,7 +150,7 @@ module Coradoc
154
150
  element_title = section.title || ''
155
151
  case title
156
152
  when String then return false unless element_title.include?(title)
157
- when Regexp then return false unless element_title =~ title
153
+ when Regexp then return false unless element_title&.match?(title)
158
154
  end
159
155
  end
160
156
 
@@ -163,7 +159,7 @@ module Coradoc
163
159
 
164
160
  def collect_sections(element, max_level: 3, current_level: 1)
165
161
  sections = []
166
- return sections unless element.respond_to?(:children)
162
+ return sections unless element.is_a?(CoreModel::StructuralElement)
167
163
 
168
164
  element.children.each do |child|
169
165
  next unless child.is_a?(CoreModel::StructuralElement) &&
@@ -186,7 +182,7 @@ module Coradoc
186
182
  when CoreModel::Base
187
183
  cloned = element.class.new
188
184
  element.class.attributes.each_key do |name|
189
- cloned.send("#{name}=", deep_clone(element.send(name)))
185
+ cloned.public_send("#{name}=", deep_clone(element.public_send(name)))
190
186
  end
191
187
  cloned
192
188
  when Array
@@ -19,17 +19,29 @@ module Coradoc
19
19
  MINIMUM_PARSE_METHODS = %i[parse_to_core parse].freeze
20
20
  REQUIRED_METHODS = %i[serialize].freeze
21
21
 
22
+ # Default implementations for optional format module methods.
23
+ # Format modules are auto-extended with this during registration.
24
+ module Interface
25
+ def handles_model?(_model)
26
+ false
27
+ end
28
+
29
+ def serialize?
30
+ true
31
+ end
32
+ end
33
+
22
34
  # Validate that a format module implements the minimum interface.
23
35
  # Warns to $stderr if methods are missing. Returns true if valid.
24
36
  def self.validate!(format_module, format_name)
25
- has_parse = MINIMUM_PARSE_METHODS.any? { |m| format_module.respond_to?(m) }
26
- has_serialize = REQUIRED_METHODS.all? { |m| format_module.respond_to?(m) }
37
+ has_parse = MINIMUM_PARSE_METHODS.any? { |m| format_module.public_methods.include?(m) }
38
+ has_serialize = REQUIRED_METHODS.all? { |m| format_module.public_methods.include?(m) }
27
39
 
28
40
  return true if has_parse && has_serialize
29
41
 
30
42
  missing = []
31
- missing << "parse_to_core or parse" unless has_parse
32
- missing << "serialize" unless has_serialize
43
+ missing << 'parse_to_core or parse' unless has_parse
44
+ missing << 'serialize' unless has_serialize
33
45
  warn "Coradoc: format :#{format_name} (#{format_module}) missing: #{missing.join(', ')}"
34
46
  false
35
47
  end
data/lib/coradoc/input.rb CHANGED
@@ -17,6 +17,6 @@ module Coradoc
17
17
  #
18
18
  module Input
19
19
  extend ProcessorRegistry
20
- self.error_label = "input processor"
20
+ self.error_label = 'input processor'
21
21
  end
22
22
  end
@@ -17,6 +17,6 @@ module Coradoc
17
17
  #
18
18
  module Output
19
19
  extend ProcessorRegistry
20
- self.error_label = "output processor"
20
+ self.error_label = 'output processor'
21
21
  end
22
22
  end