canon 0.1.6 → 0.1.7

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.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +163 -67
  3. data/README.adoc +400 -7
  4. data/docs/Gemfile +9 -0
  5. data/docs/INDEX.adoc +99 -182
  6. data/docs/_config.yml +100 -0
  7. data/docs/advanced/diff-classification.adoc +547 -0
  8. data/docs/advanced/diff-pipeline.adoc +358 -0
  9. data/docs/advanced/index.adoc +214 -0
  10. data/docs/advanced/semantic-diff-report.adoc +390 -0
  11. data/docs/{VERBOSE.adoc → advanced/verbose-mode-architecture.adoc} +51 -53
  12. data/docs/features/diff-formatting/algorithm-specific-output.adoc +533 -0
  13. data/docs/{CHARACTER_VISUALIZATION.adoc → features/diff-formatting/character-visualization.adoc} +23 -62
  14. data/docs/features/diff-formatting/colors-and-symbols.adoc +606 -0
  15. data/docs/features/diff-formatting/context-and-grouping.adoc +490 -0
  16. data/docs/features/diff-formatting/display-filtering.adoc +472 -0
  17. data/docs/features/diff-formatting/index.adoc +140 -0
  18. data/docs/features/environment-configuration/index.adoc +327 -0
  19. data/docs/features/environment-configuration/override-system.adoc +436 -0
  20. data/docs/features/environment-configuration/size-limits.adoc +273 -0
  21. data/docs/features/index.adoc +173 -0
  22. data/docs/features/input-validation/index.adoc +521 -0
  23. data/docs/features/match-options/algorithm-specific-behavior.adoc +365 -0
  24. data/docs/features/match-options/html-policies.adoc +312 -0
  25. data/docs/features/match-options/index.adoc +621 -0
  26. data/docs/getting-started/index.adoc +83 -0
  27. data/docs/getting-started/quick-start.adoc +76 -0
  28. data/docs/guides/choosing-configuration.adoc +689 -0
  29. data/docs/guides/index.adoc +181 -0
  30. data/docs/{CLI.adoc → interfaces/cli/index.adoc} +18 -13
  31. data/docs/interfaces/index.adoc +101 -0
  32. data/docs/{RSPEC.adoc → interfaces/rspec/index.adoc} +242 -31
  33. data/docs/{RUBY_API.adoc → interfaces/ruby-api/index.adoc} +118 -16
  34. data/docs/lychee.toml +65 -0
  35. data/docs/reference/cli-options.adoc +418 -0
  36. data/docs/reference/environment-variables.adoc +375 -0
  37. data/docs/reference/index.adoc +204 -0
  38. data/docs/reference/options-across-interfaces.adoc +417 -0
  39. data/docs/understanding/algorithms/dom-diff.adoc +389 -0
  40. data/docs/understanding/algorithms/index.adoc +314 -0
  41. data/docs/understanding/algorithms/semantic-tree-diff.adoc +533 -0
  42. data/docs/understanding/architecture.adoc +447 -0
  43. data/docs/understanding/comparison-pipeline.adoc +317 -0
  44. data/docs/understanding/formats/html.adoc +380 -0
  45. data/docs/understanding/formats/index.adoc +261 -0
  46. data/docs/understanding/formats/json.adoc +390 -0
  47. data/docs/understanding/formats/xml.adoc +366 -0
  48. data/docs/understanding/formats/yaml.adoc +504 -0
  49. data/docs/understanding/index.adoc +130 -0
  50. data/lib/canon/cli.rb +42 -1
  51. data/lib/canon/commands/diff_command.rb +108 -23
  52. data/lib/canon/comparison/compare_profile.rb +101 -0
  53. data/lib/canon/comparison/comparison_result.rb +41 -2
  54. data/lib/canon/comparison/html_comparator.rb +292 -71
  55. data/lib/canon/comparison/html_compare_profile.rb +117 -0
  56. data/lib/canon/comparison/match_options.rb +42 -4
  57. data/lib/canon/comparison/strategies/base_match_strategy.rb +99 -0
  58. data/lib/canon/comparison/strategies/match_strategy_factory.rb +74 -0
  59. data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +220 -0
  60. data/lib/canon/comparison/xml_comparator.rb +695 -91
  61. data/lib/canon/comparison.rb +207 -2
  62. data/lib/canon/config/env_provider.rb +71 -0
  63. data/lib/canon/config/env_schema.rb +58 -0
  64. data/lib/canon/config/override_resolver.rb +55 -0
  65. data/lib/canon/config/type_converter.rb +59 -0
  66. data/lib/canon/config.rb +158 -29
  67. data/lib/canon/data_model.rb +29 -0
  68. data/lib/canon/diff/diff_classifier.rb +74 -14
  69. data/lib/canon/diff/diff_context_builder.rb +41 -0
  70. data/lib/canon/diff/diff_line.rb +18 -2
  71. data/lib/canon/diff/diff_node.rb +18 -3
  72. data/lib/canon/diff/diff_node_mapper.rb +71 -12
  73. data/lib/canon/diff/formatting_detector.rb +53 -0
  74. data/lib/canon/diff_formatter/by_line/base_formatter.rb +60 -5
  75. data/lib/canon/diff_formatter/by_line/html_formatter.rb +68 -16
  76. data/lib/canon/diff_formatter/by_line/json_formatter.rb +0 -37
  77. data/lib/canon/diff_formatter/by_line/simple_formatter.rb +0 -42
  78. data/lib/canon/diff_formatter/by_line/xml_formatter.rb +116 -31
  79. data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +0 -37
  80. data/lib/canon/diff_formatter/by_object/base_formatter.rb +126 -19
  81. data/lib/canon/diff_formatter/by_object/xml_formatter.rb +30 -1
  82. data/lib/canon/diff_formatter/debug_output.rb +7 -1
  83. data/lib/canon/diff_formatter/diff_detail_formatter.rb +674 -57
  84. data/lib/canon/diff_formatter/legend.rb +42 -0
  85. data/lib/canon/diff_formatter.rb +78 -9
  86. data/lib/canon/errors.rb +56 -0
  87. data/lib/canon/formatters/html_formatter_base.rb +35 -1
  88. data/lib/canon/formatters/json_formatter.rb +3 -0
  89. data/lib/canon/formatters/yaml_formatter.rb +3 -0
  90. data/lib/canon/html/data_model.rb +229 -0
  91. data/lib/canon/html.rb +9 -0
  92. data/lib/canon/options/cli_generator.rb +70 -0
  93. data/lib/canon/options/registry.rb +234 -0
  94. data/lib/canon/rspec_matchers.rb +34 -13
  95. data/lib/canon/tree_diff/adapters/html_adapter.rb +316 -0
  96. data/lib/canon/tree_diff/adapters/json_adapter.rb +204 -0
  97. data/lib/canon/tree_diff/adapters/xml_adapter.rb +285 -0
  98. data/lib/canon/tree_diff/adapters/yaml_adapter.rb +213 -0
  99. data/lib/canon/tree_diff/core/attribute_comparator.rb +84 -0
  100. data/lib/canon/tree_diff/core/matching.rb +241 -0
  101. data/lib/canon/tree_diff/core/node_signature.rb +164 -0
  102. data/lib/canon/tree_diff/core/node_weight.rb +135 -0
  103. data/lib/canon/tree_diff/core/tree_node.rb +450 -0
  104. data/lib/canon/tree_diff/matchers/hash_matcher.rb +258 -0
  105. data/lib/canon/tree_diff/matchers/similarity_matcher.rb +168 -0
  106. data/lib/canon/tree_diff/matchers/structural_propagator.rb +242 -0
  107. data/lib/canon/tree_diff/matchers/universal_matcher.rb +220 -0
  108. data/lib/canon/tree_diff/operation_converter.rb +631 -0
  109. data/lib/canon/tree_diff/operations/operation.rb +92 -0
  110. data/lib/canon/tree_diff/operations/operation_detector.rb +626 -0
  111. data/lib/canon/tree_diff/tree_diff_integrator.rb +140 -0
  112. data/lib/canon/tree_diff.rb +33 -0
  113. data/lib/canon/validators/json_validator.rb +3 -1
  114. data/lib/canon/validators/yaml_validator.rb +3 -1
  115. data/lib/canon/version.rb +1 -1
  116. data/lib/canon/xml/data_model.rb +22 -23
  117. data/lib/canon/xml/element_matcher.rb +128 -20
  118. data/lib/canon/xml/namespace_helper.rb +110 -0
  119. data/lib/canon.rb +3 -0
  120. metadata +81 -23
  121. data/_config.yml +0 -116
  122. data/docs/ADVANCED_TOPICS.adoc +0 -20
  123. data/docs/BASIC_USAGE.adoc +0 -16
  124. data/docs/CUSTOMIZING_BEHAVIOR.adoc +0 -19
  125. data/docs/DIFF_ARCHITECTURE.adoc +0 -435
  126. data/docs/DIFF_FORMATTING.adoc +0 -540
  127. data/docs/FORMATS.adoc +0 -447
  128. data/docs/INPUT_VALIDATION.adoc +0 -477
  129. data/docs/MATCH_ARCHITECTURE.adoc +0 -463
  130. data/docs/MATCH_OPTIONS.adoc +0 -719
  131. data/docs/MODES.adoc +0 -432
  132. data/docs/NORMATIVE_INFORMATIVE_DIFFS.adoc +0 -219
  133. data/docs/OPTIONS.adoc +0 -1387
  134. data/docs/PREPROCESSING.adoc +0 -491
  135. data/docs/SEMANTIC_DIFF_REPORT.adoc +0 -528
  136. data/docs/UNDERSTANDING_CANON.adoc +0 -17
@@ -0,0 +1,472 @@
1
+ = Display filtering
2
+ :toc:
3
+
4
+ == General
5
+
6
+ The `show_diffs` parameter controls which differences appear in diff output
7
+ while maintaining correct equivalence determination.
8
+
9
+ This feature allows you to filter diff display based on whether differences are
10
+ normative (affect equivalence) or informative (don't affect equivalence).
11
+
12
+ == Purpose
13
+
14
+ When comparing documents with both normative and informative differences, you
15
+ may want to:
16
+
17
+ * **Show only normative differences**: Focus on changes that make documents
18
+ non-equivalent
19
+ * **Show only informative differences**: View differences that don't affect
20
+ equivalence (e.g., comments when set to `:ignore`)
21
+ * **Show all differences**: See both types (default behavior)
22
+
23
+ === Common use case: XML comments
24
+
25
+ When comparing XML with `comments: :ignore`, comment differences are classified
26
+ as informative (they don't affect equivalence). Using `show_diffs: :normative`
27
+ hides these comment diffs while showing only structural/content differences.
28
+
29
+ [example]
30
+ ====
31
+ [source,ruby]
32
+ ----
33
+ xml1 = <<~XML
34
+ <root>
35
+ <!-- Old comment -->
36
+ <element>value1</element>
37
+ </root>
38
+ XML
39
+
40
+ xml2 = <<~XML
41
+ <root>
42
+ <!-- New comment -->
43
+ <element>value2</element>
44
+ </root>
45
+ XML
46
+
47
+ # With comments: :ignore and show_diffs: :normative
48
+ result = Canon::Comparison.equivalent?(xml1, xml2,
49
+ verbose: true,
50
+ match: { comments: :ignore },
51
+ show_diffs: :normative
52
+ )
53
+
54
+ # Result:
55
+ # - equivalent? => false (element value differs)
56
+ # - Diff output shows: only the element value change
57
+ # - Diff output hides: comment differences (informative)
58
+ ----
59
+ ====
60
+
61
+ == Filtering modes
62
+
63
+ The `show_diffs` parameter accepts three values:
64
+
65
+ === All differences (`:all`)
66
+
67
+ **Default mode**. Shows both normative and informative differences.
68
+
69
+ [source,ruby]
70
+ ----
71
+ Canon::Comparison.equivalent?(doc1, doc2,
72
+ verbose: true,
73
+ show_diffs: :all # or omit (default)
74
+ )
75
+ ----
76
+
77
+ Use when:
78
+
79
+ * You want to see every difference
80
+ * Debugging to understand all changes
81
+ * Initial comparison to assess document similarity
82
+
83
+ === Normative differences only (`:normative`)
84
+
85
+ Shows only differences that affect equivalence.
86
+
87
+ [source,ruby]
88
+ ----
89
+ Canon::Comparison.equivalent?(doc1, doc2,
90
+ verbose: true,
91
+ show_diffs: :normative
92
+ )
93
+ ----
94
+
95
+ Use when:
96
+
97
+ * Focusing on changes that make documents non-equivalent
98
+ * Hiding informative diffs (e.g., comments when ignored)
99
+ * Clean output for CI/CD pipelines
100
+ * Reviewing semantic changes only
101
+
102
+ === Informative differences only (`:informative`)
103
+
104
+ Shows only differences that don't affect equivalence.
105
+
106
+ [source,ruby]
107
+ ----
108
+ Canon::Comparison.equivalent?(doc1, doc2,
109
+ verbose: true,
110
+ show_diffs: :informative
111
+ )
112
+ ----
113
+
114
+ Use when:
115
+
116
+ * Reviewing non-semantic changes
117
+ * Checking comment differences
118
+ * Auditing metadata changes
119
+ * Verifying ignored dimensions are truly informative
120
+
121
+ == Visual distinction: Informative vs normative diffs
122
+
123
+ Canon visually distinguishes informative from normative diffs using different symbols and colors:
124
+
125
+ === Normative diffs (affect equivalence)
126
+
127
+ * **Symbols**: `-` (red) for deletions, `+` (green) for additions
128
+ * **Colors**: Red for removed lines, green for added lines
129
+ * **Meaning**: These differences cause documents to be non-equivalent
130
+
131
+ [example]
132
+ ====
133
+ [source]
134
+ ----
135
+ 4| -| <item>Old</item> # Red - (normative deletion)
136
+ | 5+| <item>New</item> # Green + (normative addition)
137
+ ----
138
+ ====
139
+
140
+ === Informative diffs (don't affect equivalence)
141
+
142
+ * **Symbol**: `~` (tilde) in cyan/blue
143
+ * **Color**: Cyan (blue) for both removed and added content
144
+ * **Meaning**: These differences are ignored based on match options
145
+
146
+ [example]
147
+ ====
148
+ [source]
149
+ ----
150
+ 4| ~| <!-- Old comment --> # Cyan ~ (informative)
151
+ | 5~| <!-- New comment --> # Cyan ~ (informative)
152
+ ----
153
+ ====
154
+
155
+ This visual distinction makes it immediately clear which diffs affect equivalence and which are informational only.
156
+
157
+ .Common scenario: Attribute order with spec_friendly profile
158
+ [example]
159
+ ====
160
+ When using the `spec_friendly` profile, attribute order is informative:
161
+
162
+ [source]
163
+ ----
164
+ 4| ~| <el attr2="b" attr1="a"/> # Cyan ~ (informative)
165
+ | 5~| <el attr1="a" attr2="b"/> # Cyan ~ (informative)
166
+ ----
167
+
168
+ The cyan color and `~` symbol indicate this differs does not affect equivalence in the `spec_friendly` profile.
169
+ ====
170
+
171
+ == Usage examples
172
+
173
+ === Ruby API
174
+
175
+ [source,ruby]
176
+ ----
177
+ require 'canon/comparison'
178
+
179
+ # Show all differences
180
+ result = Canon::Comparison.equivalent?(xml1, xml2,
181
+ verbose: true,
182
+ match: { comments: :ignore },
183
+ show_diffs: :all
184
+ )
185
+
186
+ # Show only normative differences
187
+ result = Canon::Comparison.equivalent?(xml1, xml2,
188
+ verbose: true,
189
+ match: { comments: :ignore },
190
+ show_diffs: :normative
191
+ )
192
+
193
+ # Show only informative differences
194
+ result = Canon::Comparison.equivalent?(xml1, xml2,
195
+ verbose: true,
196
+ match: { comments: :ignore },
197
+ show_diffs: :informative
198
+ )
199
+
200
+ # Access via DiffFormatter directly
201
+ formatter = Canon::DiffFormatter.new(
202
+ use_color: true,
203
+ mode: :by_object,
204
+ show_diffs: :normative
205
+ )
206
+ output = formatter.format(result, :xml)
207
+ ----
208
+
209
+ === Command-line interface
210
+
211
+ [source,bash]
212
+ ----
213
+ # Show all differences (default)
214
+ $ canon diff file1.xml file2.xml
215
+
216
+ # Show only normative differences
217
+ $ canon diff file1.xml file2.xml --show-diffs normative
218
+
219
+ # Show only informative differences
220
+ $ canon diff file1.xml file2.xml --show-diffs informative
221
+
222
+ # Combined with match options
223
+ $ canon diff file1.xml file2.xml \
224
+ --comments ignore \
225
+ --show-diffs normative
226
+ ----
227
+
228
+ === RSpec matchers
229
+
230
+ [source,ruby]
231
+ ----
232
+ require 'canon/rspec_matchers'
233
+
234
+ RSpec.describe 'XML comparison' do
235
+ it 'matches equivalent documents' do
236
+ # Show all differences on failure
237
+ expect(actual).to be_xml_equivalent_to(expected)
238
+ .show_diffs(:all)
239
+ end
240
+
241
+ it 'shows only normative differences' do
242
+ expect(actual).to be_xml_equivalent_to(expected,
243
+ match: { comments: :ignore }
244
+ ).show_diffs(:normative)
245
+ end
246
+
247
+ it 'shows only informative differences' do
248
+ expect(actual).to be_xml_equivalent_to(expected,
249
+ match: { comments: :ignore }
250
+ ).show_diffs(:informative)
251
+ end
252
+ end
253
+ ----
254
+
255
+ === Configuration
256
+
257
+ Set default for all comparisons:
258
+
259
+ [source,ruby]
260
+ ----
261
+ Canon::Config.configure do |config|
262
+ config.xml.diff.show_diffs = :normative
263
+ end
264
+
265
+ # Now all XML comparisons use normative-only by default
266
+ result = Canon::Comparison.equivalent?(xml1, xml2, verbose: true)
267
+ ----
268
+
269
+ == Relationship to equivalence
270
+
271
+ IMPORTANT: Display filtering does NOT affect equivalence determination.
272
+ Equivalence is always based on normative differences only, regardless of the
273
+ `show_diffs` setting.
274
+
275
+ [source,ruby]
276
+ ----
277
+ xml1 = "<root><!-- Comment A --><el>value</el></root>"
278
+ xml2 = "<root><!-- Comment B --><el>value</el></root>"
279
+
280
+ # All three produce the same equivalence result
281
+ result_all = Canon::Comparison.equivalent?(xml1, xml2,
282
+ verbose: true,
283
+ match: { comments: :ignore },
284
+ show_diffs: :all
285
+ )
286
+
287
+ result_normative = Canon::Comparison.equivalent?(xml1, xml2,
288
+ verbose: true,
289
+ match: { comments: :ignore },
290
+ show_diffs: :normative
291
+ )
292
+
293
+ result_informative = Canon::Comparison.equivalent?(xml1, xml2,
294
+ verbose: true,
295
+ match: { comments: :ignore },
296
+ show_diffs: :informative
297
+ )
298
+
299
+ # All return true (only comment diffs, which are informative)
300
+ result_all.equivalent? # => true
301
+ result_normative.equivalent? # => true
302
+ result_informative.equivalent? # => true
303
+
304
+ # Only diff output differs:
305
+ # - result_all: shows comment diffs
306
+ # - result_normative: hides comment diffs
307
+ # - result_informative: shows comment diffs
308
+ ----
309
+
310
+ == How it works
311
+
312
+ The filtering operates at the display layer:
313
+
314
+ . **Comparison phase**: All differences are detected and classified as
315
+ normative or informative based on match options
316
+ . **Equivalence determination**: Only normative differences affect the
317
+ equivalence result
318
+ . **Display phase**: The `show_diffs` parameter filters which differences
319
+ appear in formatted output
320
+
321
+ .Diff pipeline with display filtering
322
+ [source]
323
+ ----
324
+ Input Documents
325
+
326
+
327
+ Preprocessing (optional)
328
+
329
+
330
+ Semantic Matching
331
+
332
+
333
+ Diff Detection & Classification
334
+
335
+ ├──► Normative DiffNodes
336
+
337
+ └──► Informative DiffNodes
338
+
339
+
340
+ Equivalence Determination
341
+ (based on normative diffs only)
342
+
343
+
344
+ Display Filtering ◄── show_diffs parameter
345
+ (filter which diffs to show)
346
+
347
+
348
+ Formatted Output
349
+ ----
350
+
351
+ == Match dimensions and informativeness
352
+
353
+ Different match dimension settings affect which diffs are normative vs
354
+ informative:
355
+
356
+ [cols="2,1,3"]
357
+ |===
358
+ |Dimension |Setting |Diff Classification
359
+
360
+ |`comments`
361
+ |`:strict`
362
+ |Normative (affects equivalence)
363
+
364
+ |`comments`
365
+ |`:ignore`
366
+ |Informative (doesn't affect equivalence)
367
+
368
+ |`text_content`
369
+ |`:strict`
370
+ |Normative
371
+
372
+ |`text_content`
373
+ |`:normalize`
374
+ |Normative (but normalized first)
375
+
376
+ |`structural_whitespace`
377
+ |`:strict`
378
+ |Normative
379
+
380
+ |`structural_whitespace`
381
+ |`:ignore`
382
+ |Informative
383
+
384
+ |`attribute_whitespace`
385
+ |`:strict`
386
+ |Normative
387
+
388
+ |`attribute_whitespace`
389
+ |`:normalize`
390
+ |Normative (but normalized first)
391
+
392
+ |`attribute_order`
393
+ |`:strict`
394
+ |Normative
395
+
396
+ |`attribute_order`
397
+ |`:ignore`
398
+ |Informative
399
+
400
+ |`key_order`
401
+ |`:strict`
402
+ |Normative (JSON/YAML)
403
+
404
+ |`key_order`
405
+ |`:ignore`
406
+ |Informative (JSON/YAML)
407
+ |===
408
+
409
+ == Best practices
410
+
411
+ === In test suites
412
+
413
+ Use `show_diffs: :normative` to reduce noise in test failures:
414
+
415
+ [source,ruby]
416
+ ----
417
+ Canon::Config.configure do |config|
418
+ config.xml.match.profile = :spec_friendly
419
+ config.xml.diff.show_diffs = :normative
420
+ end
421
+ ----
422
+
423
+ === In CI/CD pipelines
424
+
425
+ Use `show_diffs: :normative` for cleaner output:
426
+
427
+ [source,bash]
428
+ ----
429
+ #!/bin/bash
430
+ canon diff expected.xml actual.xml \
431
+ --match-profile spec_friendly \
432
+ --show-diffs normative
433
+ ----
434
+
435
+ === During development
436
+
437
+ Use `show_diffs: :all` to see everything while debugging:
438
+
439
+ [source,ruby]
440
+ ----
441
+ result = Canon::Comparison.equivalent?(doc1, doc2,
442
+ verbose: true,
443
+ show_diffs: :all
444
+ )
445
+ ----
446
+
447
+ === For auditing
448
+
449
+ Use `show_diffs: :informative` to verify ignored dimensions don't have
450
+ unexpected changes:
451
+
452
+ [source,ruby]
453
+ ----
454
+ result = Canon::Comparison.equivalent?(doc1, doc2,
455
+ verbose: true,
456
+ match: { comments: :ignore },
457
+ show_diffs: :informative
458
+ )
459
+
460
+ # Review comment changes that were ignored for equivalence
461
+ puts result.differences.count # Number of informative diffs
462
+ ----
463
+
464
+ == See also
465
+
466
+ * link:../match-options/index.adoc[Match options] - Configure match dimensions
467
+ * link:colors-and-symbols.adoc[Colors and symbols] - Understanding diff
468
+ visualization
469
+ * link:../../../understanding/algorithms/index.adoc[Diff algorithms] -
470
+ Algorithm-specific behavior
471
+ * link:../../../advanced/diff-classification.adoc[Diff classification] -
472
+ Normative vs informative classification
@@ -0,0 +1,140 @@
1
+ ---
2
+ title: Diff Formatting
3
+ parent: Features
4
+ nav_order: 2
5
+ has_children: true
6
+ ---
7
+ = Diff formatting
8
+ :toc:
9
+ :toclevels: 2
10
+
11
+ == Purpose
12
+
13
+ Canon provides extensive options for customizing diff output to make
14
+ differences clear, actionable, and easy to understand.
15
+
16
+ This section covers all aspects of diff output formatting, from basic color
17
+ schemes to advanced filtering options.
18
+
19
+ == Features overview
20
+
21
+ Canon's diff formatting includes:
22
+
23
+ * **Display filtering**: Control which differences appear in output based on
24
+ whether they affect equivalence
25
+ * **Colors and symbols**: Visual indicators for different types of changes
26
+ * **Character visualization**: Make invisible characters visible
27
+ * **Context and grouping**: Control how much surrounding context to show
28
+ * **Algorithm-specific output**: Different output styles for different diff
29
+ algorithms
30
+
31
+ == Available formatting options
32
+
33
+ === Display filtering
34
+
35
+ Filter which differences appear in output while maintaining correct equivalence
36
+ determination.
37
+
38
+ * Show all differences (default)
39
+ * Show only normative differences (affect equivalence)
40
+ * Show only informative differences (don't affect equivalence)
41
+
42
+ See link:display-filtering.adoc[Display filtering] for complete details.
43
+
44
+ === Colors and symbols
45
+
46
+ Canon uses color-coded output to distinguish different types of changes:
47
+
48
+ * Red: Normative deletions
49
+ * Green: Normative additions
50
+ * Yellow: Normative structural changes
51
+ * Cyan: Informative differences
52
+
53
+ See link:colors-and-symbols.adoc[Colors and symbols] for details.
54
+
55
+ === Character visualization
56
+
57
+ Make invisible characters visible in diff output:
58
+
59
+ * Whitespace visualization (spaces, tabs, newlines)
60
+ * Non-ASCII character detection
61
+ * CJK-safe Unicode symbols
62
+
63
+ See link:character-visualization.adoc[Character visualization] for details.
64
+
65
+ === Context and grouping
66
+
67
+ Control how much surrounding context to show:
68
+
69
+ * Context lines: Number of unchanged lines around changes
70
+ * Grouping: Combine nearby changes into single blocks
71
+
72
+ See link:context-and-grouping.adoc[Context and grouping] for details.
73
+
74
+ === Algorithm-specific output
75
+
76
+ Different diff algorithms produce different output styles:
77
+
78
+ * DOM diff: Line-by-line or by-object output
79
+ * Semantic tree diff: Operation-based output with tree structure
80
+
81
+ See link:algorithm-specific-output.adoc[Algorithm-specific output] for details.
82
+
83
+ == Common use cases
84
+
85
+ === Testing
86
+
87
+ Focus on actionable differences by filtering informative diffs:
88
+
89
+ [source,ruby]
90
+ ----
91
+ Canon::Config.configure do |config|
92
+ config.xml.diff.show_diffs = :normative
93
+ config.xml.diff.use_color = true
94
+ end
95
+ ----
96
+
97
+ === Debugging
98
+
99
+ See all differences with maximum context:
100
+
101
+ [source,ruby]
102
+ ----
103
+ result = Canon::Comparison.equivalent?(doc1, doc2,
104
+ verbose: true,
105
+ show_diffs: :all
106
+ )
107
+ ----
108
+
109
+ === CI/CD pipelines
110
+
111
+ Clean, focused output for automated testing:
112
+
113
+ [source,bash]
114
+ ----
115
+ canon diff expected.xml actual.xml \
116
+ --show-diffs normative \
117
+ --no-color
118
+ ----
119
+
120
+ == Configuration
121
+
122
+ Diff formatting can be configured:
123
+
124
+ * Globally via `Canon::Config.configure`
125
+ * Per-format (XML, HTML, JSON, YAML)
126
+ * Per-operation via method parameters
127
+
128
+ See link:../../reference/cli-options.adoc[CLI options] and
129
+ link:../../interfaces/ruby-api/index.adoc[Ruby API] for configuration details.
130
+
131
+ == See also
132
+
133
+ * link:../../understanding/comparison-pipeline.adoc[Comparison pipeline] -
134
+ Understanding the diff generation process
135
+ * link:../match-options/index.adoc[Match options] - Controlling what gets
136
+ compared
137
+ * link:../../advanced/diff-classification.adoc[Diff classification] -
138
+ Normative vs informative differences
139
+ * link:../../interfaces/cli/index.adoc[CLI interface] - Command-line usage
140
+ * link:../../interfaces/ruby-api/index.adoc[Ruby API] - Programmatic usage