canon 0.3.57 → 0.3.58

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: 71a44b5ac36733a05ee0b762377f6ccaecd4ed3ae8a11527e3b067f21ded2db2
4
- data.tar.gz: 1054b2885a6cd55c479c78a0935b7d18fc790753f72bdc64ebd6854fa267aeff
3
+ metadata.gz: c1b3bba3210fd3ca95a66a4a3e439f6b9e1a0f95b30ddf4d90f4069a2b5a6d8b
4
+ data.tar.gz: fadf6bdf8fb892fbb3998d53754f599b17fac80b099936d77a7dae0881e4f5c5
5
5
  SHA512:
6
- metadata.gz: 87815f32fa049a8118764a77092e74fe23f6cd87203d67728c21d3c8ba9596f7d78e83e8201f1e8508b0ca79fb234b9e2b1c51cdb9dac27d1a8431ca7f7a7029
7
- data.tar.gz: 6d51c5547e43ff83a0e1e08ca9ab84a096a57f34c1c44c469343f9cd2ac31dfaa8b15609e7c5a09fd7496a33b62b39d5cd301fe58209831810b07c4a6a762366
6
+ metadata.gz: e551b02b98c802c3d2593c1f684c89d271b223892fb32dbd20f186fe6cb13e06d18bd079839298325eb1d8a798b962876af9c95177763268ae291fc503828552
7
+ data.tar.gz: 8485c2e7e3049386ff977fca9c4162b44d439a2c218067f3aefe4a3b596d0f351b60c0c18a7f9fd0d5bcbf77192a0525c84dac7c1b35fe7f92369737f6dc2308
@@ -106,50 +106,11 @@ module Canon
106
106
  if node.label.nil? || label_str.empty? || label_str == "#text" || label_str == "text"
107
107
  "#text"
108
108
  else
109
- component = node.label.to_s
110
-
111
- # Include sorted attributes to distinguish nodes with same label
112
- # but different attributes (while ignoring attribute order)
113
- # Only include attributes if requested (for hash matching)
114
- if @include_attributes && !node.attributes.empty?
115
- sorted_attrs = node.attributes.sort.to_h
116
- attrs_str = sorted_attrs.map { |k, v| "#{k}=#{v}" }.join(",")
117
- component += "{#{attrs_str}}"
118
- end
119
-
120
- # CRITICAL: For whitespace-sensitive HTML elements, include the text value
121
- # in the signature to prevent incorrect matching of nodes with different whitespace
122
- if @include_attributes && whitespace_sensitive?(node) && node.value
123
- # Include text value in signature for whitespace-sensitive elements
124
- # Use inspect to make whitespace visible and handle special characters
125
- component += "[text=#{node.value.inspect}]"
126
- end
127
-
128
- component
109
+ # Memoized on the node — see TreeNode#signature_component.
110
+ node.signature_component(include_attributes: @include_attributes)
129
111
  end
130
112
  end
131
113
 
132
- # Check if a node is in a whitespace-sensitive context
133
- #
134
- # HTML elements where whitespace is significant: <pre>, <code>, <textarea>, <script>, <style>
135
- #
136
- # @param node [TreeNode] Node to check
137
- # @return [Boolean] True if node is whitespace-sensitive
138
- def whitespace_sensitive?(node)
139
- return false unless node
140
-
141
- # List of HTML elements where whitespace is semantically significant
142
- whitespace_sensitive_tags = %w[pre code textarea script style]
143
-
144
- # Check if this node is whitespace-sensitive
145
- if node.is_a?(TreeNode)
146
- label = node.label.to_s.downcase
147
- return true if whitespace_sensitive_tags.include?(label)
148
- end
149
-
150
- false
151
- end
152
-
153
114
  # Compute signature string from path
154
115
  #
155
116
  # @return [String]
@@ -50,6 +50,22 @@ module Canon
50
50
  @weight = nil
51
51
  end
52
52
 
53
+ # Signature path component (see NodeSignature): the label plus
54
+ # sorted attributes (and whitespace-sensitive text value) when
55
+ # +include_attributes+. Memoized per variant — signatures
56
+ # rebuild ancestor components for every node they cover, which
57
+ # is quadratic over the tree without it.
58
+ #
59
+ # @param include_attributes [Boolean]
60
+ # @return [String]
61
+ def signature_component(include_attributes: true)
62
+ if include_attributes
63
+ @signature_component_attrs ||= build_signature_component(true)
64
+ else
65
+ @signature_component ||= build_signature_component(false)
66
+ end
67
+ end
68
+
53
69
  # Check if this is a leaf node (no children)
54
70
  #
55
71
  # @return [Boolean]
@@ -57,6 +73,30 @@ module Canon
57
73
  children.empty?
58
74
  end
59
75
 
76
+ # Elements where whitespace is semantically significant; their
77
+ # text value participates in the signature (see NodeSignature).
78
+ WHITESPACE_SENSITIVE_TAGS = %w[pre code textarea script style].freeze
79
+
80
+ def build_signature_component(include_attributes)
81
+ component = label.to_s
82
+
83
+ # Sorted attributes distinguish same-label nodes while
84
+ # ignoring attribute order.
85
+ if include_attributes && !attributes.empty?
86
+ component += "{#{attributes.sort.map { |k, v| "#{k}=#{v}" }.join(',')}}" # rubocop:disable Style/StringConcatenation
87
+ end
88
+
89
+ if include_attributes &&
90
+ WHITESPACE_SENSITIVE_TAGS.include?(label.to_s.downcase) && value
91
+ # inspect makes whitespace visible and handles special
92
+ # characters.
93
+ component += "[text=#{value.inspect}]"
94
+ end
95
+
96
+ component
97
+ end
98
+ private :build_signature_component
99
+
60
100
  # Check if this is a text node (leaf with value)
61
101
  #
62
102
  # @return [Boolean]
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.57"
4
+ VERSION = "0.3.58"
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.57
4
+ version: 0.3.58
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.