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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +163 -67
- data/README.adoc +400 -7
- data/docs/Gemfile +9 -0
- data/docs/INDEX.adoc +99 -182
- data/docs/_config.yml +100 -0
- data/docs/advanced/diff-classification.adoc +547 -0
- data/docs/advanced/diff-pipeline.adoc +358 -0
- data/docs/advanced/index.adoc +214 -0
- data/docs/advanced/semantic-diff-report.adoc +390 -0
- data/docs/{VERBOSE.adoc → advanced/verbose-mode-architecture.adoc} +51 -53
- data/docs/features/diff-formatting/algorithm-specific-output.adoc +533 -0
- data/docs/{CHARACTER_VISUALIZATION.adoc → features/diff-formatting/character-visualization.adoc} +23 -62
- data/docs/features/diff-formatting/colors-and-symbols.adoc +606 -0
- data/docs/features/diff-formatting/context-and-grouping.adoc +490 -0
- data/docs/features/diff-formatting/display-filtering.adoc +472 -0
- data/docs/features/diff-formatting/index.adoc +140 -0
- data/docs/features/environment-configuration/index.adoc +327 -0
- data/docs/features/environment-configuration/override-system.adoc +436 -0
- data/docs/features/environment-configuration/size-limits.adoc +273 -0
- data/docs/features/index.adoc +173 -0
- data/docs/features/input-validation/index.adoc +521 -0
- data/docs/features/match-options/algorithm-specific-behavior.adoc +365 -0
- data/docs/features/match-options/html-policies.adoc +312 -0
- data/docs/features/match-options/index.adoc +621 -0
- data/docs/getting-started/index.adoc +83 -0
- data/docs/getting-started/quick-start.adoc +76 -0
- data/docs/guides/choosing-configuration.adoc +689 -0
- data/docs/guides/index.adoc +181 -0
- data/docs/{CLI.adoc → interfaces/cli/index.adoc} +18 -13
- data/docs/interfaces/index.adoc +101 -0
- data/docs/{RSPEC.adoc → interfaces/rspec/index.adoc} +242 -31
- data/docs/{RUBY_API.adoc → interfaces/ruby-api/index.adoc} +118 -16
- data/docs/lychee.toml +65 -0
- data/docs/reference/cli-options.adoc +418 -0
- data/docs/reference/environment-variables.adoc +375 -0
- data/docs/reference/index.adoc +204 -0
- data/docs/reference/options-across-interfaces.adoc +417 -0
- data/docs/understanding/algorithms/dom-diff.adoc +389 -0
- data/docs/understanding/algorithms/index.adoc +314 -0
- data/docs/understanding/algorithms/semantic-tree-diff.adoc +533 -0
- data/docs/understanding/architecture.adoc +447 -0
- data/docs/understanding/comparison-pipeline.adoc +317 -0
- data/docs/understanding/formats/html.adoc +380 -0
- data/docs/understanding/formats/index.adoc +261 -0
- data/docs/understanding/formats/json.adoc +390 -0
- data/docs/understanding/formats/xml.adoc +366 -0
- data/docs/understanding/formats/yaml.adoc +504 -0
- data/docs/understanding/index.adoc +130 -0
- data/lib/canon/cli.rb +42 -1
- data/lib/canon/commands/diff_command.rb +108 -23
- data/lib/canon/comparison/compare_profile.rb +101 -0
- data/lib/canon/comparison/comparison_result.rb +41 -2
- data/lib/canon/comparison/html_comparator.rb +292 -71
- data/lib/canon/comparison/html_compare_profile.rb +117 -0
- data/lib/canon/comparison/match_options.rb +42 -4
- data/lib/canon/comparison/strategies/base_match_strategy.rb +99 -0
- data/lib/canon/comparison/strategies/match_strategy_factory.rb +74 -0
- data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +220 -0
- data/lib/canon/comparison/xml_comparator.rb +695 -91
- data/lib/canon/comparison.rb +207 -2
- data/lib/canon/config/env_provider.rb +71 -0
- data/lib/canon/config/env_schema.rb +58 -0
- data/lib/canon/config/override_resolver.rb +55 -0
- data/lib/canon/config/type_converter.rb +59 -0
- data/lib/canon/config.rb +158 -29
- data/lib/canon/data_model.rb +29 -0
- data/lib/canon/diff/diff_classifier.rb +74 -14
- data/lib/canon/diff/diff_context_builder.rb +41 -0
- data/lib/canon/diff/diff_line.rb +18 -2
- data/lib/canon/diff/diff_node.rb +18 -3
- data/lib/canon/diff/diff_node_mapper.rb +71 -12
- data/lib/canon/diff/formatting_detector.rb +53 -0
- data/lib/canon/diff_formatter/by_line/base_formatter.rb +60 -5
- data/lib/canon/diff_formatter/by_line/html_formatter.rb +68 -16
- data/lib/canon/diff_formatter/by_line/json_formatter.rb +0 -37
- data/lib/canon/diff_formatter/by_line/simple_formatter.rb +0 -42
- data/lib/canon/diff_formatter/by_line/xml_formatter.rb +116 -31
- data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +0 -37
- data/lib/canon/diff_formatter/by_object/base_formatter.rb +126 -19
- data/lib/canon/diff_formatter/by_object/xml_formatter.rb +30 -1
- data/lib/canon/diff_formatter/debug_output.rb +7 -1
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +674 -57
- data/lib/canon/diff_formatter/legend.rb +42 -0
- data/lib/canon/diff_formatter.rb +78 -9
- data/lib/canon/errors.rb +56 -0
- data/lib/canon/formatters/html_formatter_base.rb +35 -1
- data/lib/canon/formatters/json_formatter.rb +3 -0
- data/lib/canon/formatters/yaml_formatter.rb +3 -0
- data/lib/canon/html/data_model.rb +229 -0
- data/lib/canon/html.rb +9 -0
- data/lib/canon/options/cli_generator.rb +70 -0
- data/lib/canon/options/registry.rb +234 -0
- data/lib/canon/rspec_matchers.rb +34 -13
- data/lib/canon/tree_diff/adapters/html_adapter.rb +316 -0
- data/lib/canon/tree_diff/adapters/json_adapter.rb +204 -0
- data/lib/canon/tree_diff/adapters/xml_adapter.rb +285 -0
- data/lib/canon/tree_diff/adapters/yaml_adapter.rb +213 -0
- data/lib/canon/tree_diff/core/attribute_comparator.rb +84 -0
- data/lib/canon/tree_diff/core/matching.rb +241 -0
- data/lib/canon/tree_diff/core/node_signature.rb +164 -0
- data/lib/canon/tree_diff/core/node_weight.rb +135 -0
- data/lib/canon/tree_diff/core/tree_node.rb +450 -0
- data/lib/canon/tree_diff/matchers/hash_matcher.rb +258 -0
- data/lib/canon/tree_diff/matchers/similarity_matcher.rb +168 -0
- data/lib/canon/tree_diff/matchers/structural_propagator.rb +242 -0
- data/lib/canon/tree_diff/matchers/universal_matcher.rb +220 -0
- data/lib/canon/tree_diff/operation_converter.rb +631 -0
- data/lib/canon/tree_diff/operations/operation.rb +92 -0
- data/lib/canon/tree_diff/operations/operation_detector.rb +626 -0
- data/lib/canon/tree_diff/tree_diff_integrator.rb +140 -0
- data/lib/canon/tree_diff.rb +33 -0
- data/lib/canon/validators/json_validator.rb +3 -1
- data/lib/canon/validators/yaml_validator.rb +3 -1
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/data_model.rb +22 -23
- data/lib/canon/xml/element_matcher.rb +128 -20
- data/lib/canon/xml/namespace_helper.rb +110 -0
- data/lib/canon.rb +3 -0
- metadata +81 -23
- data/_config.yml +0 -116
- data/docs/ADVANCED_TOPICS.adoc +0 -20
- data/docs/BASIC_USAGE.adoc +0 -16
- data/docs/CUSTOMIZING_BEHAVIOR.adoc +0 -19
- data/docs/DIFF_ARCHITECTURE.adoc +0 -435
- data/docs/DIFF_FORMATTING.adoc +0 -540
- data/docs/FORMATS.adoc +0 -447
- data/docs/INPUT_VALIDATION.adoc +0 -477
- data/docs/MATCH_ARCHITECTURE.adoc +0 -463
- data/docs/MATCH_OPTIONS.adoc +0 -719
- data/docs/MODES.adoc +0 -432
- data/docs/NORMATIVE_INFORMATIVE_DIFFS.adoc +0 -219
- data/docs/OPTIONS.adoc +0 -1387
- data/docs/PREPROCESSING.adoc +0 -491
- data/docs/SEMANTIC_DIFF_REPORT.adoc +0 -528
- data/docs/UNDERSTANDING_CANON.adoc +0 -17
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
layout: default
|
|
3
3
|
title: RSpec Matchers
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
parent: Interfaces
|
|
5
|
+
nav_order: 3
|
|
6
|
+
has_children: true
|
|
6
7
|
---
|
|
7
8
|
= Canon RSpec matchers
|
|
8
9
|
:toc:
|
|
@@ -14,9 +15,9 @@ This document describes how to use Canon's RSpec matchers for testing. Canon
|
|
|
14
15
|
provides semantic comparison matchers that focus on content rather than
|
|
15
16
|
formatting.
|
|
16
17
|
|
|
17
|
-
For Ruby API usage, see link
|
|
18
|
+
For Ruby API usage, see link:../ruby-api/[Ruby API documentation].
|
|
18
19
|
|
|
19
|
-
For command-line usage, see link
|
|
20
|
+
For command-line usage, see link:../cli/[CLI documentation].
|
|
20
21
|
|
|
21
22
|
== General
|
|
22
23
|
|
|
@@ -147,7 +148,7 @@ end
|
|
|
147
148
|
|
|
148
149
|
Available profiles: `:strict`, `:rendered`, `:spec_friendly`, `:content_only`
|
|
149
150
|
|
|
150
|
-
See link
|
|
151
|
+
See link:../../features/match-options/[Match options] for profile details.
|
|
151
152
|
====
|
|
152
153
|
|
|
153
154
|
.Match dimension options
|
|
@@ -175,7 +176,7 @@ Canon::RSpecMatchers.configure do |config|
|
|
|
175
176
|
end
|
|
176
177
|
----
|
|
177
178
|
|
|
178
|
-
See link
|
|
179
|
+
See link:../../features/match-options/[Match options] for dimension reference.
|
|
179
180
|
====
|
|
180
181
|
|
|
181
182
|
=== Diff configuration
|
|
@@ -200,7 +201,7 @@ Canon::RSpecMatchers.configure do |config|
|
|
|
200
201
|
end
|
|
201
202
|
----
|
|
202
203
|
|
|
203
|
-
See link
|
|
204
|
+
See link:../../understanding/diff-modes/[Diff modes] for mode details.
|
|
204
205
|
====
|
|
205
206
|
|
|
206
207
|
.Diff formatting
|
|
@@ -221,7 +222,7 @@ Canon::RSpecMatchers.configure do |config|
|
|
|
221
222
|
end
|
|
222
223
|
----
|
|
223
224
|
|
|
224
|
-
See link
|
|
225
|
+
See link:../../features/diff-formatting/[Diff formatting] for options.
|
|
225
226
|
====
|
|
226
227
|
|
|
227
228
|
=== Complete configuration example
|
|
@@ -339,7 +340,7 @@ end
|
|
|
339
340
|
----
|
|
340
341
|
====
|
|
341
342
|
|
|
342
|
-
|
|
343
|
+
=== Verbose output
|
|
343
344
|
|
|
344
345
|
Use `verbose: true` to show detailed diff output on test failures.
|
|
345
346
|
|
|
@@ -371,14 +372,238 @@ end
|
|
|
371
372
|
----
|
|
372
373
|
====
|
|
373
374
|
|
|
375
|
+
=== Display filtering
|
|
376
|
+
|
|
377
|
+
Use `.show_diffs()` to control which differences appear in failure output.
|
|
378
|
+
|
|
379
|
+
.Display filtering modes
|
|
380
|
+
[example]
|
|
381
|
+
====
|
|
382
|
+
[source,ruby]
|
|
383
|
+
----
|
|
384
|
+
RSpec.describe 'Display filtering' do
|
|
385
|
+
it 'shows all differences (default)' do
|
|
386
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml)
|
|
387
|
+
.show_diffs(:all)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
it 'shows only normative differences' do
|
|
391
|
+
# Only show differences that affect equivalence
|
|
392
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml)
|
|
393
|
+
.show_diffs(:normative)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
it 'shows only informative differences' do
|
|
397
|
+
# Only show differences that don't affect equivalence
|
|
398
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml,
|
|
399
|
+
match: { comments: :ignore }
|
|
400
|
+
).show_diffs(:informative)
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
----
|
|
404
|
+
====
|
|
405
|
+
|
|
406
|
+
.Combining with match options
|
|
407
|
+
[example]
|
|
408
|
+
====
|
|
409
|
+
[source,ruby]
|
|
410
|
+
----
|
|
411
|
+
RSpec.describe 'Combined filtering' do
|
|
412
|
+
it 'ignores comments but shows only normative diffs' do
|
|
413
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml)
|
|
414
|
+
.with_options(comments: :ignore)
|
|
415
|
+
.show_diffs(:normative)
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
it 'uses spec_friendly profile with normative filtering' do
|
|
419
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml)
|
|
420
|
+
.with_profile(:spec_friendly)
|
|
421
|
+
.show_diffs(:normative)
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
----
|
|
425
|
+
====
|
|
426
|
+
|
|
427
|
+
IMPORTANT: Display filtering does NOT affect equivalence determination. It
|
|
428
|
+
only controls which differences appear in the failure output. Equivalence is
|
|
429
|
+
always based on normative differences only.
|
|
430
|
+
|
|
431
|
+
See link:../../features/diff-formatting/display-filtering.adoc[Display
|
|
432
|
+
filtering] for complete details.
|
|
433
|
+
|
|
434
|
+
== Diff algorithms
|
|
435
|
+
|
|
436
|
+
Canon supports two diff algorithms that can be selected based on your needs:
|
|
437
|
+
|
|
438
|
+
* **`:dom`** (default): Positional, DOM-based matching
|
|
439
|
+
* **`:semantic`**: Tree-based matching with operation detection
|
|
440
|
+
|
|
441
|
+
=== DOM algorithm
|
|
442
|
+
|
|
443
|
+
The DOM algorithm performs positional matching and is the default behavior:
|
|
444
|
+
|
|
445
|
+
.DOM algorithm usage
|
|
446
|
+
[example]
|
|
447
|
+
====
|
|
448
|
+
[source,ruby]
|
|
449
|
+
----
|
|
450
|
+
RSpec.describe 'DOM algorithm' do
|
|
451
|
+
it 'uses positional matching by default' do
|
|
452
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
it 'explicitly specifies DOM algorithm' do
|
|
456
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml,
|
|
457
|
+
diff_algorithm: :dom,
|
|
458
|
+
verbose: true
|
|
459
|
+
)
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
----
|
|
463
|
+
====
|
|
464
|
+
|
|
465
|
+
=== Semantic algorithm
|
|
466
|
+
|
|
467
|
+
The semantic algorithm uses tree-based matching and detects operations like
|
|
468
|
+
insert, delete, update, move, merge, and split:
|
|
469
|
+
|
|
470
|
+
.Semantic algorithm usage
|
|
471
|
+
[example]
|
|
472
|
+
====
|
|
473
|
+
[source,ruby]
|
|
474
|
+
----
|
|
475
|
+
RSpec.describe 'Semantic algorithm' do
|
|
476
|
+
it 'detects semantic operations' do
|
|
477
|
+
xml1 = '<root><a>1</a><b>2</b></root>'
|
|
478
|
+
xml2 = '<root><b>2</b><a>1</a><c>3</c></root>'
|
|
479
|
+
|
|
480
|
+
expect(xml1).to be_xml_equivalent_to(xml2,
|
|
481
|
+
diff_algorithm: :semantic,
|
|
482
|
+
verbose: true
|
|
483
|
+
)
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
it 'identifies element moves' do
|
|
487
|
+
html1 = '<div><p>First</p><p>Second</p></div>'
|
|
488
|
+
html2 = '<div><p>Second</p><p>First</p></div>'
|
|
489
|
+
|
|
490
|
+
expect(html1).to be_html_equivalent_to(html2,
|
|
491
|
+
diff_algorithm: :semantic,
|
|
492
|
+
verbose: true
|
|
493
|
+
)
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
it 'detects insertions and deletions' do
|
|
497
|
+
json1 = '{"users": [{"id": 1}, {"id": 2}]}'
|
|
498
|
+
json2 = '{"users": [{"id": 1}, {"id": 2}, {"id": 3}]}'
|
|
499
|
+
|
|
500
|
+
expect(json1).to be_json_equivalent_to(json2,
|
|
501
|
+
diff_algorithm: :semantic,
|
|
502
|
+
verbose: true
|
|
503
|
+
)
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
----
|
|
507
|
+
====
|
|
508
|
+
|
|
509
|
+
=== Global algorithm configuration
|
|
510
|
+
|
|
511
|
+
Configure the diff algorithm globally:
|
|
512
|
+
|
|
513
|
+
.Global diff algorithm configuration
|
|
514
|
+
[example]
|
|
515
|
+
====
|
|
516
|
+
[source,ruby]
|
|
517
|
+
----
|
|
518
|
+
# spec_helper.rb
|
|
519
|
+
Canon::RSpecMatchers.configure do |config|
|
|
520
|
+
# Use semantic algorithm for XML by default
|
|
521
|
+
config.xml.diff.algorithm = :semantic
|
|
522
|
+
|
|
523
|
+
# Use DOM algorithm for HTML (default)
|
|
524
|
+
config.html.diff.algorithm = :dom
|
|
525
|
+
|
|
526
|
+
# Use semantic algorithm for JSON
|
|
527
|
+
config.json.diff.algorithm = :semantic
|
|
528
|
+
end
|
|
529
|
+
----
|
|
530
|
+
====
|
|
531
|
+
|
|
532
|
+
=== Per-test algorithm override
|
|
533
|
+
|
|
534
|
+
Override the global algorithm configuration for specific tests:
|
|
535
|
+
|
|
536
|
+
.Per-test algorithm override
|
|
537
|
+
[example]
|
|
538
|
+
====
|
|
539
|
+
[source,ruby]
|
|
540
|
+
----
|
|
541
|
+
RSpec.describe 'Algorithm override' do
|
|
542
|
+
# Global config uses :semantic
|
|
543
|
+
# But this test uses :dom
|
|
544
|
+
it 'uses DOM algorithm for this specific test' do
|
|
545
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml,
|
|
546
|
+
diff_algorithm: :dom,
|
|
547
|
+
verbose: true
|
|
548
|
+
)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
# Global config uses :dom
|
|
552
|
+
# But this test uses :semantic
|
|
553
|
+
it 'uses semantic algorithm to detect operations' do
|
|
554
|
+
expect(actual_html).to be_html_equivalent_to(expected_html,
|
|
555
|
+
diff_algorithm: :semantic,
|
|
556
|
+
verbose: true
|
|
557
|
+
)
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
----
|
|
561
|
+
====
|
|
562
|
+
|
|
563
|
+
=== Combining algorithm with other options
|
|
564
|
+
|
|
565
|
+
The diff algorithm can be combined with match profiles and options:
|
|
566
|
+
|
|
567
|
+
.Algorithm with profiles and options
|
|
568
|
+
[example]
|
|
569
|
+
----
|
|
570
|
+
RSpec.describe 'Combined configuration' do
|
|
571
|
+
it 'uses semantic algorithm with spec_friendly profile' do
|
|
572
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml,
|
|
573
|
+
diff_algorithm: :semantic,
|
|
574
|
+
verbose: true
|
|
575
|
+
)
|
|
576
|
+
.with_profile(:spec_friendly)
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
it 'uses semantic algorithm with custom match options' do
|
|
580
|
+
expect(actual_xml).to be_xml_equivalent_to(expected_xml,
|
|
581
|
+
diff_algorithm: :semantic,
|
|
582
|
+
verbose: true
|
|
583
|
+
)
|
|
584
|
+
.with_options(
|
|
585
|
+
structural_whitespace: :ignore,
|
|
586
|
+
comments: :ignore
|
|
587
|
+
)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
it 'uses DOM algorithm with strict matching' do
|
|
591
|
+
expect(actual_html).to be_html_equivalent_to(expected_html,
|
|
592
|
+
diff_algorithm: :dom,
|
|
593
|
+
verbose: true
|
|
594
|
+
)
|
|
595
|
+
.with_profile(:strict)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
----
|
|
599
|
+
====
|
|
600
|
+
|
|
374
601
|
== Common patterns
|
|
375
602
|
|
|
376
603
|
=== Testing XML generation
|
|
377
604
|
|
|
378
605
|
.XML generation tests
|
|
379
606
|
[example]
|
|
380
|
-
====
|
|
381
|
-
[source,ruby]
|
|
382
607
|
----
|
|
383
608
|
RSpec.describe 'XML generation' do
|
|
384
609
|
let(:expected_xml) do
|
|
@@ -414,8 +639,6 @@ end
|
|
|
414
639
|
|
|
415
640
|
.HTML output tests
|
|
416
641
|
[example]
|
|
417
|
-
====
|
|
418
|
-
[source,ruby]
|
|
419
642
|
----
|
|
420
643
|
RSpec.describe 'HTML generation' do
|
|
421
644
|
let(:expected_html) do
|
|
@@ -462,8 +685,6 @@ end
|
|
|
462
685
|
|
|
463
686
|
.JSON API tests
|
|
464
687
|
[example]
|
|
465
|
-
====
|
|
466
|
-
[source,ruby]
|
|
467
688
|
----
|
|
468
689
|
RSpec.describe 'API responses' do
|
|
469
690
|
let(:expected_response) do
|
|
@@ -498,8 +719,6 @@ end
|
|
|
498
719
|
|
|
499
720
|
.Configuration file tests
|
|
500
721
|
[example]
|
|
501
|
-
====
|
|
502
|
-
[source,ruby]
|
|
503
722
|
----
|
|
504
723
|
RSpec.describe 'Configuration files' do
|
|
505
724
|
it 'generates correct YAML config' do
|
|
@@ -538,8 +757,6 @@ detail:
|
|
|
538
757
|
|
|
539
758
|
.Debugging example
|
|
540
759
|
[example]
|
|
541
|
-
====
|
|
542
|
-
[source,ruby]
|
|
543
760
|
----
|
|
544
761
|
it 'shows exactly what differs' do
|
|
545
762
|
expect(actual).to be_xml_equivalent_to(expected, verbose: true)
|
|
@@ -553,14 +770,12 @@ The diff output will show:
|
|
|
553
770
|
* Color-coded changes (red/green)
|
|
554
771
|
* Whitespace visualization
|
|
555
772
|
* Non-ASCII character warnings
|
|
556
|
-
|
|
773
|
+
----
|
|
557
774
|
|
|
558
775
|
=== Temporarily disabling global config
|
|
559
776
|
|
|
560
777
|
.Override global config
|
|
561
778
|
[example]
|
|
562
|
-
====
|
|
563
|
-
[source,ruby]
|
|
564
779
|
----
|
|
565
780
|
it 'uses different config for this test' do
|
|
566
781
|
# Global config uses spec_friendly, but we want strict here
|
|
@@ -572,14 +787,11 @@ it 'uses different config for this test' do
|
|
|
572
787
|
)
|
|
573
788
|
end
|
|
574
789
|
----
|
|
575
|
-
====
|
|
576
790
|
|
|
577
791
|
=== Checking what's being compared
|
|
578
792
|
|
|
579
793
|
.Debug preprocessed content
|
|
580
794
|
[example]
|
|
581
|
-
====
|
|
582
|
-
[source,ruby]
|
|
583
795
|
----
|
|
584
796
|
# In your test, temporarily add:
|
|
585
797
|
result = Canon::Comparison.equivalent?(actual, expected, verbose: true)
|
|
@@ -594,12 +806,11 @@ puts result[:preprocessed][1]
|
|
|
594
806
|
puts "Differences:"
|
|
595
807
|
pp result[:differences]
|
|
596
808
|
----
|
|
597
|
-
====
|
|
598
809
|
|
|
599
810
|
== See also
|
|
600
811
|
|
|
601
|
-
* link
|
|
602
|
-
* link
|
|
603
|
-
* link
|
|
604
|
-
* link
|
|
605
|
-
* link
|
|
812
|
+
* link:../ruby-api/[Ruby API documentation]
|
|
813
|
+
* link:../cli/[Command-line interface]
|
|
814
|
+
* link:../../features/match-options/[Match options reference]
|
|
815
|
+
* link:../../understanding/diff-modes/[Diff modes]
|
|
816
|
+
* link:../../features/diff-formatting/[Diff formatting options]
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
layout: default
|
|
3
3
|
title: Ruby API
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
parent: Interfaces
|
|
5
|
+
nav_order: 1
|
|
6
|
+
has_children: true
|
|
7
7
|
---
|
|
8
8
|
= Canon Ruby API
|
|
9
9
|
:toc:
|
|
@@ -14,9 +14,9 @@ grand_parent: Documentation Index
|
|
|
14
14
|
This document describes how to use Canon from Ruby code. It covers formatting,
|
|
15
15
|
parsing, and comparison APIs.
|
|
16
16
|
|
|
17
|
-
For command-line usage, see link
|
|
17
|
+
For command-line usage, see link:../cli/[CLI documentation].
|
|
18
18
|
|
|
19
|
-
For RSpec testing, see link
|
|
19
|
+
For RSpec testing, see link:../rspec/[RSpec documentation].
|
|
20
20
|
|
|
21
21
|
== General
|
|
22
22
|
|
|
@@ -188,7 +188,7 @@ The comparison uses depth-first traversal of DOM trees (XML/HTML) or object
|
|
|
188
188
|
graphs (JSON/YAML), comparing nodes/values based on configurable match
|
|
189
189
|
dimensions.
|
|
190
190
|
|
|
191
|
-
See link
|
|
191
|
+
See link:../../features/match-options/[Match options] for details on match dimensions and
|
|
192
192
|
profiles.
|
|
193
193
|
|
|
194
194
|
=== Basic comparison
|
|
@@ -210,7 +210,14 @@ Returns:
|
|
|
210
210
|
|
|
211
211
|
* `true` if documents are semantically equivalent
|
|
212
212
|
* `false` if documents differ
|
|
213
|
-
* `
|
|
213
|
+
* `ComparisonResult` object if `verbose: true`
|
|
214
|
+
|
|
215
|
+
Options:
|
|
216
|
+
|
|
217
|
+
* `diff_algorithm`: `:dom` (default) or `:semantic` - chooses the diff algorithm
|
|
218
|
+
* `verbose`: `true` or `false` - returns detailed results when true
|
|
219
|
+
* `match`: Hash of match dimension options
|
|
220
|
+
* `match_profile`: Symbol specifying a predefined profile
|
|
214
221
|
|
|
215
222
|
.Basic comparison examples
|
|
216
223
|
[example]
|
|
@@ -262,7 +269,7 @@ Canon::Comparison.equivalent?(obj1, obj2,
|
|
|
262
269
|
)
|
|
263
270
|
----
|
|
264
271
|
|
|
265
|
-
See link
|
|
272
|
+
See link:../../features/match-options/[Match options] for complete dimension reference.
|
|
266
273
|
|
|
267
274
|
.Match option examples
|
|
268
275
|
[example]
|
|
@@ -398,6 +405,103 @@ result = Canon::Comparison.equivalent?(xml1, xml2,
|
|
|
398
405
|
----
|
|
399
406
|
====
|
|
400
407
|
|
|
408
|
+
=== Display filtering
|
|
409
|
+
|
|
410
|
+
Use the `show_diffs` parameter to control which differences appear in formatted
|
|
411
|
+
output.
|
|
412
|
+
|
|
413
|
+
Syntax:
|
|
414
|
+
|
|
415
|
+
[source,ruby]
|
|
416
|
+
----
|
|
417
|
+
Canon::Comparison.equivalent?(obj1, obj2,
|
|
418
|
+
verbose: true,
|
|
419
|
+
show_diffs: :mode
|
|
420
|
+
)
|
|
421
|
+
----
|
|
422
|
+
|
|
423
|
+
Where `mode` is one of:
|
|
424
|
+
|
|
425
|
+
`:all`:: Show all differences (default)
|
|
426
|
+
`:normative`:: Show only differences that affect equivalence
|
|
427
|
+
`:informative`:: Show only differences that don't affect equivalence
|
|
428
|
+
|
|
429
|
+
.Display filtering examples
|
|
430
|
+
[example]
|
|
431
|
+
====
|
|
432
|
+
[source,ruby]
|
|
433
|
+
----
|
|
434
|
+
# Show all differences (default)
|
|
435
|
+
result = Canon::Comparison.equivalent?(xml1, xml2,
|
|
436
|
+
verbose: true,
|
|
437
|
+
show_diffs: :all
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
# Show only normative differences
|
|
441
|
+
result = Canon::Comparison.equivalent?(xml1, xml2,
|
|
442
|
+
verbose: true,
|
|
443
|
+
match: { comments: :ignore },
|
|
444
|
+
show_diffs: :normative
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
# Show only informative differences
|
|
448
|
+
result = Canon::Comparison.equivalent?(xml1, xml2,
|
|
449
|
+
verbose: true,
|
|
450
|
+
match: { comments: :ignore },
|
|
451
|
+
show_diffs: :informative
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
# Use with DiffFormatter directly
|
|
455
|
+
formatter = Canon::DiffFormatter.new(
|
|
456
|
+
use_color: true,
|
|
457
|
+
mode: :by_object,
|
|
458
|
+
show_diffs: :normative
|
|
459
|
+
)
|
|
460
|
+
output = formatter.format(result, :xml)
|
|
461
|
+
----
|
|
462
|
+
====
|
|
463
|
+
|
|
464
|
+
IMPORTANT: Display filtering does NOT affect equivalence determination. It
|
|
465
|
+
only controls which differences appear in formatted output. Equivalence is
|
|
466
|
+
always based on normative differences only, regardless of the `show_diffs`
|
|
467
|
+
setting.
|
|
468
|
+
|
|
469
|
+
.Common use case: XML comments
|
|
470
|
+
[example]
|
|
471
|
+
====
|
|
472
|
+
[source,ruby]
|
|
473
|
+
----
|
|
474
|
+
xml1 = <<~XML
|
|
475
|
+
<root>
|
|
476
|
+
<!-- Old comment -->
|
|
477
|
+
<element>value1</element>
|
|
478
|
+
</root>
|
|
479
|
+
XML
|
|
480
|
+
|
|
481
|
+
xml2 = <<~XML
|
|
482
|
+
<root>
|
|
483
|
+
<!-- New comment -->
|
|
484
|
+
<element>value2</element>
|
|
485
|
+
</root>
|
|
486
|
+
XML
|
|
487
|
+
|
|
488
|
+
# With comments: :ignore and show_diffs: :normative
|
|
489
|
+
result = Canon::Comparison.equivalent?(xml1, xml2,
|
|
490
|
+
verbose: true,
|
|
491
|
+
match: { comments: :ignore },
|
|
492
|
+
show_diffs: :normative
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
# Result:
|
|
496
|
+
# - equivalent? => false (element value differs)
|
|
497
|
+
# - Diff output shows: only the element value change
|
|
498
|
+
# - Diff output hides: comment differences (informative)
|
|
499
|
+
----
|
|
500
|
+
====
|
|
501
|
+
|
|
502
|
+
See link:../../features/diff-formatting/display-filtering.adoc[Display
|
|
503
|
+
filtering] for complete details.
|
|
504
|
+
|
|
401
505
|
=== Format-specific comparators
|
|
402
506
|
|
|
403
507
|
You can use format-specific comparator classes directly.
|
|
@@ -414,8 +518,6 @@ Canon::Comparison::YamlComparator.equivalent?(obj1, obj2, options)
|
|
|
414
518
|
|
|
415
519
|
.Format-specific comparator examples
|
|
416
520
|
[example]
|
|
417
|
-
====
|
|
418
|
-
[source,ruby]
|
|
419
521
|
----
|
|
420
522
|
# XML comparison with strict attribute order
|
|
421
523
|
Canon::Comparison::XmlComparator.equivalent?(xml1, xml2,
|
|
@@ -467,12 +569,12 @@ end
|
|
|
467
569
|
----
|
|
468
570
|
====
|
|
469
571
|
|
|
470
|
-
See link
|
|
572
|
+
See link:../../features/input-validation/[Input validation] for details.
|
|
471
573
|
|
|
472
574
|
== See also
|
|
473
575
|
|
|
474
|
-
* link
|
|
475
|
-
* link
|
|
476
|
-
* link
|
|
477
|
-
* link
|
|
478
|
-
* link
|
|
576
|
+
* link:../cli/[Command-line interface]
|
|
577
|
+
* link:../rspec/[RSpec matchers]
|
|
578
|
+
* link:../../features/match-options/[Match options reference]
|
|
579
|
+
* link:../../understanding/formats/[Format support details]
|
|
580
|
+
* link:../../features/input-validation/[Input validation]
|
data/docs/lychee.toml
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Lychee Link Checker Configuration
|
|
2
|
+
# For Canon Documentation
|
|
3
|
+
# https://github.com/lycheeverse/lychee
|
|
4
|
+
|
|
5
|
+
# Cache results to avoid re-checking same URLs
|
|
6
|
+
cache = true
|
|
7
|
+
max_cache_age = "1d"
|
|
8
|
+
|
|
9
|
+
# Check both source files and built site
|
|
10
|
+
include_verbatim = true
|
|
11
|
+
|
|
12
|
+
# Recursively check all files
|
|
13
|
+
recursive = true
|
|
14
|
+
|
|
15
|
+
# File types to check
|
|
16
|
+
include = [
|
|
17
|
+
"_site/**/*.html"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
# Excluded paths
|
|
21
|
+
exclude = [
|
|
22
|
+
".git",
|
|
23
|
+
".github",
|
|
24
|
+
"node_modules",
|
|
25
|
+
"vendor",
|
|
26
|
+
".bundle",
|
|
27
|
+
".sass-cache",
|
|
28
|
+
".jekyll-cache"
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
# Link checking behavior
|
|
32
|
+
max_redirects = 10
|
|
33
|
+
max_retries = 3
|
|
34
|
+
timeout = 30
|
|
35
|
+
|
|
36
|
+
# Accept status codes
|
|
37
|
+
accept = [
|
|
38
|
+
"100..=103", # Informational
|
|
39
|
+
"200..=299", # Success
|
|
40
|
+
"429" # Too Many Requests (retry handled by max_retries)
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
# User agent to identify ourselves
|
|
44
|
+
user_agent = "lychee/canon-docs-link-checker"
|
|
45
|
+
|
|
46
|
+
# Check HTTP, HTTPS, and file:// schemes
|
|
47
|
+
scheme = ["https", "http", "file"]
|
|
48
|
+
|
|
49
|
+
# Include file:// URLs for local link checking
|
|
50
|
+
include_file = true
|
|
51
|
+
|
|
52
|
+
# Handle different link types
|
|
53
|
+
include_mail = false # Don't check mailto: links
|
|
54
|
+
|
|
55
|
+
# Maximum concurrent requests
|
|
56
|
+
max_concurrency = 10
|
|
57
|
+
|
|
58
|
+
# Verbose output for debugging
|
|
59
|
+
verbose = "info"
|
|
60
|
+
|
|
61
|
+
# Require HTTPS where possible
|
|
62
|
+
require_https = false # Don't enforce
|
|
63
|
+
|
|
64
|
+
# Index files
|
|
65
|
+
index_files = ["index.html"]
|