moxml 0.1.26 → 0.3.0

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/windows.yml +62 -0
  3. data/Gemfile +3 -1
  4. data/README.adoc +69 -6
  5. data/lib/compat/opal/moxml_boot.rb +6 -1
  6. data/lib/moxml/adapter/base.rb +53 -56
  7. data/lib/moxml/adapter/customized_leptris/declaration.rb +32 -0
  8. data/lib/moxml/adapter/customized_leptris/doctype.rb +31 -0
  9. data/lib/moxml/adapter/customized_leptris/entity_reference.rb +12 -0
  10. data/lib/moxml/adapter/customized_leptris/text_segment.rb +26 -0
  11. data/lib/moxml/adapter/customized_leptris.rb +16 -0
  12. data/lib/moxml/adapter/customized_libxml/cdata.rb +3 -12
  13. data/lib/moxml/adapter/customized_libxml/comment.rb +2 -9
  14. data/lib/moxml/adapter/customized_libxml/declaration.rb +1 -10
  15. data/lib/moxml/adapter/customized_libxml/node.rb +8 -0
  16. data/lib/moxml/adapter/customized_libxml/processing_instruction.rb +2 -10
  17. data/lib/moxml/adapter/customized_libxml/text.rb +2 -9
  18. data/lib/moxml/adapter/customized_oga/entity_decoder.rb +37 -0
  19. data/lib/moxml/adapter/customized_oga/raw_value_override.rb +52 -0
  20. data/lib/moxml/adapter/customized_oga/xml_generator.rb +4 -34
  21. data/lib/moxml/adapter/customized_oga.rb +2 -0
  22. data/lib/moxml/adapter/customized_ox/entity_reference.rb +1 -17
  23. data/lib/moxml/adapter/customized_rexml/entity_reference.rb +1 -11
  24. data/lib/moxml/adapter/headed_ox.rb +9 -128
  25. data/lib/moxml/adapter/leptris.rb +965 -0
  26. data/lib/moxml/adapter/libxml.rb +137 -117
  27. data/lib/moxml/adapter/nokogiri.rb +29 -8
  28. data/lib/moxml/adapter/oga.rb +139 -55
  29. data/lib/moxml/adapter/ox.rb +93 -137
  30. data/lib/moxml/adapter/rexml.rb +64 -51
  31. data/lib/moxml/adapter.rb +2 -1
  32. data/lib/moxml/attribute.rb +8 -4
  33. data/lib/moxml/attribute_resolver.rb +189 -0
  34. data/lib/moxml/builder.rb +0 -18
  35. data/lib/moxml/config.rb +29 -5
  36. data/lib/moxml/context.rb +33 -0
  37. data/lib/moxml/document.rb +1 -1
  38. data/lib/moxml/element.rb +29 -12
  39. data/lib/moxml/entity/reference.rb +28 -0
  40. data/lib/moxml/entity/restorer.rb +95 -0
  41. data/lib/moxml/entity.rb +126 -0
  42. data/lib/moxml/entity_registry.rb +1 -1
  43. data/lib/moxml/error.rb +0 -42
  44. data/lib/moxml/node.rb +135 -10
  45. data/lib/moxml/node_set.rb +1 -1
  46. data/lib/moxml/sax/namespace_splitter.rb +5 -2
  47. data/lib/moxml/signature/model/key/dsa_key_value.rb +1 -2
  48. data/lib/moxml/version.rb +1 -1
  49. data/lib/moxml/xml_emitter.rb +71 -0
  50. data/lib/moxml/xpath/compiler.rb +143 -8
  51. data/lib/moxml/xpath/parser.rb +22 -15
  52. data/lib/moxml.rb +3 -3
  53. data/spec/examples/readme_examples_spec.rb +0 -4
  54. data/spec/examples/xpath_examples_spec.rb +0 -11
  55. data/spec/integration/all_adapters_spec.rb +18 -1
  56. data/spec/integration/sax_parity_spec.rb +58 -0
  57. data/spec/integration/shared_examples/edge_cases.rb +0 -10
  58. data/spec/integration/shared_examples/high_level/{document_builder_behavior.rb → parse_behavior.rb} +1 -2
  59. data/spec/integration/shared_examples/integration_workflows.rb +0 -10
  60. data/spec/integration/shared_examples/node_wrappers/attribute_behavior.rb +98 -0
  61. data/spec/integration/shared_examples/node_wrappers/namespace_behavior.rb +26 -0
  62. data/spec/integration/shared_examples/node_wrappers/node_behavior.rb +15 -8
  63. data/spec/moxml/adapter/leptris_spec.rb +75 -0
  64. data/spec/moxml/adapter/libxml_internals_spec.rb +1 -1
  65. data/spec/moxml/adapter/ox_spec.rb +20 -6
  66. data/spec/moxml/adapter/platform_spec.rb +15 -2
  67. data/spec/moxml/adapter/shared_examples/adapter_contract.rb +180 -0
  68. data/spec/moxml/attribute_resolver_spec.rb +108 -0
  69. data/spec/moxml/config_spec.rb +0 -1
  70. data/spec/moxml/context_spec.rb +22 -0
  71. data/spec/moxml/doctype_spec.rb +1 -1
  72. data/spec/moxml/entity_spec.rb +76 -0
  73. data/spec/moxml/error_spec.rb +0 -50
  74. data/spec/moxml/node_spec.rb +104 -0
  75. data/spec/moxml/sax_entity_parity_spec.rb +358 -0
  76. data/spec/moxml/xml_emitter_spec.rb +64 -0
  77. data/spec/moxml/xpath/axes_spec.rb +112 -0
  78. data/spec/moxml/xpath/parser_spec.rb +6 -0
  79. data/spec/moxml/xpath_capabilities_spec.rb +5 -3
  80. data/spec/performance/benchmark_spec.rb +13 -6
  81. data/spec/performance/thread_safety_spec.rb +0 -4
  82. data/spec/spec_helper.rb +5 -1
  83. metadata +23 -6
  84. data/lib/moxml/adapter/libxml/entity_restorer.rb +0 -94
  85. data/lib/moxml/document_builder.rb +0 -167
  86. data/spec/moxml/document_builder_spec.rb +0 -30
@@ -23,14 +23,21 @@ RSpec.shared_examples "Performance Examples" do
23
23
  context "measures performance" do
24
24
  let(:doc) { context.parse(large_xml) }
25
25
 
26
+ # Absolute ips varies more than 2x across machines and even between
27
+ # runs on the same machine (observed: rexml serializer 1.5-2.9 ips on
28
+ # one machine). These thresholds sit at roughly half of typical
29
+ # modern-runner throughput so they only trip on asymptotic
30
+ # regressions (accidental O(n^2), broken caching), not on hardware
31
+ # variance or a few percent of legitimate overhead.
26
32
  let(:thresholds) do
27
33
  {
28
- nokogiri: { parser: 15, serializer: 1000 },
29
- oga: { parser: 10, serializer: 100 },
30
- rexml: { parser: 0, serializer: 5 },
31
- ox: { parser: 2, serializer: 1000 },
32
- headed_ox: { parser: 2, serializer: 1000 },
33
- libxml: { parser: 500, serializer: 60 },
34
+ nokogiri: { parser: 8, serializer: 500 },
35
+ oga: { parser: 5, serializer: 50 },
36
+ rexml: { parser: 0, serializer: 1 },
37
+ ox: { parser: 1, serializer: 400 },
38
+ headed_ox: { parser: 1, serializer: 400 },
39
+ libxml: { parser: 200, serializer: 30 },
40
+ leptris: { parser: 1300, serializer: 600 },
34
41
  }
35
42
  end
36
43
 
@@ -20,10 +20,6 @@ RSpec.shared_examples "Thread Safety Examples" do
20
20
  end
21
21
 
22
22
  it "handles concurrent processing" do
23
- if Moxml.new.config.adapter_name == :ox
24
- skip "Ox doesn't have a native XPath"
25
- end
26
-
27
23
  processor = processor_class.new
28
24
  threads = []
29
25
  results = Queue.new
data/spec/spec_helper.rb CHANGED
@@ -101,7 +101,11 @@ RSpec.configure do |config|
101
101
  end
102
102
 
103
103
  Moxml.configure do |config|
104
- config.adapter = RUBY_ENGINE == "opal" ? Moxml::Config::OPAL_DEFAULT_ADAPTER : Moxml::Config::DEFAULT_ADAPTER
104
+ # Pin the suite baseline to the fallback adapter so results are
105
+ # reproducible regardless of whether the local environment has a
106
+ # leptris new enough to win the runtime-default probe. Leptris gets
107
+ # full coverage through its explicit adapter/integration matrices.
108
+ config.adapter = RUBY_ENGINE == "opal" ? Moxml::Config::OPAL_DEFAULT_ADAPTER : Moxml::Config::FALLBACK_ADAPTER
105
109
  config.strict_parsing = true
106
110
  config.default_encoding = "UTF-8"
107
111
  config.entity_load_mode = :optional if RUBY_ENGINE == "opal"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moxml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.26
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-22 00:00:00.000000000 Z
11
+ date: 2026-08-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Moxml is a unified XML manipulation library that provides a common API
@@ -27,6 +27,7 @@ files:
27
27
  - ".github/workflows/rake.yml"
28
28
  - ".github/workflows/release.yml"
29
29
  - ".github/workflows/round-trip.yml"
30
+ - ".github/workflows/windows.yml"
30
31
  - ".gitignore"
31
32
  - ".gitmodules"
32
33
  - ".rspec"
@@ -119,6 +120,11 @@ files:
119
120
  - lib/moxml.rb
120
121
  - lib/moxml/adapter.rb
121
122
  - lib/moxml/adapter/base.rb
123
+ - lib/moxml/adapter/customized_leptris.rb
124
+ - lib/moxml/adapter/customized_leptris/declaration.rb
125
+ - lib/moxml/adapter/customized_leptris/doctype.rb
126
+ - lib/moxml/adapter/customized_leptris/entity_reference.rb
127
+ - lib/moxml/adapter/customized_leptris/text_segment.rb
122
128
  - lib/moxml/adapter/customized_libxml.rb
123
129
  - lib/moxml/adapter/customized_libxml/cdata.rb
124
130
  - lib/moxml/adapter/customized_libxml/comment.rb
@@ -129,6 +135,8 @@ files:
129
135
  - lib/moxml/adapter/customized_libxml/processing_instruction.rb
130
136
  - lib/moxml/adapter/customized_libxml/text.rb
131
137
  - lib/moxml/adapter/customized_oga.rb
138
+ - lib/moxml/adapter/customized_oga/entity_decoder.rb
139
+ - lib/moxml/adapter/customized_oga/raw_value_override.rb
132
140
  - lib/moxml/adapter/customized_oga/xml_declaration.rb
133
141
  - lib/moxml/adapter/customized_oga/xml_generator.rb
134
142
  - lib/moxml/adapter/customized_ox.rb
@@ -140,14 +148,15 @@ files:
140
148
  - lib/moxml/adapter/customized_rexml/entity_reference.rb
141
149
  - lib/moxml/adapter/customized_rexml/formatter.rb
142
150
  - lib/moxml/adapter/headed_ox.rb
151
+ - lib/moxml/adapter/leptris.rb
143
152
  - lib/moxml/adapter/libxml.rb
144
153
  - lib/moxml/adapter/libxml/entity_ref_registry.rb
145
- - lib/moxml/adapter/libxml/entity_restorer.rb
146
154
  - lib/moxml/adapter/nokogiri.rb
147
155
  - lib/moxml/adapter/oga.rb
148
156
  - lib/moxml/adapter/ox.rb
149
157
  - lib/moxml/adapter/rexml.rb
150
158
  - lib/moxml/attribute.rb
159
+ - lib/moxml/attribute_resolver.rb
151
160
  - lib/moxml/builder.rb
152
161
  - lib/moxml/c14n.rb
153
162
  - lib/moxml/c14n/attribute_handler.rb
@@ -177,8 +186,10 @@ files:
177
186
  - lib/moxml/declaration.rb
178
187
  - lib/moxml/doctype.rb
179
188
  - lib/moxml/document.rb
180
- - lib/moxml/document_builder.rb
181
189
  - lib/moxml/element.rb
190
+ - lib/moxml/entity.rb
191
+ - lib/moxml/entity/reference.rb
192
+ - lib/moxml/entity/restorer.rb
182
193
  - lib/moxml/entity_reference.rb
183
194
  - lib/moxml/entity_registry.rb
184
195
  - lib/moxml/entity_registry_opal_data.rb
@@ -246,6 +257,7 @@ files:
246
257
  - lib/moxml/signature/verifier.rb
247
258
  - lib/moxml/text.rb
248
259
  - lib/moxml/version.rb
260
+ - lib/moxml/xml_emitter.rb
249
261
  - lib/moxml/xml_utils.rb
250
262
  - lib/moxml/xml_utils/encoder.rb
251
263
  - lib/moxml/xpath.rb
@@ -371,12 +383,13 @@ files:
371
383
  - spec/integration/README.md
372
384
  - spec/integration/all_adapters_spec.rb
373
385
  - spec/integration/headed_ox_integration_spec.rb
386
+ - spec/integration/sax_parity_spec.rb
374
387
  - spec/integration/shared_examples/edge_cases.rb
375
388
  - spec/integration/shared_examples/entity_reference_whitespace.rb
376
389
  - spec/integration/shared_examples/high_level/.gitkeep
377
390
  - spec/integration/shared_examples/high_level/builder_behavior.rb
378
391
  - spec/integration/shared_examples/high_level/context_behavior.rb
379
- - spec/integration/shared_examples/high_level/document_builder_behavior.rb
392
+ - spec/integration/shared_examples/high_level/parse_behavior.rb
380
393
  - spec/integration/shared_examples/integration_workflows.rb
381
394
  - spec/integration/shared_examples/line_ending_behavior.rb
382
395
  - spec/integration/shared_examples/node_wrappers/.gitkeep
@@ -401,6 +414,7 @@ files:
401
414
  - spec/moxml/adapter/base_spec.rb
402
415
  - spec/moxml/adapter/entity_restoration_spec.rb
403
416
  - spec/moxml/adapter/headed_ox_spec.rb
417
+ - spec/moxml/adapter/leptris_spec.rb
404
418
  - spec/moxml/adapter/libxml_internals_spec.rb
405
419
  - spec/moxml/adapter/libxml_spec.rb
406
420
  - spec/moxml/adapter/nokogiri_spec.rb
@@ -413,6 +427,7 @@ files:
413
427
  - spec/moxml/adapter_spec.rb
414
428
  - spec/moxml/allocation_benchmark_spec.rb
415
429
  - spec/moxml/allocation_guard_spec.rb
430
+ - spec/moxml/attribute_resolver_spec.rb
416
431
  - spec/moxml/attribute_spec.rb
417
432
  - spec/moxml/builder_spec.rb
418
433
  - spec/moxml/c14n/api_spec.rb
@@ -428,12 +443,12 @@ files:
428
443
  - spec/moxml/declaration_preservation_spec.rb
429
444
  - spec/moxml/declaration_spec.rb
430
445
  - spec/moxml/doctype_spec.rb
431
- - spec/moxml/document_builder_spec.rb
432
446
  - spec/moxml/document_spec.rb
433
447
  - spec/moxml/element_spec.rb
434
448
  - spec/moxml/entity_preservation_spec.rb
435
449
  - spec/moxml/entity_reference_spec.rb
436
450
  - spec/moxml/entity_registry_spec.rb
451
+ - spec/moxml/entity_spec.rb
437
452
  - spec/moxml/error_spec.rb
438
453
  - spec/moxml/lazy_parse_spec.rb
439
454
  - spec/moxml/moxml_spec.rb
@@ -455,6 +470,7 @@ files:
455
470
  - spec/moxml/opal_smoke_spec.rb
456
471
  - spec/moxml/processing_instruction_spec.rb
457
472
  - spec/moxml/sax/namespace_splitter_spec.rb
473
+ - spec/moxml/sax_entity_parity_spec.rb
458
474
  - spec/moxml/sax_spec.rb
459
475
  - spec/moxml/signature/algorithms/base64_transform_spec.rb
460
476
  - spec/moxml/signature/algorithms/digest_base_spec.rb
@@ -472,6 +488,7 @@ files:
472
488
  - spec/moxml/signature/round_trip_spec.rb
473
489
  - spec/moxml/text_spec.rb
474
490
  - spec/moxml/version_spec.rb
491
+ - spec/moxml/xml_emitter_spec.rb
475
492
  - spec/moxml/xml_utils/.gitkeep
476
493
  - spec/moxml/xml_utils/encoder_spec.rb
477
494
  - spec/moxml/xml_utils_spec.rb
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Moxml
4
- module Adapter
5
- class Libxml < Base
6
- # Restores configured character entities into explicit Moxml
7
- # EntityReference nodes after LibXML has parsed the native tree.
8
- class EntityRestorer
9
- def initialize(doc, adapter: Libxml)
10
- @doc = doc
11
- @ctx = doc.context
12
- @registry = @ctx.entity_registry
13
- @config = @ctx.config
14
- @adapter = adapter
15
- end
16
-
17
- def run
18
- return unless @registry && @doc.root
19
-
20
- walk(@doc.root)
21
- end
22
-
23
- private
24
-
25
- def walk(element)
26
- # Snapshot because we may add/remove siblings during the walk.
27
- element.children.to_a.each do |child|
28
- if child.is_a?(::Moxml::Text)
29
- restore_text_node(child)
30
- elsif child.is_a?(::Moxml::Element)
31
- walk(child)
32
- end
33
- end
34
- end
35
-
36
- # Matches DocumentBuilder's previous behavior, including the libxml
37
- # limitation that adjacent native text nodes get merged.
38
- def restore_text_node(text_node)
39
- content = text_node.content
40
- return unless content
41
-
42
- chunks = chunk_text(content)
43
- return if chunks.size == 1 && chunks.first.first == :text
44
-
45
- parent = text_node.parent
46
- return unless parent
47
-
48
- text_node.remove
49
- chunks.each { |type, payload| append_chunk(parent, type, payload) }
50
- end
51
-
52
- def chunk_text(content)
53
- chunks = []
54
- buffer = +""
55
- restorable = @registry.restorable_codepoints
56
-
57
- content.each_char do |char|
58
- cp = char.ord
59
- if restorable.include?(cp) &&
60
- (name = @registry.primary_name_for_codepoint(cp)) &&
61
- @registry.should_restore?(cp, config: @config)
62
- unless buffer.empty?
63
- chunks << [:text, buffer.dup]
64
- buffer.clear
65
- end
66
- chunks << [:eref, name]
67
- else
68
- buffer << char
69
- end
70
- end
71
-
72
- chunks << [:text, buffer.dup] unless buffer.empty?
73
- chunks
74
- end
75
-
76
- def append_chunk(parent, type, payload)
77
- case type
78
- when :text
79
- parent.add_child(::Moxml::Text.new(
80
- @adapter.create_native_text(payload), @ctx
81
- ))
82
- when :eref
83
- parent.add_child(
84
- ::Moxml::EntityReference.new(
85
- @adapter.create_native_entity_reference(payload),
86
- @ctx,
87
- ),
88
- )
89
- end
90
- end
91
- end
92
- end
93
- end
94
- end
@@ -1,167 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Moxml
4
- class DocumentBuilder
5
- attr_reader :context
6
-
7
- def initialize(context)
8
- @context = context
9
- @node_stack = []
10
- end
11
-
12
- def build(native_doc)
13
- @current_doc = context.create_document(native_doc)
14
-
15
- # Transfer has_declaration flag if present in attachments
16
- if adapter.attachments.key?(native_doc, :has_declaration)
17
- has_declaration = adapter.attachments.get(native_doc, :has_declaration)
18
- @current_doc.has_xml_declaration = has_declaration
19
- end
20
-
21
- # Transfer DOCTYPE from parsed document if it exists in attachments
22
- if adapter.attachments.key?(native_doc, :doctype)
23
- doctype = adapter.attachments.get(native_doc, :doctype)
24
- if doctype
25
- adapter.attachments.set(@current_doc.native, :doctype, doctype)
26
- end
27
- end
28
-
29
- visit_node(native_doc)
30
- @current_doc
31
- end
32
-
33
- private
34
-
35
- def visit_node(node)
36
- case node_type(node)
37
- when :document then visit_document(node)
38
- when :element then visit_element(node)
39
- when :text then visit_text(node)
40
- when :cdata then visit_cdata(node)
41
- when :comment then visit_comment(node)
42
- when :processing_instruction then visit_processing_instruction(node)
43
- when :doctype then visit_doctype(node)
44
- when :entity_reference then visit_entity_reference(node)
45
- end
46
- end
47
-
48
- def visit_document(doc)
49
- @node_stack.push(@current_doc)
50
- visit_children(doc)
51
- @node_stack.clear
52
- end
53
-
54
- def visit_element(node)
55
- childless_node = adapter.duplicate_node(node)
56
- adapter.replace_children(childless_node, [])
57
- # Prepare node for new document (LibXML needs this)
58
- childless_node = adapter.prepare_for_new_document(
59
- childless_node,
60
- @current_doc.native,
61
- )
62
- element = Element.new(childless_node, context)
63
- @node_stack.last.add_child(element)
64
-
65
- @node_stack.push(element) # add a parent for its children
66
- visit_children(node)
67
- @node_stack.pop # remove the parent
68
- end
69
-
70
- def visit_text(node)
71
- # Prepare node for new document before wrapping
72
- prepared = adapter.prepare_for_new_document(node, @current_doc.native)
73
- content = adapter.text_content(node)
74
-
75
- # Check if we should restore entity references for this text
76
- if context.config.restore_entities && text_has_restorable_entities?(content)
77
- restore_entities_in_text(content)
78
- else
79
- @node_stack.last&.add_child(Text.new(prepared, context))
80
- end
81
- end
82
-
83
- def text_has_restorable_entities?(content)
84
- return false unless content
85
-
86
- registry = context.entity_registry
87
- codepoints = registry.restorable_codepoints
88
- content.each_char do |char|
89
- return true if codepoints.include?(char.ord)
90
- end
91
- false
92
- end
93
-
94
- def restore_entities_in_text(content)
95
- parent = @node_stack.last
96
- return unless parent
97
-
98
- registry = context.entity_registry
99
- config = context.config
100
- buffer = +""
101
-
102
- content.to_s.each_char do |char|
103
- codepoint = char.ord
104
- name = registry.primary_name_for_codepoint(codepoint)
105
-
106
- if name && registry.should_restore?(codepoint, config: config)
107
- # Flush buffered text before the entity
108
- unless buffer.empty?
109
- parent.add_child(Text.new(adapter.create_text(buffer), context))
110
- buffer.clear
111
- end
112
- parent.add_child(
113
- EntityReference.new(adapter.create_entity_reference(name), context),
114
- )
115
- else
116
- buffer << char
117
- end
118
- end
119
-
120
- # Flush remaining buffer
121
- unless buffer.empty?
122
- parent.add_child(Text.new(adapter.create_text(buffer), context))
123
- end
124
- end
125
-
126
- def visit_cdata(node)
127
- prepared = adapter.prepare_for_new_document(node, @current_doc.native)
128
- @node_stack.last&.add_child(Cdata.new(prepared, context))
129
- end
130
-
131
- def visit_comment(node)
132
- prepared = adapter.prepare_for_new_document(node, @current_doc.native)
133
- @node_stack.last&.add_child(Comment.new(prepared, context))
134
- end
135
-
136
- def visit_processing_instruction(node)
137
- prepared = adapter.prepare_for_new_document(node, @current_doc.native)
138
- @node_stack.last&.add_child(ProcessingInstruction.new(prepared, context))
139
- end
140
-
141
- def visit_doctype(node)
142
- prepared = adapter.prepare_for_new_document(node, @current_doc.native)
143
- @node_stack.last&.add_child(Doctype.new(prepared, context))
144
- end
145
-
146
- def visit_entity_reference(node)
147
- prepared = adapter.prepare_for_new_document(node, @current_doc.native)
148
- @node_stack.last&.add_child(EntityReference.new(prepared, context))
149
- end
150
-
151
- def visit_children(node)
152
- children(node).each { |child| visit_node(child) }
153
- end
154
-
155
- def node_type(node)
156
- context.config.adapter.node_type(node)
157
- end
158
-
159
- def children(node)
160
- context.config.adapter.children(node)
161
- end
162
-
163
- def adapter
164
- context.config.adapter
165
- end
166
- end
167
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- # DocumentBuilder is an internal class for parsing
6
- # These tests verify it correctly builds Moxml document from native documents
7
- RSpec.describe Moxml::DocumentBuilder do
8
- let(:context) { Moxml.new }
9
-
10
- describe "#build" do
11
- it "builds a Moxml document from native document" do
12
- native_doc = context.parse("<root><child>content</child></root>").native
13
- builder = described_class.new(context)
14
- doc = builder.build(native_doc)
15
-
16
- expect(doc).to be_a(Moxml::Document)
17
- expect(doc.root.name).to eq("root")
18
- end
19
- end
20
-
21
- describe "element handling" do
22
- it "handles nested elements" do
23
- native_doc = context.parse("<parent><child1/><child2/></parent>").native
24
- builder = described_class.new(context)
25
- doc = builder.build(native_doc)
26
-
27
- expect(doc.root.children.length).to eq(2)
28
- end
29
- end
30
- end