canon 0.3.15 → 0.3.16
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/lib/canon/comparison/diff_node_builder.rb +13 -2
- data/lib/canon/comparison/html_comparator.rb +4 -2
- data/lib/canon/comparison/markup_comparator.rb +15 -2
- data/lib/canon/comparison/xml_comparator/attribute_comparator.rb +2 -2
- data/lib/canon/comparison/xml_comparator.rb +12 -8
- data/lib/canon/diff/diff_node.rb +1 -1
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/sax_builder.rb +37 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 133da0e86ad37cf095f738d15a37ebcc3b35ae92240327d459ed1d1bbedc3a5b
|
|
4
|
+
data.tar.gz: 6c7c2cf6e60712058a6f49f28cf9181316f9e410da5a3982b72fee7fdebde115
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd39028ce4e945d04ac83d44f9a0da8b516dadf8a454bb634147aabfa480f896ed25f7cf048b39d6b0173a6a1b6aab2881a607b6e8588ff124d4616f95fb944c
|
|
7
|
+
data.tar.gz: 20eedf19bb73922d482537bfe8411bf8b8816001a4df6d59130f08558d80e14d2bfd968c9029d176cae056b0a4d9b1c36d16fb4012329073cceb490846462f7a
|
|
@@ -10,10 +10,21 @@ module Canon
|
|
|
10
10
|
# attributes), and whitespace visualization — previously duplicated
|
|
11
11
|
# across MarkupComparator and XmlComparator.
|
|
12
12
|
class DiffNodeBuilder
|
|
13
|
-
# Build
|
|
14
|
-
|
|
13
|
+
# Build a DiffNode. Verbose callers get the fully enriched form —
|
|
14
|
+
# reason, path, serialized content, attributes; non-verbose
|
|
15
|
+
# callers only ever ask normative?, and DiffClassifier reads node
|
|
16
|
+
# refs and dimension alone, so reason building and metadata
|
|
17
|
+
# enrichment (five display operations per difference) are
|
|
18
|
+
# skipped entirely.
|
|
19
|
+
def self.build(node1:, node2:, diff1:, diff2:, dimension:,
|
|
20
|
+
verbose: false, **_opts)
|
|
15
21
|
raise ArgumentError, "dimension required for DiffNode" if dimension.nil?
|
|
16
22
|
|
|
23
|
+
unless verbose
|
|
24
|
+
return Canon::Diff::DiffNode.new(node1: node1, node2: node2,
|
|
25
|
+
dimension: dimension)
|
|
26
|
+
end
|
|
27
|
+
|
|
17
28
|
reason = build_reason(node1, node2, diff1, diff2, dimension)
|
|
18
29
|
metadata = enrich_metadata(node1, node2)
|
|
19
30
|
|
|
@@ -198,7 +198,7 @@ module Canon
|
|
|
198
198
|
|
|
199
199
|
return Comparison::EQUIVALENT if children1.empty? && children2.empty?
|
|
200
200
|
|
|
201
|
-
emitter = html_diff_emitter(differences)
|
|
201
|
+
emitter = html_diff_emitter(differences, opts)
|
|
202
202
|
ChildRealignment.walk(children1, children2, emitter,
|
|
203
203
|
emit_structural_orphans: true) do |c1, c2|
|
|
204
204
|
XmlNodeComparison.compare_nodes(c1, c2, opts, child_opts,
|
|
@@ -208,10 +208,12 @@ module Canon
|
|
|
208
208
|
|
|
209
209
|
# Build a diff emitter for the HTML comparator path that
|
|
210
210
|
# creates DiffNode objects via DiffNodeBuilder.
|
|
211
|
-
def html_diff_emitter(differences)
|
|
211
|
+
def html_diff_emitter(differences, opts)
|
|
212
|
+
verbose = opts[:verbose]
|
|
212
213
|
proc do |n1, n2, d1, d2, dim|
|
|
213
214
|
differences << Canon::Comparison::DiffNodeBuilder.build(
|
|
214
215
|
node1: n1, node2: n2, diff1: d1, diff2: d2, dimension: dim,
|
|
216
|
+
verbose: verbose
|
|
215
217
|
)
|
|
216
218
|
end
|
|
217
219
|
end
|
|
@@ -16,11 +16,11 @@ module Canon
|
|
|
16
16
|
#
|
|
17
17
|
# Delegates to DiffNodeBuilder, the single DiffNode factory for
|
|
18
18
|
# the DOM comparison path.
|
|
19
|
-
def add_difference(node1, node2, diff1, diff2, dimension,
|
|
19
|
+
def add_difference(node1, node2, diff1, diff2, dimension, opts,
|
|
20
20
|
differences)
|
|
21
21
|
differences << Canon::Comparison::DiffNodeBuilder.build(
|
|
22
22
|
node1: node1, node2: node2, diff1: diff1, diff2: diff2,
|
|
23
|
-
dimension: dimension
|
|
23
|
+
dimension: dimension, verbose: opts[:verbose]
|
|
24
24
|
)
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -53,6 +53,19 @@ module Canon
|
|
|
53
53
|
# @param opts [Hash] Comparison options
|
|
54
54
|
# @return [Array] Filtered array of children
|
|
55
55
|
def filter_children(children, opts)
|
|
56
|
+
# Fast path: with no ignore_nodes list, only text/comment
|
|
57
|
+
# children can ever be excluded (node_excluded? returns false
|
|
58
|
+
# for every other kind) — an all-element child list passes
|
|
59
|
+
# through untouched, with no reject copy and no per-child
|
|
60
|
+
# exclusion checks.
|
|
61
|
+
ignore_nodes = opts[:ignore_nodes]
|
|
62
|
+
if (ignore_nodes.nil? || ignore_nodes.empty?) && !children.empty?
|
|
63
|
+
excludable = children.any? do |child|
|
|
64
|
+
text_node?(child) || comment_node?(child)
|
|
65
|
+
end
|
|
66
|
+
return children unless excludable
|
|
67
|
+
end
|
|
68
|
+
|
|
56
69
|
children.reject do |child|
|
|
57
70
|
node_excluded?(child, opts)
|
|
58
71
|
end
|
|
@@ -165,14 +165,14 @@ differences)
|
|
|
165
165
|
# @param opts [Hash] Options
|
|
166
166
|
# @param differences [Array] Array to append difference to
|
|
167
167
|
def self.add_attribute_difference(n1:, n2:, diff1:, diff2:,
|
|
168
|
-
dimension:, differences:,
|
|
168
|
+
dimension:, differences:, opts: {})
|
|
169
169
|
diff_node = Canon::Comparison::DiffNodeBuilder.build(
|
|
170
170
|
node1: n1,
|
|
171
171
|
node2: n2,
|
|
172
172
|
diff1: diff1,
|
|
173
173
|
diff2: diff2,
|
|
174
174
|
dimension: dimension,
|
|
175
|
-
|
|
175
|
+
verbose: opts[:verbose],
|
|
176
176
|
)
|
|
177
177
|
differences << diff_node if diff_node
|
|
178
178
|
end
|
|
@@ -298,14 +298,18 @@ module Canon
|
|
|
298
298
|
ns2 = Canon::XmlParsing.namespace_uri(n2)
|
|
299
299
|
|
|
300
300
|
unless ns1 == ns2
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
301
|
+
# The DiffNode is only ever appended in verbose mode — skip
|
|
302
|
+
# building it entirely otherwise.
|
|
303
|
+
if opts[:verbose]
|
|
304
|
+
differences << Canon::Comparison::DiffNodeBuilder.build(
|
|
305
|
+
node1: n1,
|
|
306
|
+
node2: n2,
|
|
307
|
+
diff1: Comparison::UNEQUAL_ELEMENTS,
|
|
308
|
+
diff2: Comparison::UNEQUAL_ELEMENTS,
|
|
309
|
+
dimension: :namespace_uri,
|
|
310
|
+
verbose: true,
|
|
311
|
+
)
|
|
312
|
+
end
|
|
309
313
|
return Comparison::UNEQUAL_ELEMENTS
|
|
310
314
|
end
|
|
311
315
|
|
data/lib/canon/diff/diff_node.rb
CHANGED
|
@@ -34,7 +34,7 @@ module Canon
|
|
|
34
34
|
# @param serialized_after [String, nil] Optional serialized content for display
|
|
35
35
|
# @param attributes_before [Hash, nil] Optional normalized attributes hash
|
|
36
36
|
# @param attributes_after [Hash, nil] Optional normalized attributes hash
|
|
37
|
-
def initialize(node1:, node2:, dimension:, reason
|
|
37
|
+
def initialize(node1:, node2:, dimension:, reason: nil,
|
|
38
38
|
path: nil, serialized_before: nil, serialized_after: nil,
|
|
39
39
|
attributes_before: nil, attributes_after: nil)
|
|
40
40
|
@node1 = node1
|
data/lib/canon/version.rb
CHANGED
|
@@ -22,6 +22,10 @@ module Canon
|
|
|
22
22
|
# root = SaxBuilder.parse(xml_string, strip_doctype: true)
|
|
23
23
|
#
|
|
24
24
|
class SaxBuilder
|
|
25
|
+
# Shared empties for the no-declaration common case: both
|
|
26
|
+
# consumers only iterate them.
|
|
27
|
+
NO_NAMESPACE_DECLS = [].freeze
|
|
28
|
+
EMPTY_NS_HASH = {}.freeze
|
|
25
29
|
# Parse XML string and return Canon::Xml::Node tree
|
|
26
30
|
#
|
|
27
31
|
# @param xml_string [String] XML content to parse
|
|
@@ -110,6 +114,31 @@ strip_doctype: false)
|
|
|
110
114
|
def start_element(name, attrs = [])
|
|
111
115
|
parent = @stack.last
|
|
112
116
|
|
|
117
|
+
# Fast path: attribute-less elements (the bulk of most
|
|
118
|
+
# documents) declare no namespaces — no separation, no hash,
|
|
119
|
+
# no qname pair array; the inherited scope object is pushed
|
|
120
|
+
# as-is (shared scope → cached namespace-node array).
|
|
121
|
+
if attrs.empty?
|
|
122
|
+
if (colon = name.index(":"))
|
|
123
|
+
prefix = name[0...colon]
|
|
124
|
+
local_name = name[(colon + 1)..]
|
|
125
|
+
else
|
|
126
|
+
prefix = nil
|
|
127
|
+
local_name = name
|
|
128
|
+
end
|
|
129
|
+
new_scope = @namespace_stack.last
|
|
130
|
+
@namespace_stack.push(new_scope)
|
|
131
|
+
element = TreeBuilder::DEFAULT.element(
|
|
132
|
+
name: local_name,
|
|
133
|
+
prefix: prefix,
|
|
134
|
+
namespace_uri: new_scope[prefix.to_s],
|
|
135
|
+
namespace_scope: new_scope,
|
|
136
|
+
)
|
|
137
|
+
parent.add_child(element)
|
|
138
|
+
@stack.push(element)
|
|
139
|
+
return
|
|
140
|
+
end
|
|
141
|
+
|
|
113
142
|
# Parse namespace from name (prefix:localname or just localname)
|
|
114
143
|
prefix, local_name = parse_qname(name)
|
|
115
144
|
|
|
@@ -280,6 +309,8 @@ strip_doctype: false)
|
|
|
280
309
|
# @param ns_decls [Array] Array of [name, value] pairs for namespace declarations
|
|
281
310
|
# @return [Hash] Namespace prefix => URI mapping
|
|
282
311
|
def build_ns_hash(ns_decls)
|
|
312
|
+
return EMPTY_NS_HASH if ns_decls.empty?
|
|
313
|
+
|
|
283
314
|
result = {}
|
|
284
315
|
ns_decls.each do |name, uri|
|
|
285
316
|
# xmlns="..." for default namespace, xmlns:prefix="..." for prefixed
|
|
@@ -311,6 +342,12 @@ strip_doctype: false)
|
|
|
311
342
|
# @param attrs [Array] Array of [name, value] pairs
|
|
312
343
|
# @return [Array] Two arrays: [namespace_decls, regular_attrs]
|
|
313
344
|
def separate_namespaces(attrs)
|
|
345
|
+
# Fast path: no xmlns declarations — the attribute pairs pass
|
|
346
|
+
# through untouched and nothing is copied.
|
|
347
|
+
unless attrs.any? { |name, _| name == "xmlns" || name.start_with?("xmlns:") }
|
|
348
|
+
return [NO_NAMESPACE_DECLS, attrs]
|
|
349
|
+
end
|
|
350
|
+
|
|
314
351
|
ns_decls = []
|
|
315
352
|
regular_attrs = []
|
|
316
353
|
|