moxml 0.5.61 → 0.5.62
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.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +5 -0
- data/Rakefile +10 -0
- data/benchmark/plan_bench.rb +118 -0
- data/lib/moxml/adapter/base.rb +9 -5
- data/lib/moxml/adapter/libxml.rb +32 -0
- data/lib/moxml/adapter/nokogiri.rb +23 -0
- data/lib/moxml/adapter/oga.rb +28 -0
- data/lib/moxml/adapter/ox.rb +29 -0
- data/lib/moxml/adapter/rexml.rb +18 -0
- data/lib/moxml/version.rb +1 -1
- data/spec/moxml/plan_conformance_spec.rb +80 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 430e3a7e8c18cfa2c083ae9b263e9fedbaed03c109811980f0ca51de36507be7
|
|
4
|
+
data.tar.gz: 9644f7689ef2126884a6b11ecfcf9c532e0b2cae9cb44005b5b6b3434d96c7b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9f89223d0bc12427916bb46220f79d957df704b878ea02dc11387c9096c6829f5309ed857a3faa4c1b9aee0697b3dfe2f7fa9f73fc5e083b6c1c0963bea11501
|
|
7
|
+
data.tar.gz: 5120f5700dd76a688576501a90ee2e6ffc443558cb89478dd23f2ea5a424d29dac41dd4df4cb9acc764451b81f84c5a03eed3d4ab734adfa276c7a1043bf54ce
|
data/.github/workflows/rake.yml
CHANGED
data/Rakefile
CHANGED
|
@@ -253,6 +253,16 @@ namespace :benchmark do
|
|
|
253
253
|
sh "ruby", "benchmark/pipeline_bench.rb"
|
|
254
254
|
end
|
|
255
255
|
|
|
256
|
+
# Plan-bench regression lock (#249 follow-up): Moxml::Plan vs the
|
|
257
|
+
# wrapper walk vs raw nokogiri on the consumer shape. With
|
|
258
|
+
# LEPTRIS_BENCH_LOCK=1 (CI) it exits 1 when plan time exceeds
|
|
259
|
+
# 1.5x raw nokogiri — the "raw-nokogiri CPU parity" regression
|
|
260
|
+
# tripwire.
|
|
261
|
+
desc "Plan materialization benchmark with raw-nokogiri parity lock"
|
|
262
|
+
task :plan do
|
|
263
|
+
sh "bundle exec ruby benchmark/plan_bench.rb"
|
|
264
|
+
end
|
|
265
|
+
|
|
256
266
|
desc "Generate adapter benchmark report"
|
|
257
267
|
task :report do
|
|
258
268
|
ruby "benchmarks/generate_report.rb"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Plan-bench regression lock (leptris follow-up to #249): the plan
|
|
4
|
+
# path must stay at or near raw-nokogiri CPU parity on the consumer
|
|
5
|
+
# shape. Run via `rake benchmark:plan` or with LEPTRIS_BENCH_LOCK=1
|
|
6
|
+
# to enforce the ceiling (CI): plan <= nokogiri * 1.5 — failures
|
|
7
|
+
# mean an adapter or plan change regressed the compiled walk.
|
|
8
|
+
require "moxml"
|
|
9
|
+
require "nokogiri"
|
|
10
|
+
|
|
11
|
+
Field = Struct.new(:name, :unit, :value)
|
|
12
|
+
Record = Struct.new(:id, :kind, :fields)
|
|
13
|
+
Catalog = Struct.new(:records)
|
|
14
|
+
|
|
15
|
+
parts = [%(<?xml version="1.0"?><catalog>)]
|
|
16
|
+
150.times do |i|
|
|
17
|
+
parts << %(<record id="r#{i}" kind="k#{i % 3}">)
|
|
18
|
+
6.times { |j| parts << %(<field name="f#{j}" unit="u#{j}">value #{i}.#{j}</field>) }
|
|
19
|
+
parts << %(</record>)
|
|
20
|
+
end
|
|
21
|
+
parts << %(</catalog>)
|
|
22
|
+
XML = parts.join
|
|
23
|
+
|
|
24
|
+
CTX = Moxml.new(:leptris)
|
|
25
|
+
|
|
26
|
+
PLAN = Moxml::Plan.new do
|
|
27
|
+
on("record") { |attrs, _t, fields| Record.new(attrs["id"], attrs["kind"], fields) }
|
|
28
|
+
on("field") { |attrs, text, _k| Field.new(attrs["name"], attrs["unit"], text) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def plan_run
|
|
32
|
+
records = PLAN.parse(XML, CTX)
|
|
33
|
+
raise "shape" unless records.size == 150 && records[7].fields[3].value == "value 7.3"
|
|
34
|
+
|
|
35
|
+
records
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def wrapper_run
|
|
39
|
+
doc = CTX.parse(XML)
|
|
40
|
+
catalog = Catalog.new([])
|
|
41
|
+
doc.root.children.each do |rec|
|
|
42
|
+
next unless rec.is_a?(Moxml::Element)
|
|
43
|
+
|
|
44
|
+
record = Record.new(rec["id"], rec["kind"], [])
|
|
45
|
+
rec.children.each do |f|
|
|
46
|
+
next unless f.is_a?(Moxml::Element)
|
|
47
|
+
|
|
48
|
+
record.fields << Field.new(f["name"], f["unit"], f.text)
|
|
49
|
+
end
|
|
50
|
+
catalog.records << record
|
|
51
|
+
end
|
|
52
|
+
raise "shape" unless catalog.records.size == 150
|
|
53
|
+
|
|
54
|
+
catalog
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def nokogiri_run
|
|
58
|
+
doc = Nokogiri::XML(XML)
|
|
59
|
+
catalog = Catalog.new([])
|
|
60
|
+
doc.root.children.each do |rec|
|
|
61
|
+
next unless rec.is_a?(Nokogiri::XML::Element)
|
|
62
|
+
|
|
63
|
+
record = Record.new(rec["id"], rec["kind"], [])
|
|
64
|
+
rec.children.each do |f|
|
|
65
|
+
next unless f.is_a?(Nokogiri::XML::Element)
|
|
66
|
+
|
|
67
|
+
record.fields << Field.new(f["name"], f["unit"], f.text)
|
|
68
|
+
end
|
|
69
|
+
catalog.records << record
|
|
70
|
+
end
|
|
71
|
+
raise "shape" unless catalog.records.size == 150
|
|
72
|
+
|
|
73
|
+
catalog
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
REPS = 200
|
|
77
|
+
|
|
78
|
+
def bench(&block)
|
|
79
|
+
times = []
|
|
80
|
+
allocs = []
|
|
81
|
+
REPS.times do
|
|
82
|
+
GC.start
|
|
83
|
+
a0 = GC.stat(:total_allocated_objects)
|
|
84
|
+
t0 = Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID)
|
|
85
|
+
yield
|
|
86
|
+
times << (Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID) - t0)
|
|
87
|
+
allocs << (GC.stat(:total_allocated_objects) - a0)
|
|
88
|
+
end
|
|
89
|
+
[times.sort[times.size / 2] * 1e6, allocs.min]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The parity lock needs the lean plan rows (binding 1.9.194.2+);
|
|
93
|
+
# on older bindings the plan runs the generic fallback and the
|
|
94
|
+
# ceiling is meaningless — report and exit clean.
|
|
95
|
+
if Gem::Version.new(Leptris::VERSION) < Gem::Version.new("1.9.194.2")
|
|
96
|
+
puts "SKIP parity lock: leptris #{Leptris::VERSION} lacks snapshot_rows (needs 1.9.194.2)"
|
|
97
|
+
exit 0
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# warm
|
|
101
|
+
plan_run
|
|
102
|
+
wrapper_run
|
|
103
|
+
nokogiri_run
|
|
104
|
+
|
|
105
|
+
plan_us, plan_allocs = bench { plan_run }
|
|
106
|
+
wrap_us, wrap_allocs = bench { wrapper_run }
|
|
107
|
+
nk_us, nk_allocs = bench { nokogiri_run }
|
|
108
|
+
|
|
109
|
+
puts format("plan (parse+materialize) %<t>8.0f us %<a>7d allocs",
|
|
110
|
+
t: plan_us, a: plan_allocs)
|
|
111
|
+
puts format("wrapper (parse+walk) %<t>8.0f us %<a>7d allocs",
|
|
112
|
+
t: wrap_us, a: wrap_allocs)
|
|
113
|
+
puts format("nokogiri (parse+walk) %<t>8.0f us %<a>7d allocs",
|
|
114
|
+
t: nk_us, a: nk_allocs)
|
|
115
|
+
puts format("plan/nokogiri %<r>.2fx (ceiling 1.50x for the CI lock)",
|
|
116
|
+
r: plan_us / nk_us)
|
|
117
|
+
|
|
118
|
+
exit(1) if ENV["LEPTRIS_BENCH_LOCK"] && plan_us > nk_us * 1.5
|
data/lib/moxml/adapter/base.rb
CHANGED
|
@@ -358,11 +358,15 @@ namespace_validation_mode: :strict)
|
|
|
358
358
|
nil
|
|
359
359
|
end
|
|
360
360
|
|
|
361
|
-
# Plan row stream (Moxml::Plan)
|
|
362
|
-
# (flat [k, v, ...]), first-text, depth|
|
|
363
|
-
# document order (pre-order)
|
|
364
|
-
#
|
|
365
|
-
#
|
|
361
|
+
# Plan row stream (Moxml::Plan) — ADAPTER CONTRACT. Yields
|
|
362
|
+
# |name, attrs_pairs (flat [k, v, ...]), first-text, depth|
|
|
363
|
+
# per element in document order (pre-order); first-text is
|
|
364
|
+
# the element's first text child or nil. Adapters implement
|
|
365
|
+
# this natively off their engine nodes (nokogiri, ox, oga,
|
|
366
|
+
# rexml, libxml, leptris do) — Moxml::Plan executes entirely
|
|
367
|
+
# on these rows with no wrapper materialization. This default
|
|
368
|
+
# returns nil, which makes Moxml::Plan fall back to the
|
|
369
|
+
# generic wrapper walk — correct but slow; last resort only.
|
|
366
370
|
def plan_rows(_native)
|
|
367
371
|
nil
|
|
368
372
|
end
|
data/lib/moxml/adapter/libxml.rb
CHANGED
|
@@ -1312,6 +1312,38 @@ module Moxml
|
|
|
1312
1312
|
dst[attr_name] = attr.value
|
|
1313
1313
|
end
|
|
1314
1314
|
end
|
|
1315
|
+
|
|
1316
|
+
# Plan row stream (Moxml::Plan contract): pre-order element
|
|
1317
|
+
# rows straight off the LibXML nodes — no wrapper minting.
|
|
1318
|
+
def plan_rows(native)
|
|
1319
|
+
root = if native.is_a?(::LibXML::XML::Document)
|
|
1320
|
+
r = native.root
|
|
1321
|
+
return nil unless r
|
|
1322
|
+
|
|
1323
|
+
r
|
|
1324
|
+
else
|
|
1325
|
+
native
|
|
1326
|
+
end
|
|
1327
|
+
|
|
1328
|
+
walk = lambda do |el, depth|
|
|
1329
|
+
attrs = []
|
|
1330
|
+
el.attributes.each do |attr|
|
|
1331
|
+
attrs << attr.name << attr.value
|
|
1332
|
+
end
|
|
1333
|
+
first_text = nil
|
|
1334
|
+
el.children.each do |c|
|
|
1335
|
+
first_text ||= c.content if c.text?
|
|
1336
|
+
end
|
|
1337
|
+
yield(el.name, attrs, first_text, depth)
|
|
1338
|
+
el.children.each do |c|
|
|
1339
|
+
walk.call(c, depth + 1) if c.element?
|
|
1340
|
+
end
|
|
1341
|
+
end
|
|
1342
|
+
walk.call(root, 0)
|
|
1343
|
+
true
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
public :plan_rows
|
|
1315
1347
|
end
|
|
1316
1348
|
|
|
1317
1349
|
# Bridge between LibXML SAX and Moxml SAX
|
|
@@ -516,6 +516,25 @@ module Moxml
|
|
|
516
516
|
attachments.set(native_doc, :xml_decl, nil)
|
|
517
517
|
end
|
|
518
518
|
|
|
519
|
+
# Plan row stream (Moxml::Plan contract): pre-order element
|
|
520
|
+
# rows |name, attrs_pairs, first-text, depth| straight off
|
|
521
|
+
# the libxml2-backed nodes — no wrapper minting.
|
|
522
|
+
def plan_rows(native)
|
|
523
|
+
root = native.is_a?(::Nokogiri::XML::Document) ? native.root : native
|
|
524
|
+
return nil unless root
|
|
525
|
+
|
|
526
|
+
walk = lambda do |el, depth|
|
|
527
|
+
attrs = []
|
|
528
|
+
el.attribute_nodes.each { |a| attrs << a.name << a.value }
|
|
529
|
+
first_text = nil
|
|
530
|
+
el.children.each { |c| first_text ||= c.content if c.text? }
|
|
531
|
+
yield(el.name, attrs, first_text, depth)
|
|
532
|
+
el.element_children.each { |c| walk.call(c, depth + 1) }
|
|
533
|
+
end
|
|
534
|
+
walk.call(root, 0)
|
|
535
|
+
true
|
|
536
|
+
end
|
|
537
|
+
|
|
519
538
|
private
|
|
520
539
|
|
|
521
540
|
def build_declaration_attrs(version, encoding, standalone)
|
|
@@ -533,6 +552,10 @@ module Moxml
|
|
|
533
552
|
hsh.merge(attr_name => value)
|
|
534
553
|
end
|
|
535
554
|
end
|
|
555
|
+
|
|
556
|
+
# Plan row stream (Moxml::Plan contract): pre-order element
|
|
557
|
+
# rows |name, attrs_pairs, first-text, depth| straight off
|
|
558
|
+
# the libxml2-backed nodes — no wrapper minting.
|
|
536
559
|
end
|
|
537
560
|
|
|
538
561
|
# Bridge between Nokogiri SAX and Moxml SAX
|
data/lib/moxml/adapter/oga.rb
CHANGED
|
@@ -643,6 +643,34 @@ module Moxml
|
|
|
643
643
|
|
|
644
644
|
::Moxml::Adapter::CustomizedOga::XmlGenerator.new(node).to_xml
|
|
645
645
|
end
|
|
646
|
+
|
|
647
|
+
# Plan row stream (Moxml::Plan contract): pre-order element
|
|
648
|
+
# rows over Oga's Ruby node objects.
|
|
649
|
+
def plan_rows(native)
|
|
650
|
+
root = if native.is_a?(::Oga::XML::Document)
|
|
651
|
+
native.children.find { |c| c.is_a?(::Oga::XML::Element) }
|
|
652
|
+
else
|
|
653
|
+
native
|
|
654
|
+
end
|
|
655
|
+
return nil unless root.is_a?(::Oga::XML::Element)
|
|
656
|
+
|
|
657
|
+
walk = lambda do |el, depth|
|
|
658
|
+
attrs = []
|
|
659
|
+
el.attributes.each { |a| attrs << a.name << a.value }
|
|
660
|
+
first_text = nil
|
|
661
|
+
el.children.each do |c|
|
|
662
|
+
first_text ||= c.text if c.is_a?(::Oga::XML::Text)
|
|
663
|
+
end
|
|
664
|
+
yield(el.name, attrs, first_text, depth)
|
|
665
|
+
el.children.each do |c|
|
|
666
|
+
walk.call(c, depth + 1) if c.is_a?(::Oga::XML::Element)
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
walk.call(root, 0)
|
|
670
|
+
true
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
public :plan_rows
|
|
646
674
|
end
|
|
647
675
|
|
|
648
676
|
# Bridge between a parsed Oga DOM and Moxml SAX events.
|
data/lib/moxml/adapter/ox.rb
CHANGED
|
@@ -955,6 +955,35 @@ module Moxml
|
|
|
955
955
|
output << "</#{elem.name}>"
|
|
956
956
|
output
|
|
957
957
|
end
|
|
958
|
+
|
|
959
|
+
# Plan row stream (Moxml::Plan contract): pre-order element
|
|
960
|
+
# rows over Ox's Ruby node objects.
|
|
961
|
+
def plan_rows(native)
|
|
962
|
+
root = if native.is_a?(::Ox::Document)
|
|
963
|
+
nodes = native.nodes.grep(::Ox::Element)
|
|
964
|
+
nodes.first
|
|
965
|
+
else
|
|
966
|
+
native
|
|
967
|
+
end
|
|
968
|
+
return nil unless root.is_a?(::Ox::Element)
|
|
969
|
+
|
|
970
|
+
walk = lambda do |el, depth|
|
|
971
|
+
attrs = []
|
|
972
|
+
(el.attributes || {}).each { |k, v| attrs << k.to_s << v.to_s }
|
|
973
|
+
first_text = nil
|
|
974
|
+
(el.nodes || []).each do |c|
|
|
975
|
+
first_text ||= c if c.is_a?(::String)
|
|
976
|
+
end
|
|
977
|
+
yield(el.name.to_s, attrs, first_text, depth)
|
|
978
|
+
(el.nodes || []).each do |c|
|
|
979
|
+
walk.call(c, depth + 1) if c.is_a?(::Ox::Element)
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
walk.call(root, 0)
|
|
983
|
+
true
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
public :plan_rows
|
|
958
987
|
end
|
|
959
988
|
end
|
|
960
989
|
|
data/lib/moxml/adapter/rexml.rb
CHANGED
|
@@ -694,6 +694,24 @@ module Moxml
|
|
|
694
694
|
)
|
|
695
695
|
formatter.write(node, output)
|
|
696
696
|
end
|
|
697
|
+
|
|
698
|
+
# Plan row stream (Moxml::Plan contract): pre-order element
|
|
699
|
+
# rows over REXML's Ruby node objects.
|
|
700
|
+
def plan_rows(native)
|
|
701
|
+
root = native.is_a?(::REXML::Document) ? native.root : native
|
|
702
|
+
return nil unless root
|
|
703
|
+
|
|
704
|
+
walk = lambda do |el, depth|
|
|
705
|
+
attrs = []
|
|
706
|
+
el.attributes.each { |k, v| attrs << k << v }
|
|
707
|
+
yield(el.name, attrs, el.text, depth)
|
|
708
|
+
el.elements.each { |c| walk.call(c, depth + 1) }
|
|
709
|
+
end
|
|
710
|
+
walk.call(root, 0)
|
|
711
|
+
true
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
public :plan_rows
|
|
697
715
|
end
|
|
698
716
|
end
|
|
699
717
|
|
data/lib/moxml/version.rb
CHANGED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# Moxml::Plan adapter-contract conformance (leptris follow-up to
|
|
6
|
+
# #249): every adapter must produce IDENTICAL plan results on the
|
|
7
|
+
# same document, whether its plan_rows is a bulk C stream (leptris,
|
|
8
|
+
# nokogiri, libxml) or a Ruby-native walk (ox, oga, rexml).
|
|
9
|
+
PlanRow = Struct.new(:id, :kind, :fields)
|
|
10
|
+
PlanCell = Struct.new(:name, :unit, :value)
|
|
11
|
+
|
|
12
|
+
RSpec.describe "Moxml::Plan adapter conformance" do
|
|
13
|
+
# Single-line fixture: no inter-element whitespace text, so
|
|
14
|
+
# engines that differ on insignificant text still agree.
|
|
15
|
+
let(:xml) do
|
|
16
|
+
'<catalog><record id="r0" kind="k0"><field name="f0" unit="u0">v 0.0</field><field name="f1" unit="u1">v 0.1</field></record><record id="r1" kind="k1"><field name="f0" unit="u0">v 1.0</field></record></catalog>'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
let(:plan) do
|
|
20
|
+
Moxml::Plan.new do
|
|
21
|
+
on("record") do |attrs, _text, fields|
|
|
22
|
+
PlanRow.new(attrs["id"], attrs["kind"], fields)
|
|
23
|
+
end
|
|
24
|
+
on("field") do |attrs, text, _kids|
|
|
25
|
+
PlanCell.new(attrs["name"], attrs["unit"], text)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
ADAPTERS = %i[leptris nokogiri ox oga rexml libxml].freeze # rubocop:disable Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration
|
|
31
|
+
|
|
32
|
+
it "executes on every available adapter" do
|
|
33
|
+
available = ADAPTERS.select do |a|
|
|
34
|
+
ctx = Moxml.new(a)
|
|
35
|
+
ctx.parse(xml)
|
|
36
|
+
true
|
|
37
|
+
rescue StandardError
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
expect(available).not_to be_empty
|
|
41
|
+
|
|
42
|
+
results = available.to_h { |a| [a, plan.parse(xml, Moxml.new(a))] }
|
|
43
|
+
|
|
44
|
+
baseline = results[available.first]
|
|
45
|
+
results.each do |adapter, rows|
|
|
46
|
+
expect(rows).to eq(baseline), "adapter #{adapter} diverged"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
expect(baseline.size).to eq(2)
|
|
50
|
+
expect(baseline[0].fields.map(&:value)).to eq(["v 0.0", "v 0.1"])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "skips no element and preserves order" do
|
|
54
|
+
rows = plan.parse(xml, Moxml.new(:nokogiri))
|
|
55
|
+
|
|
56
|
+
expect(rows.map(&:id)).to eq(%w[r0 r1])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "handles depth-3 nesting identically" do
|
|
60
|
+
deep = Moxml::Plan.new do
|
|
61
|
+
on("catalog") { |_a, _t, records| records }
|
|
62
|
+
on("record") { |attrs, _t, fields| [attrs["id"], fields] }
|
|
63
|
+
on("field") { |attrs, text, _| [attrs["name"], text] }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
ADAPTERS.each do |a|
|
|
67
|
+
begin
|
|
68
|
+
ctx = Moxml.new(a)
|
|
69
|
+
ctx.parse(xml)
|
|
70
|
+
rescue StandardError
|
|
71
|
+
next
|
|
72
|
+
end
|
|
73
|
+
out = deep.parse(xml, ctx)
|
|
74
|
+
expect(out[0]).to eq(
|
|
75
|
+
[["r0", [["f0", "v 0.0"], ["f1", "v 0.1"]]],
|
|
76
|
+
["r1", [["f0", "v 1.0"]]]],
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: moxml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.62
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -39,6 +39,7 @@ files:
|
|
|
39
39
|
- README.adoc
|
|
40
40
|
- Rakefile
|
|
41
41
|
- benchmark/pipeline_bench.rb
|
|
42
|
+
- benchmark/plan_bench.rb
|
|
42
43
|
- benchmarks/.gitignore
|
|
43
44
|
- benchmarks/generate_report.rb
|
|
44
45
|
- bin/console
|
|
@@ -488,6 +489,7 @@ files:
|
|
|
488
489
|
- spec/moxml/opal_oga_smoke_spec.rb
|
|
489
490
|
- spec/moxml/opal_rexml_adapter_spec.rb
|
|
490
491
|
- spec/moxml/opal_smoke_spec.rb
|
|
492
|
+
- spec/moxml/plan_conformance_spec.rb
|
|
491
493
|
- spec/moxml/plan_spec.rb
|
|
492
494
|
- spec/moxml/processing_instruction_spec.rb
|
|
493
495
|
- spec/moxml/readonly_parse_spec.rb
|