canon 0.1.14 → 0.1.15
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/color_detector.rb +3 -3
- data/lib/canon/comparison/comparison_result.rb +1 -3
- data/lib/canon/comparison/dimensions/attribute_order_dimension.rb +1 -1
- data/lib/canon/comparison/dimensions/attribute_presence_dimension.rb +1 -1
- data/lib/canon/comparison/dimensions/comments_dimension.rb +2 -2
- data/lib/canon/comparison/dimensions/element_position_dimension.rb +1 -1
- data/lib/canon/comparison/dimensions/registry.rb +1 -1
- data/lib/canon/comparison/dimensions/structural_whitespace_dimension.rb +2 -2
- data/lib/canon/comparison/dimensions/text_content_dimension.rb +2 -2
- data/lib/canon/comparison/format_detector.rb +1 -1
- data/lib/canon/comparison/html_comparator.rb +2 -6
- data/lib/canon/comparison/markup_comparator.rb +7 -7
- data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +3 -3
- data/lib/canon/comparison/xml_comparator/child_comparison.rb +2 -2
- data/lib/canon/comparison/xml_comparator/node_parser.rb +1 -1
- data/lib/canon/comparison/xml_comparator.rb +4 -8
- data/lib/canon/comparison/xml_node_comparison.rb +3 -3
- data/lib/canon/comparison.rb +1 -1
- data/lib/canon/config/env_provider.rb +3 -3
- data/lib/canon/diff/diff_block_builder.rb +2 -2
- data/lib/canon/diff/diff_context_builder.rb +1 -1
- data/lib/canon/diff/diff_node_mapper.rb +1 -1
- data/lib/canon/diff_formatter/by_line/base_formatter.rb +2 -2
- data/lib/canon/diff_formatter/by_line/html_formatter.rb +2 -2
- data/lib/canon/diff_formatter/by_line/xml_formatter.rb +2 -2
- data/lib/canon/diff_formatter/by_object/base_formatter.rb +1 -1
- data/lib/canon/diff_formatter/by_object/json_formatter.rb +3 -1
- data/lib/canon/diff_formatter/by_object/xml_formatter.rb +1 -1
- data/lib/canon/diff_formatter/debug_output.rb +4 -6
- data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +1 -1
- data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +7 -0
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +6 -0
- data/lib/canon/diff_formatter.rb +5 -5
- data/lib/canon/errors.rb +3 -3
- data/lib/canon/rspec_matchers.rb +2 -2
- data/lib/canon/tree_diff/adapters/json_adapter.rb +2 -6
- data/lib/canon/tree_diff/adapters/yaml_adapter.rb +2 -6
- data/lib/canon/tree_diff/core/matching.rb +2 -2
- data/lib/canon/tree_diff/core/node_signature.rb +2 -4
- data/lib/canon/tree_diff/core/tree_node.rb +1 -1
- data/lib/canon/tree_diff/operation_converter.rb +1 -1
- data/lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb +1 -1
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/line_range_mapper.rb +1 -1
- data/lib/canon/xml/nodes/attribute_node.rb +4 -0
- data/lib/canon/xml/nodes/element_node.rb +4 -0
- data/lib/canon/xml/nodes/namespace_node.rb +4 -0
- data/lib/canon/xml/nodes/processing_instruction_node.rb +4 -0
- data/lib/canon.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '04860609f8d3300ccebf84a0f2208510600dcfaac4b3f54f698eb2de7eed0493'
|
|
4
|
+
data.tar.gz: fc50abe2a915d7d7ff1cd630c0a5a50849b6fd5780664cb6bb419300b2388743
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1bcc3ad7439fdd7f65627c53cd0dc4b92d781bdbdaf330d2bb8ecc89b3319a4fc02e78de8e961cdb69854661881db39bf59c664210c7a59b7a011355b1db71b
|
|
7
|
+
data.tar.gz: cca1b3f2eee48054b5431118350e64acb46f485096cd8c88798e0935210985d63eb93de4727a42d17cfaad8ef03c55e7d1745922500f3a3495a791d86fd60676
|
data/lib/canon/color_detector.rb
CHANGED
|
@@ -82,7 +82,7 @@ module Canon
|
|
|
82
82
|
# @return [Boolean] true if colors appear to be supported
|
|
83
83
|
def detect_from_env
|
|
84
84
|
# Check TERM variable
|
|
85
|
-
term = ENV
|
|
85
|
+
term = ENV.fetch("TERM", nil)
|
|
86
86
|
if term && NO_COLOR_TERMS.any? { |t| term.include?(t) }
|
|
87
87
|
# Known no-color terminals
|
|
88
88
|
return false
|
|
@@ -100,7 +100,7 @@ module Canon
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
# Check for known color-capable terminals
|
|
103
|
-
colorterm = ENV
|
|
103
|
+
colorterm = ENV.fetch("COLORTERM", nil)
|
|
104
104
|
return true if COLOR_TERM_VALUES.include?(colorterm)
|
|
105
105
|
|
|
106
106
|
# Default: assume colors are supported on modern terminals
|
|
@@ -125,7 +125,7 @@ module Canon
|
|
|
125
125
|
# - Generic CI: check for specific TeamCity/Terminal variables
|
|
126
126
|
#
|
|
127
127
|
# @return [Boolean] true if CI environment likely supports colors
|
|
128
|
-
def detect_ci_colors
|
|
128
|
+
def detect_ci_colors # rubocop:disable Naming/PredicateMethod
|
|
129
129
|
# Most modern CI systems support ANSI colors
|
|
130
130
|
# Only disable for explicitly known non-color CI
|
|
131
131
|
return false if ENV["TERM"] == "dumb"
|
|
@@ -44,10 +44,8 @@ html_version: nil, match_options: nil, algorithm: :dom, original_strings: nil)
|
|
|
44
44
|
if diff.is_a?(Canon::Diff::DiffNode)
|
|
45
45
|
diff.normative?
|
|
46
46
|
# Legacy Hash format - always considered normative (structural differences)
|
|
47
|
-
elsif diff.is_a?(Hash)
|
|
48
|
-
true
|
|
49
47
|
else
|
|
50
|
-
|
|
48
|
+
diff.is_a?(Hash)
|
|
51
49
|
end
|
|
52
50
|
end
|
|
53
51
|
end
|
|
@@ -37,7 +37,7 @@ module Canon
|
|
|
37
37
|
# @param order1 [Array<Symbol>] First attribute order
|
|
38
38
|
# @param order2 [Array<Symbol>] Second attribute order
|
|
39
39
|
# @return [Boolean] true if attribute order is exactly the same
|
|
40
|
-
def compare_strict(order1, order2)
|
|
40
|
+
def compare_strict(order1, order2) # rubocop:disable Naming/PredicateMethod
|
|
41
41
|
order1 == order2
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -37,7 +37,7 @@ module Canon
|
|
|
37
37
|
# @param names1 [Array<Symbol>] First attribute names
|
|
38
38
|
# @param names2 [Array<Symbol>] Second attribute names
|
|
39
39
|
# @return [Boolean] true if attribute names are exactly equal
|
|
40
|
-
def compare_strict(names1, names2)
|
|
40
|
+
def compare_strict(names1, names2) # rubocop:disable Naming/PredicateMethod
|
|
41
41
|
names1.sort == names2.sort
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -37,7 +37,7 @@ module Canon
|
|
|
37
37
|
# @param comments1 [Array<String>] First comments array
|
|
38
38
|
# @param comments2 [Array<String>] Second comments array
|
|
39
39
|
# @return [Boolean] true if comments are exactly equal
|
|
40
|
-
def compare_strict(comments1, comments2)
|
|
40
|
+
def compare_strict(comments1, comments2) # rubocop:disable Naming/PredicateMethod
|
|
41
41
|
comments1 == comments2
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -48,7 +48,7 @@ module Canon
|
|
|
48
48
|
# @param comments1 [Array<String>] First comments array
|
|
49
49
|
# @param comments2 [Array<String>] Second comments array
|
|
50
50
|
# @return [Boolean] true if normalized comments are equal
|
|
51
|
-
def compare_normalize(comments1, comments2)
|
|
51
|
+
def compare_normalize(comments1, comments2) # rubocop:disable Naming/PredicateMethod
|
|
52
52
|
normalize_comments(comments1) == normalize_comments(comments2)
|
|
53
53
|
end
|
|
54
54
|
|
|
@@ -39,7 +39,7 @@ module Canon
|
|
|
39
39
|
# @param pos1 [Integer] First position
|
|
40
40
|
# @param pos2 [Integer] Second position
|
|
41
41
|
# @return [Boolean] true if positions are equal
|
|
42
|
-
def compare_strict(pos1, pos2)
|
|
42
|
+
def compare_strict(pos1, pos2) # rubocop:disable Naming/PredicateMethod
|
|
43
43
|
pos1 == pos2
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -67,7 +67,7 @@ module Canon
|
|
|
67
67
|
# @param node2 [Object] Second node
|
|
68
68
|
# @param behavior [Symbol] Comparison behavior
|
|
69
69
|
# @return [Boolean] true if nodes match for this dimension
|
|
70
|
-
def self.compare(dimension_name, node1, node2, behavior)
|
|
70
|
+
def self.compare(dimension_name, node1, node2, behavior) # rubocop:disable Naming/PredicateMethod
|
|
71
71
|
dimension = get(dimension_name)
|
|
72
72
|
dimension.equivalent?(node1, node2, behavior)
|
|
73
73
|
end
|
|
@@ -41,7 +41,7 @@ module Canon
|
|
|
41
41
|
# @param ws1 [Array<String>] First whitespace array
|
|
42
42
|
# @param ws2 [Array<String>] Second whitespace array
|
|
43
43
|
# @return [Boolean] true if structural whitespace is exactly equal
|
|
44
|
-
def compare_strict(ws1, ws2)
|
|
44
|
+
def compare_strict(ws1, ws2) # rubocop:disable Naming/PredicateMethod
|
|
45
45
|
ws1 == ws2
|
|
46
46
|
end
|
|
47
47
|
|
|
@@ -52,7 +52,7 @@ module Canon
|
|
|
52
52
|
# @param ws1 [Array<String>] First whitespace array
|
|
53
53
|
# @param ws2 [Array<String>] Second whitespace array
|
|
54
54
|
# @return [Boolean] true if normalized structural whitespace is equal
|
|
55
|
-
def compare_normalize(ws1, ws2)
|
|
55
|
+
def compare_normalize(ws1, ws2) # rubocop:disable Naming/PredicateMethod
|
|
56
56
|
normalize_whitespace(ws1) == normalize_whitespace(ws2)
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -37,7 +37,7 @@ module Canon
|
|
|
37
37
|
# @param text1 [String, nil] First text
|
|
38
38
|
# @param text2 [String, nil] Second text
|
|
39
39
|
# @return [Boolean] true if texts are exactly equal
|
|
40
|
-
def compare_strict(text1, text2)
|
|
40
|
+
def compare_strict(text1, text2) # rubocop:disable Naming/PredicateMethod
|
|
41
41
|
text1.to_s == text2.to_s
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -49,7 +49,7 @@ module Canon
|
|
|
49
49
|
# @param text1 [String, nil] First text
|
|
50
50
|
# @param text2 [String, nil] Second text
|
|
51
51
|
# @return [Boolean] true if normalized texts are equal
|
|
52
|
-
def compare_normalize(text1, text2)
|
|
52
|
+
def compare_normalize(text1, text2) # rubocop:disable Naming/PredicateMethod
|
|
53
53
|
normalized1 = normalize_text(text1)
|
|
54
54
|
normalized2 = normalize_text(text2)
|
|
55
55
|
|
|
@@ -52,7 +52,7 @@ module Canon
|
|
|
52
52
|
# @return [Symbol] Format type
|
|
53
53
|
def detect_string(str)
|
|
54
54
|
# Use cache for format detection
|
|
55
|
-
Cache.fetch(:format_detect, Cache.key_for_format_detection(str)) do
|
|
55
|
+
Cache.fetch(:format_detect, Cache.key_for_format_detection(str)) do # rubocop:disable Lint/UselessDefaultValueArgument
|
|
56
56
|
detect_string_uncached(str)
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -134,9 +134,7 @@ module Canon
|
|
|
134
134
|
# Classify DiffNodes as normative/informative if we have verbose output
|
|
135
135
|
if opts[:verbose] && !differences.empty?
|
|
136
136
|
classifier = Canon::Diff::DiffClassifier.new(match_opts)
|
|
137
|
-
classifier.classify_all(differences.
|
|
138
|
-
d.is_a?(Canon::Diff::DiffNode)
|
|
139
|
-
end)
|
|
137
|
+
classifier.classify_all(differences.grep(Canon::Diff::DiffNode))
|
|
140
138
|
end
|
|
141
139
|
|
|
142
140
|
if opts[:verbose]
|
|
@@ -153,9 +151,7 @@ module Canon
|
|
|
153
151
|
# Non-verbose mode: check equivalence
|
|
154
152
|
# If comparison found differences, classify them to determine if normative
|
|
155
153
|
classifier = Canon::Diff::DiffClassifier.new(match_opts)
|
|
156
|
-
classifier.classify_all(differences.
|
|
157
|
-
d.is_a?(Canon::Diff::DiffNode)
|
|
158
|
-
end)
|
|
154
|
+
classifier.classify_all(differences.grep(Canon::Diff::DiffNode))
|
|
159
155
|
# Equivalent if no normative differences (matches semantic algorithm)
|
|
160
156
|
differences.none?(&:normative?)
|
|
161
157
|
else
|
|
@@ -116,13 +116,13 @@ module Canon
|
|
|
116
116
|
|
|
117
117
|
# Canon::Xml::Node ElementNode
|
|
118
118
|
if node.is_a?(Canon::Xml::Nodes::ElementNode)
|
|
119
|
-
node.attribute_nodes.
|
|
120
|
-
|
|
119
|
+
node.attribute_nodes.to_h do |attr|
|
|
120
|
+
[attr.name, attr.value]
|
|
121
121
|
end
|
|
122
122
|
# Nokogiri nodes
|
|
123
123
|
elsif node.respond_to?(:attributes)
|
|
124
|
-
node.attributes.
|
|
125
|
-
|
|
124
|
+
node.attributes.to_h do |_, attr|
|
|
125
|
+
[attr.name, attr.value]
|
|
126
126
|
end
|
|
127
127
|
else
|
|
128
128
|
{}
|
|
@@ -231,9 +231,9 @@ module Canon
|
|
|
231
231
|
# @param node [Object] Node to check
|
|
232
232
|
# @return [Boolean] true if node is a text node
|
|
233
233
|
def text_node?(node)
|
|
234
|
-
node.respond_to?(:text?) && node.text? &&
|
|
235
|
-
!node.respond_to?(:element?) ||
|
|
236
|
-
node.respond_to?(:node_type) && node.node_type == :text
|
|
234
|
+
(node.respond_to?(:text?) && node.text? &&
|
|
235
|
+
!node.respond_to?(:element?)) ||
|
|
236
|
+
(node.respond_to?(:node_type) && node.node_type == :text)
|
|
237
237
|
end
|
|
238
238
|
|
|
239
239
|
# Get text content from a node
|
|
@@ -146,8 +146,8 @@ module Canon
|
|
|
146
146
|
# MUST match DOM diff preprocessing EXACTLY (xml_comparator.rb:106-109)
|
|
147
147
|
# Simple pattern: add newline between adjacent tags
|
|
148
148
|
[
|
|
149
|
-
xml1.gsub(
|
|
150
|
-
xml2.gsub(
|
|
149
|
+
xml1.gsub("><", ">\n<"),
|
|
150
|
+
xml2.gsub("><", ">\n<"),
|
|
151
151
|
]
|
|
152
152
|
end
|
|
153
153
|
|
|
@@ -185,7 +185,7 @@ module Canon
|
|
|
185
185
|
|
|
186
186
|
# KEY FIX: Use simple gsub, NOT Canon.format
|
|
187
187
|
# This ensures proper line-by-line display matching DOM diff format
|
|
188
|
-
[html1.gsub(
|
|
188
|
+
[html1.gsub("><", ">\n<"), html2.gsub("><", ">\n<")]
|
|
189
189
|
end
|
|
190
190
|
|
|
191
191
|
# Preprocess JSON documents
|
|
@@ -241,9 +241,9 @@ diff_children, differences)
|
|
|
241
241
|
smaller_set = children2
|
|
242
242
|
end
|
|
243
243
|
|
|
244
|
-
smaller_set_names = smaller_set.
|
|
244
|
+
smaller_set_names = smaller_set.filter_map do |c|
|
|
245
245
|
c.respond_to?(:name) ? c.name : nil
|
|
246
|
-
end
|
|
246
|
+
end
|
|
247
247
|
|
|
248
248
|
new_larger_set = []
|
|
249
249
|
max_len = larger_set.length
|
|
@@ -26,7 +26,7 @@ module Canon
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# Apply preprocessing to XML string before parsing
|
|
29
|
-
xml_string = apply_preprocessing(node, preprocessing)
|
|
29
|
+
xml_string = apply_preprocessing(node, preprocessing).strip
|
|
30
30
|
|
|
31
31
|
# Use Canon::Xml::DataModel for parsing to get Canon::Xml::Node instances
|
|
32
32
|
Canon::Xml::DataModel.from_xml(xml_string,
|
|
@@ -123,17 +123,15 @@ module Canon
|
|
|
123
123
|
# Classify DiffNodes as normative/informative if we have verbose output
|
|
124
124
|
if opts[:verbose] && !differences.empty?
|
|
125
125
|
classifier = Canon::Diff::DiffClassifier.new(match_opts)
|
|
126
|
-
classifier.classify_all(differences.
|
|
127
|
-
d.is_a?(Canon::Diff::DiffNode)
|
|
128
|
-
end)
|
|
126
|
+
classifier.classify_all(differences.grep(Canon::Diff::DiffNode))
|
|
129
127
|
end
|
|
130
128
|
|
|
131
129
|
if opts[:verbose]
|
|
132
130
|
# Serialize parsed nodes for consistent formatting
|
|
133
131
|
# This ensures both sides formatted identically, showing only real differences
|
|
134
132
|
preprocessed = [
|
|
135
|
-
serialize_node(node1).gsub(
|
|
136
|
-
serialize_node(node2).gsub(
|
|
133
|
+
serialize_node(node1).gsub("><", ">\n<"),
|
|
134
|
+
serialize_node(node2).gsub("><", ">\n<"),
|
|
137
135
|
]
|
|
138
136
|
|
|
139
137
|
ComparisonResult.new(
|
|
@@ -148,9 +146,7 @@ module Canon
|
|
|
148
146
|
# Non-verbose mode: check equivalence
|
|
149
147
|
# If comparison found differences, classify them to determine if normative
|
|
150
148
|
classifier = Canon::Diff::DiffClassifier.new(match_opts)
|
|
151
|
-
classifier.classify_all(differences.
|
|
152
|
-
d.is_a?(Canon::Diff::DiffNode)
|
|
153
|
-
end)
|
|
149
|
+
classifier.classify_all(differences.grep(Canon::Diff::DiffNode))
|
|
154
150
|
# Equivalent if no normative differences (matches semantic algorithm)
|
|
155
151
|
differences.none?(&:normative?)
|
|
156
152
|
else
|
|
@@ -281,9 +281,9 @@ diff_children, differences)
|
|
|
281
281
|
# @param node [Object] Node to check
|
|
282
282
|
# @return [Boolean] true if node is a text node
|
|
283
283
|
def self.text_node?(node)
|
|
284
|
-
node.respond_to?(:text?) && node.text? &&
|
|
285
|
-
!node.respond_to?(:element?) ||
|
|
286
|
-
node.respond_to?(:node_type) && node.node_type == :text
|
|
284
|
+
(node.respond_to?(:text?) && node.text? &&
|
|
285
|
+
!node.respond_to?(:element?)) ||
|
|
286
|
+
(node.respond_to?(:node_type) && node.node_type == :text)
|
|
287
287
|
end
|
|
288
288
|
|
|
289
289
|
# Extract text content from a node
|
data/lib/canon/comparison.rb
CHANGED
|
@@ -495,7 +495,7 @@ module Canon
|
|
|
495
495
|
|
|
496
496
|
# Use cache for string documents
|
|
497
497
|
Cache.fetch(:document_parse,
|
|
498
|
-
Cache.key_for_document(doc, format, preprocessing)) do
|
|
498
|
+
Cache.key_for_document(doc, format, preprocessing)) do # rubocop:disable Lint/UselessDefaultValueArgument
|
|
499
499
|
yield doc
|
|
500
500
|
end
|
|
501
501
|
end
|
|
@@ -37,12 +37,12 @@ module Canon
|
|
|
37
37
|
attributes.each do |attr|
|
|
38
38
|
# Try format-specific ENV var first
|
|
39
39
|
env_key = EnvSchema.env_key(format, config_type, attr)
|
|
40
|
-
value = ENV
|
|
40
|
+
value = ENV.fetch(env_key, nil)
|
|
41
41
|
|
|
42
42
|
# Fall back to global ENV var if format-specific not set
|
|
43
43
|
if value.nil?
|
|
44
44
|
global_key = EnvSchema.global_env_key(attr)
|
|
45
|
-
value = ENV
|
|
45
|
+
value = ENV.fetch(global_key, nil)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# Convert and store if value exists
|
|
@@ -57,7 +57,7 @@ module Canon
|
|
|
57
57
|
result = {}
|
|
58
58
|
attributes.each do |attr|
|
|
59
59
|
global_key = EnvSchema.global_env_key(attr)
|
|
60
|
-
value = ENV
|
|
60
|
+
value = ENV.fetch(global_key, nil)
|
|
61
61
|
|
|
62
62
|
if value
|
|
63
63
|
result[attr] = TypeConverter.convert(attr, value)
|
|
@@ -66,13 +66,13 @@ module Canon
|
|
|
66
66
|
# Create a DiffBlock from lines
|
|
67
67
|
def create_block(start_idx, end_idx, diff_lines)
|
|
68
68
|
# Determine types from diff_lines
|
|
69
|
-
types = diff_lines.map(&:type).uniq.
|
|
69
|
+
types = diff_lines.map(&:type).uniq.filter_map do |t|
|
|
70
70
|
case t
|
|
71
71
|
when :added then "+"
|
|
72
72
|
when :removed then "-"
|
|
73
73
|
when :changed then "!"
|
|
74
74
|
end
|
|
75
|
-
end
|
|
75
|
+
end
|
|
76
76
|
|
|
77
77
|
# Create block
|
|
78
78
|
block = DiffBlock.new(
|
|
@@ -182,7 +182,7 @@ module Canon
|
|
|
182
182
|
if node.respond_to?(:name) && node.name == line_element_name
|
|
183
183
|
true
|
|
184
184
|
# Check if the node's parent has the matching name (for TextNode diffs)
|
|
185
|
-
elsif node.respond_to?(:parent) && node.parent.respond_to?(:name) && node.parent.name == line_element_name
|
|
185
|
+
elsif node.respond_to?(:parent) && node.parent.respond_to?(:name) && node.parent.name == line_element_name # rubocop:disable Style/IfWithBooleanLiteralBranches
|
|
186
186
|
true
|
|
187
187
|
else
|
|
188
188
|
false
|
|
@@ -160,7 +160,7 @@ module Canon
|
|
|
160
160
|
|
|
161
161
|
# Keep only context_lines after the last change
|
|
162
162
|
keep_until = [last_change_pos + context_lines, hunk.length - 1].min
|
|
163
|
-
hunk.slice!(keep_until + 1..-1) if keep_until < hunk.length - 1
|
|
163
|
+
hunk.slice!((keep_until + 1)..-1) if keep_until < hunk.length - 1
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
# Colorize text if color is enabled
|
|
@@ -454,7 +454,7 @@ module Canon
|
|
|
454
454
|
# Try to get from config if available
|
|
455
455
|
config = Canon::Config.instance
|
|
456
456
|
# Default to 10,000 if config not available
|
|
457
|
-
config&.xml&.diff&.max_diff_lines || 10_000
|
|
457
|
+
config&.xml&.diff&.max_diff_lines || 10_000 # rubocop:disable Style/SafeNavigationChainLength
|
|
458
458
|
end
|
|
459
459
|
|
|
460
460
|
# Build set of children of matched parents
|
|
@@ -294,9 +294,9 @@ module Canon
|
|
|
294
294
|
@diff_grouping_lines)
|
|
295
295
|
format_diff_groups(groups)
|
|
296
296
|
else
|
|
297
|
-
diff_sections.
|
|
297
|
+
diff_sections.filter_map do |s|
|
|
298
298
|
s[:formatted]
|
|
299
|
-
end.
|
|
299
|
+
end.join("\n\n")
|
|
300
300
|
end
|
|
301
301
|
|
|
302
302
|
output << formatted_diffs
|
|
@@ -289,9 +289,9 @@ module Canon
|
|
|
289
289
|
@diff_grouping_lines)
|
|
290
290
|
format_diff_groups(groups)
|
|
291
291
|
else
|
|
292
|
-
diff_sections.
|
|
292
|
+
diff_sections.filter_map do |s|
|
|
293
293
|
s[:formatted]
|
|
294
|
-
end.
|
|
294
|
+
end.join("\n\n")
|
|
295
295
|
end
|
|
296
296
|
|
|
297
297
|
output << formatted_diffs
|
|
@@ -298,7 +298,7 @@ show_diffs: :all)
|
|
|
298
298
|
# Try to get from config if available
|
|
299
299
|
config = Canon::Config.instance
|
|
300
300
|
# Default to 10,000 if config not available
|
|
301
|
-
config&.xml&.diff&.max_diff_lines || 10_000
|
|
301
|
+
config&.xml&.diff&.max_diff_lines || 10_000 # rubocop:disable Style/SafeNavigationChainLength
|
|
302
302
|
end
|
|
303
303
|
end
|
|
304
304
|
end
|
|
@@ -293,7 +293,9 @@ module Canon
|
|
|
293
293
|
if value.empty?
|
|
294
294
|
"{}"
|
|
295
295
|
else
|
|
296
|
-
"{Hash with #{value.keys.length} keys:
|
|
296
|
+
"{Hash with #{value.keys.length} keys: " \
|
|
297
|
+
"#{value.keys.take(3).join(', ')}" \
|
|
298
|
+
"#{'...' if value.keys.length > 3}}"
|
|
297
299
|
end
|
|
298
300
|
else
|
|
299
301
|
value.inspect
|
|
@@ -27,9 +27,9 @@ module Canon
|
|
|
27
27
|
|
|
28
28
|
output = []
|
|
29
29
|
output << ""
|
|
30
|
-
output << "=" * 80
|
|
30
|
+
output << ("=" * 80)
|
|
31
31
|
output << "CANON VERBOSE MODE - DETAILED OPTIONS"
|
|
32
|
-
output << "=" * 80
|
|
32
|
+
output << ("=" * 80)
|
|
33
33
|
output << ""
|
|
34
34
|
|
|
35
35
|
# Show match options as a table
|
|
@@ -44,7 +44,7 @@ module Canon
|
|
|
44
44
|
output << format_comparison_summary(comparison_result)
|
|
45
45
|
output << ""
|
|
46
46
|
|
|
47
|
-
output << "=" * 80
|
|
47
|
+
output << ("=" * 80)
|
|
48
48
|
output << ""
|
|
49
49
|
|
|
50
50
|
output.join("\n")
|
|
@@ -63,9 +63,7 @@ module Canon
|
|
|
63
63
|
internal_keys = %i[tree_diff_operations tree_diff_statistics
|
|
64
64
|
tree_diff_matching]
|
|
65
65
|
|
|
66
|
-
rows = comparison_result.match_options.
|
|
67
|
-
internal_keys.include?(dimension)
|
|
68
|
-
end.map do |dimension, behavior|
|
|
66
|
+
rows = comparison_result.match_options.except(*internal_keys).map do |dimension, behavior|
|
|
69
67
|
{
|
|
70
68
|
dimension: dimension.to_s,
|
|
71
69
|
behavior: behavior.to_s,
|
|
@@ -148,7 +148,7 @@ module Canon
|
|
|
148
148
|
changed_str = changed.map do |prefix|
|
|
149
149
|
attr_name = prefix.empty? ? "xmlns" : "xmlns:#{prefix}"
|
|
150
150
|
"#{ColorHelper.colorize(attr_name, :cyan, use_color)}: " \
|
|
151
|
-
|
|
151
|
+
"\"#{ns_decls1[prefix]}\" → \"#{ns_decls2[prefix]}\""
|
|
152
152
|
end.join(", ")
|
|
153
153
|
changes_parts << "Changed: #{changed_str}"
|
|
154
154
|
end
|
|
@@ -144,6 +144,11 @@ module Canon
|
|
|
144
144
|
elsif node.respond_to?(:get_attribute)
|
|
145
145
|
attr = node.get_attribute(attr_name)
|
|
146
146
|
attr.respond_to?(:value) ? attr.value : attr
|
|
147
|
+
elsif node.respond_to?(:attribute_nodes)
|
|
148
|
+
attribute_node = node.attribute_nodes.find do |attr|
|
|
149
|
+
attr.name == attr_name.to_s
|
|
150
|
+
end
|
|
151
|
+
attribute_node&.value
|
|
147
152
|
end
|
|
148
153
|
end
|
|
149
154
|
|
|
@@ -162,6 +167,8 @@ module Canon
|
|
|
162
167
|
node.inner_text
|
|
163
168
|
elsif node.respond_to?(:value)
|
|
164
169
|
node.value
|
|
170
|
+
elsif node.respond_to?(:node_info)
|
|
171
|
+
node.node_info
|
|
165
172
|
elsif node.respond_to?(:to_s)
|
|
166
173
|
node.to_s
|
|
167
174
|
else
|
|
@@ -109,6 +109,12 @@ module Canon
|
|
|
109
109
|
output << "#{colorize('Location:', :cyan, use_color,
|
|
110
110
|
bold: true)} #{colorize(location, :blue,
|
|
111
111
|
use_color)}"
|
|
112
|
+
|
|
113
|
+
# show reason if available
|
|
114
|
+
if diff.respond_to?(:reason) && diff.reason
|
|
115
|
+
output << "#{colorize('Reason:', :cyan, use_color,
|
|
116
|
+
bold: true)} #{colorize(diff.reason, :yellow, use_color)}"
|
|
117
|
+
end
|
|
112
118
|
output << ""
|
|
113
119
|
|
|
114
120
|
# Dimension-specific details
|
data/lib/canon/diff_formatter.rb
CHANGED
|
@@ -410,7 +410,7 @@ module Canon
|
|
|
410
410
|
when :xml
|
|
411
411
|
[
|
|
412
412
|
Canon::Xml::C14n.canonicalize(expected, with_comments: false).gsub(
|
|
413
|
-
|
|
413
|
+
"><", ">\n<"
|
|
414
414
|
),
|
|
415
415
|
Canon::Xml::C14n.canonicalize(actual, with_comments: false).gsub(
|
|
416
416
|
/>\s+$/, ""
|
|
@@ -510,11 +510,11 @@ module Canon
|
|
|
510
510
|
output << colorize("=== ORIGINAL INPUTS (Raw) ===", :cyan, :bold)
|
|
511
511
|
output << ""
|
|
512
512
|
output << colorize("EXPECTED:", :yellow, :bold)
|
|
513
|
-
output << "-" * 70
|
|
513
|
+
output << ("-" * 70)
|
|
514
514
|
output << raw1
|
|
515
515
|
output << ""
|
|
516
516
|
output << colorize("RECEIVED:", :yellow, :bold)
|
|
517
|
-
output << "-" * 70
|
|
517
|
+
output << ("-" * 70)
|
|
518
518
|
output << raw2
|
|
519
519
|
output << ""
|
|
520
520
|
output << ""
|
|
@@ -543,11 +543,11 @@ preprocessing_info = nil)
|
|
|
543
543
|
end
|
|
544
544
|
output << ""
|
|
545
545
|
output << colorize("EXPECTED:", :yellow, :bold)
|
|
546
|
-
output << "-" * 70
|
|
546
|
+
output << ("-" * 70)
|
|
547
547
|
output << preprocessed1
|
|
548
548
|
output << ""
|
|
549
549
|
output << colorize("RECEIVED:", :yellow, :bold)
|
|
550
|
-
output << "-" * 70
|
|
550
|
+
output << ("-" * 70)
|
|
551
551
|
output << preprocessed2
|
|
552
552
|
output << ""
|
|
553
553
|
output << ""
|
data/lib/canon/errors.rb
CHANGED
|
@@ -83,13 +83,13 @@ module Canon
|
|
|
83
83
|
case limit_type
|
|
84
84
|
when :file_size
|
|
85
85
|
"File size (#{format_bytes(actual)}) exceeds limit (#{format_bytes(limit)}). " \
|
|
86
|
-
|
|
86
|
+
"Increase limit via CANON_MAX_FILE_SIZE or config.diff.max_file_size"
|
|
87
87
|
when :node_count
|
|
88
88
|
"Tree node count (#{actual}) exceeds limit (#{limit}). " \
|
|
89
|
-
|
|
89
|
+
"Increase limit via CANON_MAX_NODE_COUNT or config.diff.max_node_count"
|
|
90
90
|
when :diff_lines
|
|
91
91
|
"Diff output (#{actual} lines) exceeds limit (#{limit} lines). " \
|
|
92
|
-
|
|
92
|
+
"Output truncated. Increase limit via CANON_MAX_DIFF_LINES or config.diff.max_diff_lines"
|
|
93
93
|
else
|
|
94
94
|
"Size limit exceeded: #{limit_type} (#{actual} > #{limit})"
|
|
95
95
|
end
|
data/lib/canon/rspec_matchers.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "canon" unless defined?(
|
|
3
|
+
require "canon" unless defined?(Canon)
|
|
4
4
|
require "canon/comparison"
|
|
5
5
|
require "canon/diff_formatter"
|
|
6
6
|
require "canon/config"
|
|
@@ -137,7 +137,7 @@ module Canon
|
|
|
137
137
|
@target
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
-
def diffable
|
|
140
|
+
def diffable # rubocop:disable Naming/PredicateMethod
|
|
141
141
|
false
|
|
142
142
|
end
|
|
143
143
|
|
|
@@ -166,13 +166,9 @@ module Canon
|
|
|
166
166
|
# @param tree_node [Core::TreeNode] Array tree node
|
|
167
167
|
# @return [Array] Reconstructed array
|
|
168
168
|
def build_array(tree_node)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
tree_node.children.each do |child|
|
|
172
|
-
array << from_tree(child)
|
|
169
|
+
tree_node.children.map do |child|
|
|
170
|
+
from_tree(child)
|
|
173
171
|
end
|
|
174
|
-
|
|
175
|
-
array
|
|
176
172
|
end
|
|
177
173
|
|
|
178
174
|
# Parse value from value TreeNode
|
|
@@ -169,13 +169,9 @@ module Canon
|
|
|
169
169
|
# @param tree_node [Core::TreeNode] Array tree node
|
|
170
170
|
# @return [Array] Reconstructed array
|
|
171
171
|
def build_array(tree_node)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
tree_node.children.each do |child|
|
|
175
|
-
array << from_tree(child)
|
|
172
|
+
tree_node.children.map do |child|
|
|
173
|
+
from_tree(child)
|
|
176
174
|
end
|
|
177
|
-
|
|
178
|
-
array
|
|
179
175
|
end
|
|
180
176
|
|
|
181
177
|
# Parse value from value TreeNode
|
|
@@ -28,7 +28,7 @@ module Canon
|
|
|
28
28
|
# @param node1 [TreeNode] Node from tree 1
|
|
29
29
|
# @param node2 [TreeNode] Node from tree 2
|
|
30
30
|
# @return [Boolean] true if added, false if violates constraints
|
|
31
|
-
def add(node1, node2)
|
|
31
|
+
def add(node1, node2) # rubocop:disable Naming/PredicateMethod
|
|
32
32
|
return false unless valid_pair?(node1, node2)
|
|
33
33
|
|
|
34
34
|
@pairs << [node1, node2]
|
|
@@ -43,7 +43,7 @@ module Canon
|
|
|
43
43
|
# @param node1 [TreeNode] Node from tree 1
|
|
44
44
|
# @param node2 [TreeNode] Node from tree 2
|
|
45
45
|
# @return [Boolean] true if removed, false if not found
|
|
46
|
-
def remove(node1, node2)
|
|
46
|
+
def remove(node1, node2) # rubocop:disable Naming/PredicateMethod
|
|
47
47
|
removed = @pairs.delete([node1, node2])
|
|
48
48
|
return false unless removed
|
|
49
49
|
|
|
@@ -81,12 +81,10 @@ module Canon
|
|
|
81
81
|
#
|
|
82
82
|
# @return [Array<String>] Path components
|
|
83
83
|
def compute_path
|
|
84
|
-
components = []
|
|
85
|
-
|
|
86
84
|
# Build path from root to node
|
|
87
85
|
ancestors = @node.ancestors.reverse
|
|
88
|
-
ancestors.
|
|
89
|
-
|
|
86
|
+
components = ancestors.map do |ancestor|
|
|
87
|
+
path_component(ancestor)
|
|
90
88
|
end
|
|
91
89
|
|
|
92
90
|
# Add the node itself
|
|
@@ -292,7 +292,7 @@ module Canon
|
|
|
292
292
|
attr_diff = attribute_difference(other)
|
|
293
293
|
|
|
294
294
|
# Weighted combination
|
|
295
|
-
depth_diff * 0.3 + content_diff * 0.5 + attr_diff * 0.2
|
|
295
|
+
(depth_diff * 0.3) + (content_diff * 0.5) + (attr_diff * 0.2)
|
|
296
296
|
end
|
|
297
297
|
|
|
298
298
|
# Get content as a set for similarity calculation
|
|
@@ -352,7 +352,7 @@ module Canon
|
|
|
352
352
|
#
|
|
353
353
|
# @param dimension [Symbol] Match dimension
|
|
354
354
|
# @return [Boolean] true if normative (should be shown)
|
|
355
|
-
def determine_normative(dimension)
|
|
355
|
+
def determine_normative(dimension) # rubocop:disable Naming/PredicateMethod
|
|
356
356
|
# Check match options behavior for this dimension
|
|
357
357
|
behavior = @match_options.behavior_for(dimension)
|
|
358
358
|
|
data/lib/canon/version.rb
CHANGED
data/lib/canon.rb
CHANGED
|
@@ -13,7 +13,7 @@ require_relative "canon/formatters/html4_formatter"
|
|
|
13
13
|
require_relative "canon/formatters/html5_formatter"
|
|
14
14
|
require_relative "canon/comparison"
|
|
15
15
|
|
|
16
|
-
require_relative "canon/rspec_matchers" if defined?(
|
|
16
|
+
require_relative "canon/rspec_matchers" if defined?(RSpec)
|
|
17
17
|
|
|
18
18
|
module Canon
|
|
19
19
|
SUPPORTED_FORMATS = %i[xml yaml json html html4 html5 string].freeze
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: canon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-03-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: diff-lcs
|
|
@@ -351,6 +351,7 @@ metadata:
|
|
|
351
351
|
homepage_uri: https://github.com/lutaml/canon
|
|
352
352
|
source_code_uri: https://github.com/lutaml/canon
|
|
353
353
|
changelog_uri: https://github.com/lutaml/canon
|
|
354
|
+
rubygems_mfa_required: 'true'
|
|
354
355
|
post_install_message:
|
|
355
356
|
rdoc_options: []
|
|
356
357
|
require_paths:
|