canon 0.3.27 → 0.3.29

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/README.adoc +3 -0
  4. data/docs/INDEX.adoc +1 -1
  5. data/docs/advanced/diff-classification.adoc +1 -1
  6. data/docs/advanced/extending-canon.adoc +1 -1
  7. data/docs/advanced/index.adoc +6 -6
  8. data/docs/advanced/verbose-mode-architecture.adoc +1 -1
  9. data/docs/features/configuration-profiles.adoc +4 -4
  10. data/docs/features/diff-formatting/algorithm-specific-output.adoc +5 -5
  11. data/docs/features/diff-formatting/colors-and-symbols.adoc +4 -4
  12. data/docs/features/diff-formatting/comment-asymmetry.adoc +3 -3
  13. data/docs/features/diff-formatting/display-filtering.adoc +4 -4
  14. data/docs/features/diff-formatting/display-preprocessing.adoc +7 -7
  15. data/docs/features/diff-formatting/index.adoc +16 -16
  16. data/docs/features/diff-formatting/pretty-diff-mode.adoc +4 -4
  17. data/docs/features/diff-formatting/themes.adoc +2 -2
  18. data/docs/features/diff-formatting/whitespace-adjacency.adoc +3 -3
  19. data/docs/features/environment-configuration/index.adoc +8 -8
  20. data/docs/features/environment-configuration/override-system.adoc +5 -5
  21. data/docs/features/environment-configuration/size-limits.adoc +4 -4
  22. data/docs/features/index.adoc +1 -1
  23. data/docs/features/match-options/algorithm-specific-behavior.adoc +5 -5
  24. data/docs/features/match-options/html-policies.adoc +1 -1
  25. data/docs/features/match-options/index.adoc +7 -7
  26. data/docs/features/match-options/pretty-printed-fixtures.adoc +4 -4
  27. data/docs/features/regenerate-expected.adoc +157 -0
  28. data/docs/guides/choosing-configuration.adoc +6 -6
  29. data/docs/interfaces/rspec/index.adoc +1 -1
  30. data/docs/interfaces/ruby-api/index.adoc +1 -1
  31. data/docs/internals/diffnode-enrichment.adoc +1 -1
  32. data/docs/internals/index.adoc +4 -4
  33. data/docs/reference/cli-options.adoc +4 -4
  34. data/docs/reference/environment-variables.adoc +1 -1
  35. data/docs/understanding/algorithms/dom-diff.adoc +9 -9
  36. data/docs/understanding/algorithms/index.adoc +11 -11
  37. data/docs/understanding/algorithms/semantic-tree-diff.adoc +7 -7
  38. data/docs/understanding/architecture.adoc +9 -9
  39. data/docs/understanding/comparison-pipeline.adoc +7 -7
  40. data/docs/understanding/formats/html.adoc +5 -5
  41. data/docs/understanding/formats/index.adoc +5 -5
  42. data/docs/understanding/formats/json.adoc +5 -5
  43. data/docs/understanding/formats/xml.adoc +4 -4
  44. data/docs/understanding/formats/yaml.adoc +5 -5
  45. data/lib/canon/comparison/diff_node_builder.rb +9 -0
  46. data/lib/canon/config/env_schema.rb +6 -0
  47. data/lib/canon/rebaseliner/atomic_writer.rb +32 -0
  48. data/lib/canon/rebaseliner/call_site_resolver.rb +126 -0
  49. data/lib/canon/rebaseliner/heredoc_locator.rb +140 -0
  50. data/lib/canon/rebaseliner/heredoc_rewriter.rb +56 -0
  51. data/lib/canon/rebaseliner/heredoc_target.rb +19 -0
  52. data/lib/canon/rebaseliner/logger.rb +24 -0
  53. data/lib/canon/rebaseliner.rb +162 -0
  54. data/lib/canon/rspec_matchers.rb +101 -23
  55. data/lib/canon/version.rb +1 -1
  56. metadata +10 -2
@@ -0,0 +1,157 @@
1
+ ---
2
+ title: Regenerating expected heredocs
3
+ parent: Features
4
+ nav_order: 50
5
+ ---
6
+ = Regenerating expected heredocs
7
+ :toc:
8
+ :toclevels: 3
9
+
10
+ == Purpose
11
+
12
+ When a Canon matcher (`be_xml_equivalent_to`, `be_html_equivalent_to`, etc.)
13
+ asserts equivalence against a heredoc-literal `expected`, and the
14
+ upstream code legitimately changes its output, the fixture heredoc
15
+ needs to be updated to the new value. The default workflow is:
16
+
17
+ 1. Run `bundle exec rspec` — see N failing assertions.
18
+ 2. Copy the prettyprinted received from canon's diff display.
19
+ 3. Paste into the `<<~XML ... XML` heredoc in the spec file.
20
+ 4. Re-run, iterate.
21
+
22
+ For large fixture suites (e.g. the metanorma stack — 200+ heredocs per
23
+ rebaseline event) this is slow and error-prone (indent drift, partial
24
+ copies, missed trailing whitespace).
25
+
26
+ The `CANON_REGENERATE_EXPECTED=true` env var collapses steps 2-3 into
27
+ an automated rewrite.
28
+
29
+ == Workflow
30
+
31
+ [source,sh]
32
+ ----
33
+ CANON_REGENERATE_EXPECTED=true bundle exec rspec
34
+ git diff # review what changed
35
+ git commit -am "rebaseline fixtures after upstream X change"
36
+ ----
37
+
38
+ When the env var is set:
39
+
40
+ * Every failing `be_*_equivalent_to` assertion attempts to rewrite the
41
+ source heredoc that backs its `expected` argument.
42
+ * The rewrite uses the same `Canon::PrettyPrinter` that powers
43
+ `CANON_<FORMAT>_DIFF_SHOW_PRETTYPRINT_RECEIVED` — output is identical
44
+ to what would have appeared in the diff display.
45
+ * Successful rewrites mark the assertion as passing for the run, so CI
46
+ does not fail mid-rebaseline.
47
+ * Passing assertions are never touched.
48
+ * Negated matchers (`.not_to`) are never rewritten.
49
+
50
+ Each rewrite (or skip) emits a single-line log to stderr:
51
+
52
+ [source]
53
+ ----
54
+ [canon:rebaseline] rewritten /path/to/spec.rb:123
55
+ [canon:rebaseline] skipped_interpolation /path/to/spec.rb:456
56
+ ----
57
+
58
+ == Supported expected forms (v1)
59
+
60
+ The rebaseliner uses Prism to parse the caller spec file and locate the
61
+ heredoc backing the `expected` argument. It supports:
62
+
63
+ * `<<~XML` / `<<-XML` / `<<XML` heredoc assigned to a local variable in
64
+ the same `it` block.
65
+ * `<<~XML` / `<<-XML` / `<<XML` heredoc passed inline directly to the
66
+ matcher.
67
+ * *Multiple sequential assignments* to the same local variable within
68
+ one `it` block (the common metanorma pattern of reassigning `output`
69
+ before each format-specific expect). The rebaseliner walks backward
70
+ from the failing `expect` line to the *most-recent* assignment and
71
+ rewrites that one.
72
+ * Substitution chains on the actual side (e.g.
73
+ `expect(strip_guid(actual).gsub(...))`) — since the matcher receives
74
+ the post-substitution value, idempotency holds on the next run.
75
+
76
+ == Skipped with a warning (v1)
77
+
78
+ * Heredoc with `#{}` interpolation. Mechanical rewriting would lose
79
+ the interpolation; v2 (token preservation) is planned.
80
+ * Expected value from a method call (`load_fixture(...)`). The
81
+ expected is computed at runtime; the rebaseliner cannot identify
82
+ which on-disk fixture to rewrite.
83
+ * Expected value from a `let` or `shared_context` in a different
84
+ spec/support file. v1 does not cross file boundaries.
85
+ * Inline string literal expected (no heredoc). There is nothing to
86
+ re-indent into.
87
+
88
+ In each skipped case the file is left unchanged and the assertion
89
+ fails normally with the standard Canon diff display.
90
+
91
+ == Tracking line shifts across multiple rewrites
92
+
93
+ After a rewrite, the file's on-disk line numbering can shift if the new
94
+ heredoc body has a different line count from the old. Ruby's
95
+ `caller_locations` continues to report the *original* line numbers
96
+ during the same process run (the in-memory source is unchanged), so
97
+ the rebaseliner maintains a per-file cumulative line-shift tracker and
98
+ translates subsequent caller-reported lines accordingly. Multiple
99
+ rewrites within a single `it` block, or across multiple `it` blocks
100
+ in the same spec file, work transparently.
101
+
102
+ == Limitations and v2 roadmap
103
+
104
+ The following are intentionally out of v1 scope:
105
+
106
+ * `#{}` interpolation in heredoc bodies — v2 adds token-preserving
107
+ rewrites that re-anchor `#{var}` fragments in the prettyprinted
108
+ actual.
109
+ * JSON and YAML format prettyprinter wiring (v1 covers XML + HTML).
110
+ * A `canon regenerate SPEC_GLOB` Thor subcommand with a summary
111
+ report.
112
+ * File-locking for `parallel_rspec` safety. v1 documents "do not run
113
+ rebaseline mode in parallel."
114
+ * Optional `rubocop -A` post-rewrite formatter.
115
+
116
+ == Architecture
117
+
118
+ The rebaseliner is a self-contained module under
119
+ `lib/canon/rebaseliner/`:
120
+
121
+ `Canon::Rebaseliner`::
122
+ Top-level orchestrator. `enabled?` reads the env var.
123
+ `rewrite!` is the entry called by the matcher hook on failure.
124
+
125
+ `CallSiteResolver`::
126
+ Parses the spec file with Prism and locates the matcher invocation
127
+ on the failing line. Returns the AST node passed as `expected` and
128
+ the enclosing `it`/`example` block.
129
+
130
+ `HeredocLocator`::
131
+ Classifies the `expected` AST node. For local-variable references,
132
+ walks the enclosing block backward to find the most-recent
133
+ assignment. Returns a `HeredocSpec` describing the byte range to
134
+ rewrite, or a skip reason.
135
+
136
+ `HeredocRewriter`::
137
+ Re-indents the new body for `<<~` (squiggly) heredocs and writes the
138
+ new source via `AtomicWriter`.
139
+
140
+ `AtomicWriter`::
141
+ Tempfile-then-rename to avoid half-written files on Ctrl-C.
142
+
143
+ `Logger`::
144
+ Single-line stderr writes with the `[canon:rebaseline]` prefix.
145
+
146
+ The matcher hook lives in `lib/canon/rspec_matchers.rb`. It captures
147
+ `caller_locations` only when the env var is set, so passing
148
+ assertions pay no overhead.
149
+
150
+ == Testing the rebaseliner
151
+
152
+ `spec/canon/rebaseliner_spec.rb` runs each fixture under
153
+ `spec/fixtures/rebaseliner/` in a subprocess with the env var set,
154
+ then asserts the file content was (or was not) modified appropriately
155
+ and that the stderr log line is present. Add new fixture cases by
156
+ dropping `*_input.rb` into `spec/fixtures/rebaseliner/` and a new
157
+ example into `rebaseliner_spec.rb`.
@@ -216,7 +216,7 @@ Canon::Comparison.equivalent?(doc1, doc2,
216
216
  )
217
217
  ----
218
218
 
219
- **Remember**: Match options behave differently with each algorithm! See link:../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior].
219
+ **Remember**: Match options behave differently with each algorithm! See link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior].
220
220
 
221
221
  ==== Whitespace Type Sensitivity
222
222
 
@@ -709,14 +709,14 @@ Profiles bundle all layers (preprocessing, match profile, diff settings,
709
709
  whitespace element lists) into a named preset defined in YAML.
710
710
  Custom file profiles can inherit from built-in profiles.
711
711
 
712
- See link:../features/configuration-profiles.adoc[Configuration Profiles] for full documentation.
712
+ See link:../../features/configuration-profiles/[Configuration Profiles] for full documentation.
713
713
 
714
714
  == See Also
715
715
 
716
- * link:../features/configuration-profiles.adoc[Configuration Profiles] - Named config presets
717
- * link:../understanding/comparison-pipeline.adoc[Comparison Pipeline] - Understanding the 4 layers
716
+ * link:../../features/configuration-profiles/[Configuration Profiles] - Named config presets
717
+ * link:../../understanding/comparison-pipeline/[Comparison Pipeline] - Understanding the 4 layers
718
718
  * link:../understanding/algorithms/[Algorithms] - Detailed algorithm documentation
719
- * link:../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] - How algorithms differ
720
- * link:../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output] - Output format differences
719
+ * link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] - How algorithms differ
720
+ * link:../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output] - Output format differences
721
721
  * link:../features/match-options/[Match Options] - All matching options
722
722
  * link:../features/diff-formatting/[Diff Formatting] - Formatting options
@@ -428,7 +428,7 @@ IMPORTANT: Display filtering does NOT affect equivalence determination. It
428
428
  only controls which differences appear in the failure output. Equivalence is
429
429
  always based on normative differences only.
430
430
 
431
- See link:../../features/diff-formatting/display-filtering.adoc[Display
431
+ See link:../../features/diff-formatting/display-filtering/[Display
432
432
  filtering] for complete details.
433
433
 
434
434
  == Diff algorithms
@@ -545,7 +545,7 @@ result = Canon::Comparison.equivalent?(xml1, xml2,
545
545
  ----
546
546
  ====
547
547
 
548
- See link:../../features/diff-formatting/display-filtering.adoc[Display
548
+ See link:../../features/diff-formatting/display-filtering/[Display
549
549
  filtering] for complete details.
550
550
 
551
551
  === Format-specific comparators
@@ -606,7 +606,7 @@ The old API still works for backwards compatibility, but enriched properties pro
606
606
 
607
607
  == See also
608
608
 
609
- * link:../understanding/architecture.adoc[Architecture] - 4-layer architecture overview
609
+ * link:../../understanding/architecture/[Architecture] - 4-layer architecture overview
610
610
  * link:../understanding/algorithms/[Algorithms] - DOM and Semantic algorithm details
611
611
  * link:../features/diff-formatting/[Diff Formatting] - Layer 4 rendering options
612
612
  * link:diff-char-range-pipeline[DiffCharRange Pipeline] - How enriched DiffNodes are processed into character-level display positions
@@ -71,7 +71,7 @@ Canon separates comparison concerns into four layers:
71
71
 
72
72
  Only Layer 2 differs between algorithms, and the enriched DiffNode structure ensures clean communication between layers.
73
73
 
74
- See link:../understanding/architecture.adoc[Architecture] for the complete overview.
74
+ See link:../understanding/architecture/[Architecture] for the complete overview.
75
75
 
76
76
  === Enriched Metadata Flow
77
77
 
@@ -265,7 +265,7 @@ def add_difference(node1, node2, diff1, diff2, dimension, opts, differences)
265
265
  end
266
266
  ----
267
267
 
268
- See link:../understanding/algorithms/dom-diff.adoc[DOM Diff Algorithm] for details.
268
+ See link:../understanding/algorithms/dom-diff/[DOM Diff Algorithm] for details.
269
269
 
270
270
  === Semantic Algorithm
271
271
 
@@ -289,11 +289,11 @@ def convert_insert(operation)
289
289
  end
290
290
  ----
291
291
 
292
- See link:../understanding/algorithms/semantic-tree-diff.adoc[Semantic Tree Diff Algorithm] for details.
292
+ See link:../understanding/algorithms/semantic-tree-diff/[Semantic Tree Diff Algorithm] for details.
293
293
 
294
294
  == See Also
295
295
 
296
- * link:../understanding/architecture.adoc[Architecture] - 4-layer architecture overview
296
+ * link:../understanding/architecture/[Architecture] - 4-layer architecture overview
297
297
  * link:../understanding/algorithms/[Algorithms] - DOM and Semantic algorithm details
298
298
  * link:../features/diff-formatting/[Diff Formatting] - Layer 4 rendering options
299
299
  * link:../advanced/[Advanced Topics] - Deep technical documentation
@@ -11,9 +11,9 @@ nav_order: 1
11
11
 
12
12
  This page provides a complete reference for all Canon command-line interface options organized by command and function.
13
13
 
14
- For conceptual understanding, see link:../understanding/comparison-pipeline.adoc[Comparison Pipeline].
14
+ For conceptual understanding, see link:../../understanding/comparison-pipeline/[Comparison Pipeline].
15
15
 
16
- For choosing the right configuration, see link:../guides/choosing-configuration.adoc[Choosing Configuration].
16
+ For choosing the right configuration, see link:../../guides/choosing-configuration/[Choosing Configuration].
17
17
 
18
18
  == Command syntax
19
19
 
@@ -413,8 +413,8 @@ canon diff page1.html page2.html \
413
413
 
414
414
  == See also
415
415
 
416
- * link:../understanding/comparison-pipeline.adoc[Comparison Pipeline] - 4-layer architecture
417
- * link:../guides/choosing-configuration.adoc[Choosing Configuration] - Decision guide
416
+ * link:../../understanding/comparison-pipeline/[Comparison Pipeline] - 4-layer architecture
417
+ * link:../../guides/choosing-configuration/[Choosing Configuration] - Decision guide
418
418
  * link:../features/match-options/[Match Options] - Dimension reference
419
419
  * link:../features/diff-formatting/[Diff Formatting] - Output customization
420
420
  * link:../interfaces/cli/[CLI Interface] - Command-line usage guide
@@ -128,7 +128,7 @@ export CANON_JSON_FORMAT_PREPROCESSING=normalize
128
128
  |`CANON_XML_DIFF_PRETTY_PRINTED_EXPECTED`
129
129
  |boolean
130
130
  |`false`
131
- |When `true`, whitespace-only text nodes that start with `"\n"` inside `:collapse`-classified elements are dropped from the **expected (fixture)** document before it reaches the line diff. Solves the asymmetric case where the expected side is a hand-indented heredoc fixture but the received side is compact programmatic XML. Only applies when `display_preprocessing: :normalize_pretty_print`. Format-specific; no global form. See also link:../features/match-options/pretty-printed-fixtures.adoc[Pretty-printed fixture support].
131
+ |When `true`, whitespace-only text nodes that start with `"\n"` inside `:collapse`-classified elements are dropped from the **expected (fixture)** document before it reaches the line diff. Solves the asymmetric case where the expected side is a hand-indented heredoc fixture but the received side is compact programmatic XML. Only applies when `display_preprocessing: :normalize_pretty_print`. Format-specific; no global form. See also link:../../features/match-options/pretty-printed-fixtures/[Pretty-printed fixture support].
132
132
  |XML (display only)
133
133
 
134
134
  |`CANON_XML_DIFF_PRETTY_PRINTED_RECEIVED`
@@ -174,7 +174,7 @@ Canon::Comparison.equivalent?(doc1, doc2,
174
174
  )
175
175
  ----
176
176
 
177
- See link:../../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] for how DOM interprets match options.
177
+ See link:../../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] for how DOM interprets match options.
178
178
 
179
179
  === With Diff Formatting
180
180
 
@@ -289,7 +289,7 @@ The DOM algorithm cannot detect when content moves to a different position:
289
289
 
290
290
  **Limitation**: Reordered content shows as DELETE + INSERT pairs
291
291
 
292
- **Workaround**: Use link:semantic-tree-diff.adoc[Semantic Algorithm] for move detection
292
+ **Workaround**: Use link:../semantic-tree-diff/[Semantic Algorithm] for move detection
293
293
 
294
294
  === Position-Dependent
295
295
 
@@ -297,7 +297,7 @@ The algorithm assumes similar structure between documents:
297
297
 
298
298
  **Limitation**: Heavily restructured documents produce noisy diffs
299
299
 
300
- **Workaround**: Use link:semantic-tree-diff.adoc[Semantic Algorithm] for restructured documents
300
+ **Workaround**: Use link:../semantic-tree-diff/[Semantic Algorithm] for restructured documents
301
301
 
302
302
  == Common Use Cases
303
303
 
@@ -381,9 +381,9 @@ Canon::Comparison.equivalent?(html1, html2,
381
381
 
382
382
  == See Also
383
383
 
384
- * link:index.adoc[Algorithms Overview] - Comparison of DOM vs Semantic
385
- * link:semantic-tree-diff.adoc[Semantic Algorithm] - Alternative algorithm
386
- * link:../../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] - How DOM interprets options
387
- * link:../../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output] - Output format details
388
- * link:../../guides/choosing-configuration.adoc[Choosing Configuration] - Complete decision guide
389
- * link:../../advanced/dom-diff-internals.adoc[DOM Diff Internals] - Advanced implementation details (if available)
384
+ * link:../[Algorithms Overview] - Comparison of DOM vs Semantic
385
+ * link:../semantic-tree-diff/[Semantic Algorithm] - Alternative algorithm
386
+ * link:../../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] - How DOM interprets options
387
+ * link:../../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output] - Output format details
388
+ * link:../../../guides/choosing-configuration/[Choosing Configuration] - Complete decision guide
389
+ * link:../dom-diff/[DOM Diff] - Implementation details
@@ -12,7 +12,7 @@ has_children: true
12
12
 
13
13
  Canon provides two comparison algorithms, each with different strengths and use cases. This section explains how to choose between them and what to expect from each.
14
14
 
15
- This corresponds to **Layer 2 (Algorithm Selection)** in Canon's 4-layer architecture. See link:../comparison-pipeline.adoc[Comparison Pipeline] for the complete flow.
15
+ This corresponds to **Layer 2 (Algorithm Selection)** in Canon's 4-layer architecture. See link:../comparison-pipeline/[Comparison Pipeline] for the complete flow.
16
16
 
17
17
  == Overview
18
18
 
@@ -21,12 +21,12 @@ Canon supports two algorithms for document comparison:
21
21
  * **DOM Algorithm** - Fast, stable, positional comparison (default)
22
22
  * **Semantic Algorithm** - Slower, intelligent, detects moves and restructuring (experimental)
23
23
 
24
- **Critical**: The algorithm choice affects how Layers 3 and 4 behave. See link:../../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] and link:../../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output].
24
+ **Critical**: The algorithm choice affects how Layers 3 and 4 behave. See link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] and link:../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output].
25
25
 
26
26
  == Child Pages
27
27
 
28
- * link:dom-diff.adoc[DOM Algorithm] - Positional comparison details
29
- * link:semantic-tree-diff.adoc[Semantic Algorithm] - Tree-based comparison details
28
+ * link:dom-diff/[DOM Algorithm] - Positional comparison details
29
+ * link:semantic-tree-diff/[Semantic Algorithm] - Tree-based comparison details
30
30
 
31
31
  == Algorithm Comparison
32
32
 
@@ -249,7 +249,7 @@ NOTE: These are approximate times. Actual performance depends on document struct
249
249
  3. Performance slower but more intelligent
250
250
  4. Output format changes to operation-based
251
251
 
252
- See link:../../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] for migration details.
252
+ See link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] for migration details.
253
253
 
254
254
  === Switching from Semantic to DOM
255
255
 
@@ -306,9 +306,9 @@ end
306
306
 
307
307
  == See also
308
308
 
309
- * link:dom-diff.adoc[DOM Algorithm] - Detailed DOM algorithm documentation
310
- * link:semantic-tree-diff.adoc[Semantic Algorithm] - Detailed semantic algorithm documentation
311
- * link:../comparison-pipeline.adoc[Comparison Pipeline] - 4-layer architecture
312
- * link:../../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] - How algorithms interpret options
313
- * link:../../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output] - Output format differences
314
- * link:../../guides/choosing-configuration.adoc[Choosing Configuration] - Complete decision guide
309
+ * link:dom-diff/[DOM Algorithm] - Detailed DOM algorithm documentation
310
+ * link:semantic-tree-diff/[Semantic Algorithm] - Detailed semantic algorithm documentation
311
+ * link:../comparison-pipeline/[Comparison Pipeline] - 4-layer architecture
312
+ * link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] - How algorithms interpret options
313
+ * link:../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output] - Output format differences
314
+ * link:../../guides/choosing-configuration/[Choosing Configuration] - Complete decision guide
@@ -230,7 +230,7 @@ Canon::Comparison.equivalent?(doc1, doc2,
230
230
  )
231
231
  ----
232
232
 
233
- See link:../../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] for details.
233
+ See link:../../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] for details.
234
234
 
235
235
  === With Diff Formatting
236
236
 
@@ -525,9 +525,9 @@ When switching from DOM to Semantic:
525
525
 
526
526
  == See Also
527
527
 
528
- * link:index.adoc[Algorithms Overview] - Comparison of DOM vs Semantic
529
- * link:dom-diff.adoc[DOM Algorithm] - Standard algorithm
530
- * link:../../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] - How Semantic interprets options
531
- * link:../../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output] - Output format details
532
- * link:../../guides/choosing-configuration.adoc[Choosing Configuration] - Complete decision guide
533
- * link:../../advanced/semantic-tree-diff-internals.adoc[Semantic Tree Diff Internals] - Advanced details (if available)
528
+ * link:../[Algorithms Overview] - Comparison of DOM vs Semantic
529
+ * link:../dom-diff/[DOM Algorithm] - Standard algorithm
530
+ * link:../../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] - How Semantic interprets options
531
+ * link:../../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output] - Output format details
532
+ * link:../../../guides/choosing-configuration/[Choosing Configuration] - Complete decision guide
533
+ * link:../semantic-tree-diff/[Semantic Tree Diff] - Advanced details
@@ -11,9 +11,9 @@ nav_order: 1
11
11
 
12
12
  This document explains Canon's 4-layer comparison architecture and how documents flow through preprocessing, algorithm selection, semantic matching, and diff rendering.
13
13
 
14
- For a guided walkthrough of choosing configurations, see link:../guides/choosing-configuration.adoc[Choosing Configuration].
14
+ For a guided walkthrough of choosing configurations, see link:../../guides/choosing-configuration/[Choosing Configuration].
15
15
 
16
- For detailed 4-layer pipeline documentation, see link:comparison-pipeline.adoc[Comparison Pipeline].
16
+ For detailed 4-layer pipeline documentation, see link:../comparison-pipeline/[Comparison Pipeline].
17
17
 
18
18
  == Overview
19
19
 
@@ -799,7 +799,7 @@ Control how differences are displayed. **This layer is algorithm-specific** - ea
799
799
  * **DOM algorithm**: Generates line-based differences
800
800
  * **Semantic algorithm**: Generates operation-based differences (INSERT, DELETE, UPDATE, MOVE)
801
801
 
802
- See link:../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output] for detailed comparison.
802
+ See link:../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output] for detailed comparison.
803
803
 
804
804
  === Diff options
805
805
 
@@ -865,7 +865,7 @@ result = Canon::Comparison.equivalent?(doc1, doc2,
865
865
  )
866
866
  ----
867
867
 
868
- See link:comparison-pipeline.adoc[Comparison Pipeline] for layer-by-layer examples.
868
+ See link:../comparison-pipeline/[Comparison Pipeline] for layer-by-layer examples.
869
869
 
870
870
  === DiffNode: Representation of differences
871
871
 
@@ -1153,16 +1153,16 @@ This refactoring improves:
1153
1153
 
1154
1154
  == See also
1155
1155
 
1156
- * link:comparison-pipeline.adoc[Comparison Pipeline] - Complete 4-layer walkthrough
1156
+ * link:../comparison-pipeline/[Comparison Pipeline] - Complete 4-layer walkthrough
1157
1157
  * link:algorithms/[Algorithms] - DOM and Semantic algorithm details
1158
1158
  * link:../internals/[Internals] - Implementation details and data structures
1159
- * link:../internals/diffnode-enrichment.adoc[DiffNode Enrichment] - How metadata flows from Layer 2 to Layer 4
1159
+ * link:../../internals/diffnode-enrichment/[DiffNode Enrichment] - How metadata flows from Layer 2 to Layer 4
1160
1160
  * link:../features/preprocessing/[Preprocessing options]
1161
1161
  * link:../features/match-options/[Match dimensions and profiles]
1162
- * link:../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior]
1162
+ * link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior]
1163
1163
  * link:../features/diff-formatting/[Diff formatting]
1164
- * link:../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output]
1165
- * link:../guides/choosing-configuration.adoc[Choosing Configuration]
1164
+ * link:../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output]
1165
+ * link:../../guides/choosing-configuration/[Choosing Configuration]
1166
1166
  * link:../interfaces/ruby-api/[Ruby API documentation]
1167
1167
  * link:../interfaces/cli/[Command-line interface]
1168
1168
  * link:../interfaces/rspec/[RSpec matchers]
@@ -67,7 +67,7 @@ graph TD
67
67
  * Match profiles (preset combinations)
68
68
  * Algorithm-specific behaviors
69
69
 
70
- **Documentation**: See link:../features/match-options/[Match Options] and link:../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior]
70
+ **Documentation**: See link:../features/match-options/[Match Options] and link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior]
71
71
 
72
72
  === Layer 4: Diff Formatting
73
73
 
@@ -81,7 +81,7 @@ graph TD
81
81
  * Context and grouping
82
82
  * Character visualization
83
83
 
84
- **Documentation**: See link:../features/diff-formatting/[Diff Formatting] and link:../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output]
84
+ **Documentation**: See link:../features/diff-formatting/[Diff Formatting] and link:../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output]
85
85
 
86
86
  == DiffNode Data Flow
87
87
 
@@ -154,7 +154,7 @@ After creation, DiffNodes are enriched with metadata for Layer 4 rendering:
154
154
  * **NodeSerializer**: Library-agnostic serialization of node content
155
155
  * **Attribute extraction**: Normalized attribute hashes
156
156
 
157
- See link:../internals/diffnode-enrichment.adoc[DiffNode Enrichment] for implementation details.
157
+ See link:../../internals/diffnode-enrichment/[DiffNode Enrichment] for implementation details.
158
158
 
159
159
  === Layer 3: Classification
160
160
 
@@ -432,8 +432,8 @@ Canon::Comparison.equivalent?(doc1, doc2,
432
432
 
433
433
  == See Also
434
434
 
435
- * link:architecture.adoc[Architecture] - Overall system design
435
+ * link:../architecture/[Architecture] - Overall system design
436
436
  * link:algorithms/[Algorithms] - Detailed algorithm documentation
437
- * link:../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] - How algorithms interpret match options
438
- * link:../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output] - Different output formats
439
- * link:../guides/choosing-configuration.adoc[Choosing Configuration] - Decision guide for all layers
437
+ * link:../../features/match-options/algorithm-specific-behavior/[Algorithm-Specific Behavior] - How algorithms interpret match options
438
+ * link:../../features/diff-formatting/algorithm-specific-output/[Algorithm-Specific Output] - Different output formats
439
+ * link:../../guides/choosing-configuration/[Choosing Configuration] - Decision guide for all layers
@@ -396,9 +396,9 @@ XHTML is treated as XML and follows stricter rules.
396
396
 
397
397
  == See also
398
398
 
399
- * link:../comparison-pipeline.adoc[Comparison Pipeline] - Understanding the 4 layers
399
+ * link:../../comparison-pipeline/[Comparison Pipeline] - Understanding the 4 layers
400
400
  * link:../../features/match-options/[Match Options] - All matching options
401
- * link:../../guides/choosing-configuration.adoc[Choosing Configuration] - Decision guide
402
- * link:index.adoc[Format Support] - Overview of all formats
403
- * link:xml.adoc[XML Format] - XML-specific features
404
- * link:json.adoc[JSON Format] - JSON-specific features
401
+ * link:../../../guides/choosing-configuration/[Choosing Configuration] - Decision guide
402
+ * link:../[Format Support] - Overview of all formats
403
+ * link:../xml/[XML Format] - XML-specific features
404
+ * link:../json/[JSON Format] - JSON-specific features
@@ -20,10 +20,10 @@ Canon provides unified canonicalization and comparison for four serialization fo
20
20
 
21
21
  This page provides an overview of format support. See the child pages for format-specific details:
22
22
 
23
- * link:xml.adoc[XML Format] - W3C C14N, namespace handling
24
- * link:html.adoc[HTML Format] - HTML4/5 detection, rendering behavior
25
- * link:json.adoc[JSON Format] - Sorted keys, type preservation
26
- * link:yaml.adoc[YAML Format] - YAML specifics, anchors and aliases
23
+ * link:xml/[XML Format] - W3C C14N, namespace handling
24
+ * link:html/[HTML Format] - HTML4/5 detection, rendering behavior
25
+ * link:json/[JSON Format] - Sorted keys, type preservation
26
+ * link:yaml/[YAML Format] - YAML specifics, anchors and aliases
27
27
 
28
28
  == Format detection
29
29
 
@@ -257,5 +257,5 @@ Canon::Comparison::YamlComparator.equivalent?(yaml1, yaml2,
257
257
  * link:../../interfaces/ruby-api/[Ruby API documentation]
258
258
  * link:../../interfaces/cli/[Command-line interface]
259
259
  * link:../../features/match-options/[Match options reference]
260
- * link:../comparison-pipeline.adoc[Comparison Pipeline]
260
+ * link:../comparison-pipeline/[Comparison Pipeline]
261
261
  * link:../../features/preprocessing/[Preprocessing options]
@@ -382,9 +382,9 @@ Canon normalizes Unicode escapes during canonicalization.
382
382
 
383
383
  == See also
384
384
 
385
- * link:../comparison-pipeline.adoc[Comparison Pipeline] - Understanding the 4 layers
385
+ * link:../../comparison-pipeline/[Comparison Pipeline] - Understanding the 4 layers
386
386
  * link:../../features/match-options/[Match Options] - All matching options
387
- * link:../../guides/choosing-configuration.adoc[Choosing Configuration] - Decision guide
388
- * link:index.adoc[Format Support] - Overview of all formats
389
- * link:yaml.adoc[YAML Format] - YAML-specific features (similar to JSON)
390
- * link:xml.adoc[XML Format] - XML-specific features
387
+ * link:../../../guides/choosing-configuration/[Choosing Configuration] - Decision guide
388
+ * link:../[Format Support] - Overview of all formats
389
+ * link:../yaml/[YAML Format] - YAML-specific features (similar to JSON)
390
+ * link:../xml/[XML Format] - XML-specific features
@@ -439,8 +439,8 @@ canon diff expected.xml actual.xml \
439
439
 
440
440
  == See also
441
441
 
442
- * link:../comparison-pipeline.adoc[Comparison Pipeline] - Understanding the 4 layers
442
+ * link:../../comparison-pipeline/[Comparison Pipeline] - Understanding the 4 layers
443
443
  * link:../../features/match-options/[Match Options] - All matching options
444
- * link:../../guides/choosing-configuration.adoc[Choosing Configuration] - Decision guide
445
- * link:index.adoc[Format Support] - Overview of all formats
446
- * link:html.adoc[HTML Format] - HTML-specific features
444
+ * link:../../../guides/choosing-configuration/[Choosing Configuration] - Decision guide
445
+ * link:../[Format Support] - Overview of all formats
446
+ * link:../html/[HTML Format] - HTML-specific features
@@ -496,9 +496,9 @@ YAML is sensitive to indentation. Use `structural_whitespace: :ignore` to handle
496
496
 
497
497
  == See also
498
498
 
499
- * link:../comparison-pipeline.adoc[Comparison Pipeline] - Understanding the 4 layers
499
+ * link:../../comparison-pipeline/[Comparison Pipeline] - Understanding the 4 layers
500
500
  * link:../../features/match-options/[Match Options] - All matching options
501
- * link:../../guides/choosing-configuration.adoc[Choosing Configuration] - Decision guide
502
- * link:index.adoc[Format Support] - Overview of all formats
503
- * link:json.adoc[JSON Format] - JSON-specific features (similar to YAML)
504
- * link:xml.adoc[XML Format] - XML-specific features
501
+ * link:../../../guides/choosing-configuration/[Choosing Configuration] - Decision guide
502
+ * link:../[Format Support] - Overview of all formats
503
+ * link:../json/[JSON Format] - JSON-specific features (similar to YAML)
504
+ * link:../xml/[XML Format] - XML-specific features
@@ -179,6 +179,15 @@ module Canon
179
179
  return "whitespace: #{describe_whitespace(text1)} vs #{describe_whitespace(text2)}"
180
180
  end
181
181
 
182
+ # Identical content modulo whitespace: two full visualized
183
+ # copies read as materially different text when the only
184
+ # delta is trailing/invisible whitespace (#94) — the compact
185
+ # character-count description says what actually differs.
186
+ if text1.strip == text2.strip
187
+ return "whitespace-only: #{describe_whitespace(text1)} vs " \
188
+ "#{describe_whitespace(text2)}"
189
+ end
190
+
182
191
  "Text: \"#{visualize_whitespace(text1)}\" vs \"#{visualize_whitespace(text2)}\""
183
192
  end
184
193
 
@@ -21,6 +21,12 @@ module Canon
21
21
 
22
22
  FORMAT_ATTRIBUTE_TYPES = {
23
23
  preprocessing: :string,
24
+
25
+ # Rebaseliner: opt-in mode that rewrites failing heredoc
26
+ # expectations in spec files with the prettyprinted received
27
+ # value. Read directly by Canon::Rebaseliner.enabled?; schema
28
+ # entry exists for --env-help discoverability.
29
+ regenerate_expected: :boolean,
24
30
  }.freeze
25
31
 
26
32
  class << self