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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59a766120de370a517050c389b3ec809574e8e0f876b6a9b3ae351386cfc7333
|
|
4
|
+
data.tar.gz: 6a64cdc990d0d295645ec1f893e37da8b03858c06a2b3992d0e00926d04c939b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
-
|
|
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
|
|
124
|
-
|
|
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