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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d48fa5b4488a85c95b613bcab72881a5e286fdb9859da76aafc78553ff506419
4
- data.tar.gz: f0bd3b76b81a0181dc4ae801bed2288828f8d8bc85a6414a98c993d10d770b7a
3
+ metadata.gz: 133da0e86ad37cf095f738d15a37ebcc3b35ae92240327d459ed1d1bbedc3a5b
4
+ data.tar.gz: 6c7c2cf6e60712058a6f49f28cf9181316f9e410da5a3982b72fee7fdebde115
5
5
  SHA512:
6
- metadata.gz: 1b32e0477c8932748179074f076478747d3eb1bce3892e6d7fd8ecae3e1dc7e686fa51907cdbd6444ad87267eb9521206b4caaa6f2d85a93b36f5cc2b3758e4a
7
- data.tar.gz: 11c89d97b5144a557746e7d84e9128db443e8951fc40381486da826935f012ccc15249de122232a0ca95b32b5c32ebffe64a2415b6db8f8b9790af2e1eda1b10
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 an enriched DiffNode.
14
- def self.build(node1:, node2:, diff1:, diff2:, dimension:, **_opts)
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, _opts,
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:, **opts)
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
- **opts,
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
- diff_node = Canon::Comparison::DiffNodeBuilder.build(
302
- node1: n1,
303
- node2: n2,
304
- diff1: Comparison::UNEQUAL_ELEMENTS,
305
- diff2: Comparison::UNEQUAL_ELEMENTS,
306
- dimension: :namespace_uri,
307
- )
308
- differences << diff_node if opts[:verbose]
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
 
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canon
4
- VERSION = "0.3.15"
4
+ VERSION = "0.3.16"
5
5
  end
@@ -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
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.15
4
+ version: 0.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.