canon 0.1.13 → 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/.rubocop_todo.yml +69 -21
- data/README.adoc +41 -0
- data/docs/interfaces/ruby-api/index.adoc +26 -0
- data/docs/understanding/formats/xml.adoc +25 -0
- data/lib/canon/color_detector.rb +18 -15
- 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 +11 -3
- data/lib/canon/comparison/format_detector.rb +1 -1
- data/lib/canon/comparison/html_comparator.rb +91 -41
- data/lib/canon/comparison/html_parser.rb +22 -0
- data/lib/canon/comparison/markup_comparator.rb +46 -11
- data/lib/canon/comparison/profile_definition.rb +1 -1
- data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +3 -3
- data/lib/canon/comparison/xml_comparator/child_comparison.rb +87 -9
- data/lib/canon/comparison/xml_comparator/node_parser.rb +1 -1
- data/lib/canon/comparison/xml_comparator.rb +48 -15
- data/lib/canon/comparison/xml_node_comparison.rb +110 -12
- data/lib/canon/comparison.rb +45 -1
- data/lib/canon/config/env_provider.rb +3 -3
- data/lib/canon/config/env_schema.rb +2 -1
- data/lib/canon/config.rb +10 -0
- 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 +10 -1
- data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +11 -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/formatters/xml_formatter.rb +20 -0
- data/lib/canon/html/data_model.rb +26 -4
- data/lib/canon/rspec_matchers.rb +17 -2
- data/lib/canon/tree_diff/adapters/html_adapter.rb +20 -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/matchers/hash_matcher.rb +12 -2
- 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/element_matcher.rb +70 -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/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-
|
|
3
|
+
# on 2026-02-17 14:18:53 UTC using RuboCop version 1.81.7.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -12,13 +12,52 @@ Gemspec/RequiredRubyVersion:
|
|
|
12
12
|
Exclude:
|
|
13
13
|
- 'canon.gemspec'
|
|
14
14
|
|
|
15
|
-
# Offense count:
|
|
15
|
+
# Offense count: 1
|
|
16
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
17
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
18
|
+
# SupportedStyles: with_first_argument, with_fixed_indentation
|
|
19
|
+
Layout/ArgumentAlignment:
|
|
20
|
+
Exclude:
|
|
21
|
+
- 'lib/canon/xml/element_matcher.rb'
|
|
22
|
+
|
|
23
|
+
# Offense count: 23
|
|
24
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
25
|
+
# Configuration parameters: EnforcedStyleAlignWith.
|
|
26
|
+
# SupportedStylesAlignWith: either, start_of_block, start_of_line
|
|
27
|
+
Layout/BlockAlignment:
|
|
28
|
+
Exclude:
|
|
29
|
+
- 'spec/canon/fixtures/isodoc_spec.rb'
|
|
30
|
+
- 'spec/canon/table_class_attribute_bug_spec.rb'
|
|
31
|
+
|
|
32
|
+
# Offense count: 23
|
|
33
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
34
|
+
Layout/BlockEndNewline:
|
|
35
|
+
Exclude:
|
|
36
|
+
- 'spec/canon/fixtures/isodoc_spec.rb'
|
|
37
|
+
- 'spec/canon/table_class_attribute_bug_spec.rb'
|
|
38
|
+
|
|
39
|
+
# Offense count: 46
|
|
40
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
41
|
+
# Configuration parameters: Width, AllowedPatterns.
|
|
42
|
+
Layout/IndentationWidth:
|
|
43
|
+
Exclude:
|
|
44
|
+
- 'spec/canon/fixtures/isodoc_spec.rb'
|
|
45
|
+
- 'spec/canon/table_class_attribute_bug_spec.rb'
|
|
46
|
+
|
|
47
|
+
# Offense count: 780
|
|
16
48
|
# This cop supports safe autocorrection (--autocorrect).
|
|
17
49
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
|
|
18
50
|
# URISchemes: http, https
|
|
19
51
|
Layout/LineLength:
|
|
20
52
|
Enabled: false
|
|
21
53
|
|
|
54
|
+
# Offense count: 1
|
|
55
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
56
|
+
# Configuration parameters: AllowInHeredoc.
|
|
57
|
+
Layout/TrailingWhitespace:
|
|
58
|
+
Exclude:
|
|
59
|
+
- 'lib/canon/xml/element_matcher.rb'
|
|
60
|
+
|
|
22
61
|
# Offense count: 48
|
|
23
62
|
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
|
|
24
63
|
Lint/DuplicateBranch:
|
|
@@ -48,44 +87,45 @@ Lint/UnreachableCode:
|
|
|
48
87
|
Exclude:
|
|
49
88
|
- 'lib/canon/diff_formatter/debug_output.rb'
|
|
50
89
|
|
|
51
|
-
# Offense count:
|
|
90
|
+
# Offense count: 7
|
|
52
91
|
# This cop supports safe autocorrection (--autocorrect).
|
|
53
92
|
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
|
|
54
93
|
# NotImplementedExceptions: NotImplementedError
|
|
55
94
|
Lint/UnusedMethodArgument:
|
|
56
95
|
Exclude:
|
|
96
|
+
- 'lib/canon/comparison.rb'
|
|
57
97
|
- 'lib/canon/diff/path_builder.rb'
|
|
58
98
|
- 'lib/canon/diff_formatter/by_line/base_formatter.rb'
|
|
59
99
|
- 'lib/canon/diff_formatter/by_line/xml_formatter.rb'
|
|
60
100
|
- 'lib/canon/diff_formatter/by_object/base_formatter.rb'
|
|
61
101
|
|
|
62
|
-
# Offense count:
|
|
102
|
+
# Offense count: 215
|
|
63
103
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
64
104
|
Metrics/AbcSize:
|
|
65
105
|
Enabled: false
|
|
66
106
|
|
|
67
|
-
# Offense count:
|
|
107
|
+
# Offense count: 21
|
|
68
108
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
|
69
109
|
# AllowedMethods: refine
|
|
70
110
|
Metrics/BlockLength:
|
|
71
111
|
Max: 84
|
|
72
112
|
|
|
73
|
-
# Offense count:
|
|
113
|
+
# Offense count: 183
|
|
74
114
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
75
115
|
Metrics/CyclomaticComplexity:
|
|
76
116
|
Enabled: false
|
|
77
117
|
|
|
78
|
-
# Offense count:
|
|
118
|
+
# Offense count: 369
|
|
79
119
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
80
120
|
Metrics/MethodLength:
|
|
81
|
-
Max:
|
|
121
|
+
Max: 115
|
|
82
122
|
|
|
83
123
|
# Offense count: 44
|
|
84
124
|
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
|
|
85
125
|
Metrics/ParameterLists:
|
|
86
126
|
Max: 9
|
|
87
127
|
|
|
88
|
-
# Offense count:
|
|
128
|
+
# Offense count: 149
|
|
89
129
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
90
130
|
Metrics/PerceivedComplexity:
|
|
91
131
|
Enabled: false
|
|
@@ -119,12 +159,13 @@ Naming/VariableNumber:
|
|
|
119
159
|
- 'lib/canon/comparison/markup_comparator.rb'
|
|
120
160
|
- 'lib/canon/comparison/xml_comparator/diff_node_builder.rb'
|
|
121
161
|
|
|
122
|
-
# Offense count:
|
|
162
|
+
# Offense count: 13
|
|
123
163
|
# Configuration parameters: MinSize.
|
|
124
164
|
Performance/CollectionLiteralInLoop:
|
|
125
165
|
Exclude:
|
|
126
166
|
- 'lib/canon/comparison/html_comparator.rb'
|
|
127
167
|
- 'lib/canon/xml/xml_base_handler.rb'
|
|
168
|
+
- 'spec/canon/table_class_attribute_bug_spec.rb'
|
|
128
169
|
|
|
129
170
|
# Offense count: 68
|
|
130
171
|
# Configuration parameters: Prefixes, AllowedPatterns.
|
|
@@ -132,7 +173,7 @@ Performance/CollectionLiteralInLoop:
|
|
|
132
173
|
RSpec/ContextWording:
|
|
133
174
|
Enabled: false
|
|
134
175
|
|
|
135
|
-
# Offense count:
|
|
176
|
+
# Offense count: 27
|
|
136
177
|
# Configuration parameters: IgnoredMetadata.
|
|
137
178
|
RSpec/DescribeClass:
|
|
138
179
|
Enabled: false
|
|
@@ -143,13 +184,7 @@ RSpec/DescribeMethod:
|
|
|
143
184
|
- 'spec/canon/comparison/multiple_differences_spec.rb'
|
|
144
185
|
- 'spec/canon/diff_formatter/character_map_customization_spec.rb'
|
|
145
186
|
|
|
146
|
-
# Offense count:
|
|
147
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
148
|
-
RSpec/EmptyHook:
|
|
149
|
-
Exclude:
|
|
150
|
-
- 'spec/canon/color_detector_spec.rb'
|
|
151
|
-
|
|
152
|
-
# Offense count: 679
|
|
187
|
+
# Offense count: 696
|
|
153
188
|
# Configuration parameters: CountAsOne.
|
|
154
189
|
RSpec/ExampleLength:
|
|
155
190
|
Max: 67
|
|
@@ -201,11 +236,11 @@ RSpec/MultipleDescribes:
|
|
|
201
236
|
Exclude:
|
|
202
237
|
- 'spec/canon/comparison/match_options_spec.rb'
|
|
203
238
|
|
|
204
|
-
# Offense count:
|
|
239
|
+
# Offense count: 536
|
|
205
240
|
RSpec/MultipleExpectations:
|
|
206
241
|
Max: 15
|
|
207
242
|
|
|
208
|
-
# Offense count:
|
|
243
|
+
# Offense count: 70
|
|
209
244
|
# Configuration parameters: AllowSubject.
|
|
210
245
|
RSpec/MultipleMemoizedHelpers:
|
|
211
246
|
Max: 13
|
|
@@ -224,12 +259,13 @@ RSpec/NamedSubject:
|
|
|
224
259
|
RSpec/NestedGroups:
|
|
225
260
|
Max: 4
|
|
226
261
|
|
|
227
|
-
# Offense count:
|
|
262
|
+
# Offense count: 11
|
|
228
263
|
# Configuration parameters: AllowedPatterns.
|
|
229
264
|
# AllowedPatterns: ^expect_, ^assert_
|
|
230
265
|
RSpec/NoExpectationExample:
|
|
231
266
|
Exclude:
|
|
232
267
|
- 'spec/canon/context_grouping_spec.rb'
|
|
268
|
+
- 'spec/canon/fixtures/isodoc_spec.rb'
|
|
233
269
|
- 'spec/canon/informative_diffs_debug_spec.rb'
|
|
234
270
|
- 'spec/canon/isodoc_blockquotes_spec.rb'
|
|
235
271
|
- 'spec/canon/match_scenarios_spec.rb'
|
|
@@ -257,6 +293,18 @@ RSpec/VerifiedDoubles:
|
|
|
257
293
|
- 'spec/canon/diff/xml_serialization_formatter_spec.rb'
|
|
258
294
|
- 'spec/canon/tree_diff/operation_converter_spec.rb'
|
|
259
295
|
|
|
296
|
+
# Offense count: 44
|
|
297
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
298
|
+
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
|
|
299
|
+
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
|
|
300
|
+
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
|
|
301
|
+
# FunctionalMethods: let, let!, subject, watch
|
|
302
|
+
# AllowedMethods: lambda, proc, it
|
|
303
|
+
Style/BlockDelimiters:
|
|
304
|
+
Exclude:
|
|
305
|
+
- 'spec/canon/fixtures/isodoc_spec.rb'
|
|
306
|
+
- 'spec/canon/table_class_attribute_bug_spec.rb'
|
|
307
|
+
|
|
260
308
|
# Offense count: 1
|
|
261
309
|
# This cop supports safe autocorrection (--autocorrect).
|
|
262
310
|
# Configuration parameters: EnforcedStyle, AllowComments.
|
data/README.adoc
CHANGED
|
@@ -16,6 +16,47 @@ Key features:
|
|
|
16
16
|
* **Multiple interfaces**: Ruby API, CLI, RSpec matchers
|
|
17
17
|
* **Smart diff output**: By-line or by-object modes with syntax highlighting
|
|
18
18
|
|
|
19
|
+
== When to use formatting vs comparison
|
|
20
|
+
|
|
21
|
+
Canon provides two main APIs with different purposes:
|
|
22
|
+
|
|
23
|
+
*Use `Canon.format` for formatting/canonicalization:*
|
|
24
|
+
|
|
25
|
+
* Pretty-printing XML/JSON/YAML for display
|
|
26
|
+
* Canonicalizing documents for storage
|
|
27
|
+
* Normalizing formatting
|
|
28
|
+
|
|
29
|
+
*Use `Canon::Comparison.equivalent?` for semantic comparison:*
|
|
30
|
+
|
|
31
|
+
* Test assertions
|
|
32
|
+
* Document equivalence checking
|
|
33
|
+
* Diff generation
|
|
34
|
+
|
|
35
|
+
[IMPORTANT]
|
|
36
|
+
====
|
|
37
|
+
Do NOT use `Canon.format_xml` output for string comparison in tests.
|
|
38
|
+
The formatting process changes line counts and formatting, which causes
|
|
39
|
+
false test failures.
|
|
40
|
+
|
|
41
|
+
Use `Canon::Comparison.equivalent?` instead, which performs semantic
|
|
42
|
+
comparison and properly handles XML declarations.
|
|
43
|
+
====
|
|
44
|
+
|
|
45
|
+
[example]
|
|
46
|
+
====
|
|
47
|
+
[source,ruby]
|
|
48
|
+
----
|
|
49
|
+
# WRONG - formatting changes line counts
|
|
50
|
+
expect(Canon.format_xml(actual)).to eq(expected_formatted)
|
|
51
|
+
|
|
52
|
+
# RIGHT - semantic comparison ignores formatting differences
|
|
53
|
+
expect(Canon::Comparison.equivalent?(actual, expected, format: :xml)).to be true
|
|
54
|
+
|
|
55
|
+
# BEST - use RSpec matchers
|
|
56
|
+
expect(actual).to be_xml_equivalent_to(expected)
|
|
57
|
+
----
|
|
58
|
+
====
|
|
59
|
+
|
|
19
60
|
== Installation
|
|
20
61
|
|
|
21
62
|
Add to your application's Gemfile:
|
|
@@ -18,6 +18,32 @@ For command-line usage, see link:../cli/[CLI documentation].
|
|
|
18
18
|
|
|
19
19
|
For RSpec testing, see link:../rspec/[RSpec documentation].
|
|
20
20
|
|
|
21
|
+
== Choosing the right API
|
|
22
|
+
|
|
23
|
+
Canon provides two main categories of APIs with different purposes.
|
|
24
|
+
|
|
25
|
+
=== Formatting APIs
|
|
26
|
+
|
|
27
|
+
Use `Canon.format` or `Canon.format_xml` when you need to:
|
|
28
|
+
|
|
29
|
+
* Pretty-print documents for display
|
|
30
|
+
* Canonicalize documents for storage
|
|
31
|
+
* Normalize document formatting
|
|
32
|
+
|
|
33
|
+
NOTE: XML declarations are preserved in pretty-print mode and removed in
|
|
34
|
+
canonicalization mode.
|
|
35
|
+
|
|
36
|
+
=== Comparison APIs
|
|
37
|
+
|
|
38
|
+
Use `Canon::Comparison.equivalent?` when you need to:
|
|
39
|
+
|
|
40
|
+
* Compare documents semantically
|
|
41
|
+
* Generate diffs
|
|
42
|
+
* Make test assertions
|
|
43
|
+
|
|
44
|
+
NOTE: XML declarations are stripped during preprocessing for semantic comparison.
|
|
45
|
+
Documents with and without XML declarations are considered equivalent.
|
|
46
|
+
|
|
21
47
|
== General
|
|
22
48
|
|
|
23
49
|
Canon provides a unified Ruby API for working with XML, HTML, JSON, and YAML
|
|
@@ -183,6 +183,31 @@ configures preprocessing, match options, diff algorithm, and formatting.
|
|
|
183
183
|
|
|
184
184
|
== XML-specific features
|
|
185
185
|
|
|
186
|
+
=== XML declaration handling
|
|
187
|
+
|
|
188
|
+
The XML declaration (`<?xml version="1.0" encoding="UTF-8"?>`) is handled
|
|
189
|
+
differently depending on the operation:
|
|
190
|
+
|
|
191
|
+
[cols="2,3"]
|
|
192
|
+
|===
|
|
193
|
+
| Operation | XML Declaration
|
|
194
|
+
|
|
195
|
+
| `Canon.format_xml` (pretty)
|
|
196
|
+
| Preserved
|
|
197
|
+
|
|
198
|
+
| `Canon.format_xml` (c14n)
|
|
199
|
+
| Removed (per W3C C14N spec)
|
|
200
|
+
|
|
201
|
+
| `Canon::Comparison.equivalent?`
|
|
202
|
+
| Stripped during preprocessing
|
|
203
|
+
|
|
204
|
+
| RSpec matchers
|
|
205
|
+
| Stripped during preprocessing
|
|
206
|
+
|===
|
|
207
|
+
|
|
208
|
+
This means documents with and without XML declarations are considered
|
|
209
|
+
equivalent when using the comparison API.
|
|
210
|
+
|
|
186
211
|
=== Comment handling
|
|
187
212
|
|
|
188
213
|
XML comments are preserved in canonical form unless `--with-comments` is explicitly set.
|
data/lib/canon/color_detector.rb
CHANGED
|
@@ -81,24 +81,27 @@ module Canon
|
|
|
81
81
|
#
|
|
82
82
|
# @return [Boolean] true if colors appear to be supported
|
|
83
83
|
def detect_from_env
|
|
84
|
-
# Check for known color-capable terminals
|
|
85
|
-
colorterm = ENV["COLORTERM"]
|
|
86
|
-
return true if COLOR_TERM_VALUES.include?(colorterm)
|
|
87
|
-
|
|
88
84
|
# Check TERM variable
|
|
89
|
-
term = ENV
|
|
90
|
-
if term
|
|
85
|
+
term = ENV.fetch("TERM", nil)
|
|
86
|
+
if term && NO_COLOR_TERMS.any? { |t| term.include?(t) }
|
|
91
87
|
# Known no-color terminals
|
|
92
|
-
return false
|
|
88
|
+
return false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Check CI environments
|
|
92
|
+
# Some CI systems support colors, others don't
|
|
93
|
+
return detect_ci_colors if ci_environment?
|
|
94
|
+
|
|
95
|
+
if term
|
|
93
96
|
# Known color-capable terminals
|
|
94
97
|
return true if COLOR_TERM_SUFFIXES.any? { |s| term.end_with?(s) }
|
|
95
98
|
# Most modern terminals support basic ANSI colors
|
|
96
99
|
return true unless term.empty? || term == "unknown"
|
|
97
100
|
end
|
|
98
101
|
|
|
99
|
-
# Check
|
|
100
|
-
|
|
101
|
-
return
|
|
102
|
+
# Check for known color-capable terminals
|
|
103
|
+
colorterm = ENV.fetch("COLORTERM", nil)
|
|
104
|
+
return true if COLOR_TERM_VALUES.include?(colorterm)
|
|
102
105
|
|
|
103
106
|
# Default: assume colors are supported on modern terminals
|
|
104
107
|
# This is a safe default for most use cases
|
|
@@ -122,17 +125,17 @@ module Canon
|
|
|
122
125
|
# - Generic CI: check for specific TeamCity/Terminal variables
|
|
123
126
|
#
|
|
124
127
|
# @return [Boolean] true if CI environment likely supports colors
|
|
125
|
-
def detect_ci_colors
|
|
128
|
+
def detect_ci_colors # rubocop:disable Naming/PredicateMethod
|
|
129
|
+
# Most modern CI systems support ANSI colors
|
|
130
|
+
# Only disable for explicitly known non-color CI
|
|
131
|
+
return false if ENV["TERM"] == "dumb"
|
|
132
|
+
|
|
126
133
|
# GitHub Actions explicitly supports colors
|
|
127
134
|
return true if ENV["GITHUB_ACTIONS"]
|
|
128
135
|
|
|
129
136
|
# TeamCity supports colors with specific env var
|
|
130
137
|
return true if ENV["TEAMCITY_VERSION"]
|
|
131
138
|
|
|
132
|
-
# Most modern CI systems support ANSI colors
|
|
133
|
-
# Only disable for explicitly known non-color CI
|
|
134
|
-
return false if ENV["TERM"] == "dumb"
|
|
135
|
-
|
|
136
139
|
# Default to supporting colors in CI
|
|
137
140
|
true
|
|
138
141
|
end
|
|
@@ -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,19 +37,27 @@ 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
|
|
|
44
44
|
# Normalized text comparison
|
|
45
45
|
#
|
|
46
46
|
# Collapses whitespace and compares.
|
|
47
|
+
# Two whitespace-only strings that both normalize to empty are equivalent.
|
|
47
48
|
#
|
|
48
49
|
# @param text1 [String, nil] First text
|
|
49
50
|
# @param text2 [String, nil] Second text
|
|
50
51
|
# @return [Boolean] true if normalized texts are equal
|
|
51
|
-
def compare_normalize(text1, text2)
|
|
52
|
-
|
|
52
|
+
def compare_normalize(text1, text2) # rubocop:disable Naming/PredicateMethod
|
|
53
|
+
normalized1 = normalize_text(text1)
|
|
54
|
+
normalized2 = normalize_text(text2)
|
|
55
|
+
|
|
56
|
+
# Both empty after normalization = equivalent
|
|
57
|
+
# This handles whitespace-only text nodes that normalize to empty
|
|
58
|
+
return true if normalized1.empty? && normalized2.empty?
|
|
59
|
+
|
|
60
|
+
normalized1 == normalized2
|
|
53
61
|
end
|
|
54
62
|
|
|
55
63
|
private
|
|
@@ -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
|