canon 0.3.58 → 0.3.59

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: c1b3bba3210fd3ca95a66a4a3e439f6b9e1a0f95b30ddf4d90f4069a2b5a6d8b
4
- data.tar.gz: fadf6bdf8fb892fbb3998d53754f599b17fac80b099936d77a7dae0881e4f5c5
3
+ metadata.gz: 59a766120de370a517050c389b3ec809574e8e0f876b6a9b3ae351386cfc7333
4
+ data.tar.gz: 6a64cdc990d0d295645ec1f893e37da8b03858c06a2b3992d0e00926d04c939b
5
5
  SHA512:
6
- metadata.gz: e551b02b98c802c3d2593c1f684c89d271b223892fb32dbd20f186fe6cb13e06d18bd079839298325eb1d8a798b962876af9c95177763268ae291fc503828552
7
- data.tar.gz: 8485c2e7e3049386ff977fca9c4162b44d439a2c218067f3aefe4a3b596d0f351b60c0c18a7f9fd0d5bcbf77192a0525c84dac7c1b35fe7f92369737f6dc2308
6
+ metadata.gz: 0f659e6d2708dc675e2bc0df68eb57773ca16224083249e95a9906b1f7d967c92a917882f73a810490ca3b11c228afb9b581d1ceb80b0dc674d98d46014aba42
7
+ data.tar.gz: 974a7dfa4cdcacb21e76952c193160022ecd83de6887b4a5582c60d5853feb5c89a3e69be559ef36484c37a8f9228da1cad8a9168829d23b3e096d51d09fca6d
@@ -215,9 +215,10 @@ module Canon
215
215
 
216
216
  # Check prefix closure constraint
217
217
  # If ancestors are matched, they must be matched to each other
218
- node1.ancestors.each_with_index do |anc1, idx|
218
+ ancestors1 = node1.ancestors
219
+ anc2_ancestors = node2.ancestors
220
+ ancestors1.each_with_index do |anc1, idx|
219
221
  # Get corresponding ancestor in tree2
220
- anc2_ancestors = node2.ancestors
221
222
  return false if idx >= anc2_ancestors.size
222
223
 
223
224
  anc2 = anc2_ancestors[idx]
@@ -81,34 +81,7 @@ module Canon
81
81
  #
82
82
  # @return [Array<String>] Path components
83
83
  def compute_path
84
- # Build path from root to node
85
- ancestors = @node.ancestors.reverse
86
- components = ancestors.map do |ancestor|
87
- path_component(ancestor)
88
- end
89
-
90
- # Add the node itself
91
- components << path_component(@node)
92
-
93
- components
94
- end
95
-
96
- # Get path component for a node
97
- #
98
- # @param node [TreeNode] Node to get component for
99
- # @return [String]
100
- def path_component(node)
101
- # For element nodes: use label with sorted attributes
102
- # For text nodes: use "#text"
103
- # CRITICAL: Text nodes should use "#text" not "text"
104
- # Check the label - actual text nodes have no label or label == "text"
105
- label_str = node.label.to_s.downcase
106
- if node.label.nil? || label_str.empty? || label_str == "#text" || label_str == "text"
107
- "#text"
108
- else
109
- # Memoized on the node — see TreeNode#signature_component.
110
- node.signature_component(include_attributes: @include_attributes)
111
- end
84
+ @node.signature_path(include_attributes: @include_attributes)
112
85
  end
113
86
 
114
87
  # Compute signature string from path
@@ -66,6 +66,20 @@ module Canon
66
66
  end
67
67
  end
68
68
 
69
+ # Signature path components from root to this node, built by
70
+ # parent chaining (see NodeSignature). Memoized per variant —
71
+ # signatures previously re-walked the ancestor chain per node.
72
+ #
73
+ # @param include_attributes [Boolean]
74
+ # @return [Array<String>]
75
+ def signature_path(include_attributes: true)
76
+ if include_attributes
77
+ @signature_path_attrs ||= build_signature_path(true)
78
+ else
79
+ @signature_path ||= build_signature_path(false)
80
+ end
81
+ end
82
+
69
83
  # Check if this is a leaf node (no children)
70
84
  #
71
85
  # @return [Boolean]
@@ -77,7 +91,21 @@ module Canon
77
91
  # text value participates in the signature (see NodeSignature).
78
92
  WHITESPACE_SENSITIVE_TAGS = %w[pre code textarea script style].freeze
79
93
 
94
+ def build_signature_path(include_attributes)
95
+ component = signature_component(include_attributes: include_attributes)
96
+ if parent
97
+ parent.signature_path(include_attributes: include_attributes) + [component]
98
+ else
99
+ [component]
100
+ end
101
+ end
102
+
80
103
  def build_signature_component(include_attributes)
104
+ label_str = label.to_s.downcase
105
+ if label.nil? || label_str.empty? || label_str == "#text" || label_str == "text"
106
+ return "#text"
107
+ end
108
+
81
109
  component = label.to_s
82
110
 
83
111
  # Sorted attributes distinguish same-label nodes while
@@ -95,7 +123,7 @@ module Canon
95
123
 
96
124
  component
97
125
  end
98
- private :build_signature_component
126
+ private :build_signature_component, :build_signature_path
99
127
 
100
128
  # Check if this is a text node (leaf with value)
101
129
  #
@@ -118,11 +118,19 @@ module Canon
118
118
 
119
119
  def subtrees_match?(node1, node2)
120
120
  return false unless nodes_match?(node1, node2)
121
- return false unless node1.children.size == node2.children.size
122
121
 
123
- node1.children.zip(node2.children).all? do |child1, child2|
124
- subtrees_match?(child1, child2)
122
+ children1 = node1.children
123
+ children2 = node2.children
124
+ return false unless children1.size == children2.size
125
+
126
+ index = 0
127
+ while index < children1.size
128
+ return false unless subtrees_match?(children1[index],
129
+ children2[index])
130
+
131
+ index += 1
125
132
  end
133
+ true
126
134
  end
127
135
 
128
136
  def nodes_match?(node1, node2)
@@ -142,6 +150,11 @@ module Canon
142
150
  return true if (text1.nil? || text1.empty?) && (text2.nil? || text2.empty?)
143
151
  return false if (text1.nil? || text1.empty?) || (text2.nil? || text2.empty?)
144
152
 
153
+ # Identical raw text is equivalent under every mode — skips
154
+ # the gsub normalization for the overwhelmingly common
155
+ # matched-leaf case.
156
+ return true if text1 == text2
157
+
145
158
  norm1 = normalize_text(text1)
146
159
  norm2 = normalize_text(text2)
147
160
  return true if norm1.empty? && norm2.empty?
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.58"
4
+ VERSION = "0.3.59"
5
5
  end
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.58
4
+ version: 0.3.59
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.