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,447 @@
1
+ ---
2
+ title: Architecture
3
+ parent: Understanding
4
+ nav_order: 1
5
+ ---
6
+ = Architecture
7
+ :toc:
8
+ :toclevels: 3
9
+
10
+ == Purpose
11
+
12
+ This document explains Canon's 4-layer comparison architecture and how documents flow through preprocessing, algorithm selection, semantic matching, and diff rendering.
13
+
14
+ For a guided walkthrough of choosing configurations, see link:../guides/choosing-configuration.adoc[Choosing Configuration].
15
+
16
+ For detailed 4-layer pipeline documentation, see link:comparison-pipeline.adoc[Comparison Pipeline].
17
+
18
+ == Overview
19
+
20
+ Canon uses a 4-layer architecture that separates concerns for clean, maintainable comparison logic:
21
+
22
+ . **Layer 1 - Preprocessing**: Optional document normalization
23
+ . **Layer 2 - Algorithm Selection**: Choose comparison strategy (DOM vs Semantic)
24
+ . **Layer 3 - Match Options**: Content comparison with configurable dimensions (algorithm-specific)
25
+ . **Layer 4 - Diff Formatting**: Formatted output with visualization (algorithm-specific)
26
+
27
+ Each layer is independent and configurable, allowing fine-grained control over comparison behavior.
28
+
29
+ **Key Insight**: Layers 3 and 4 are **algorithm-specific** - they behave differently depending on which algorithm (DOM or Semantic) is chosen in Layer 2.
30
+
31
+ == System architecture diagram
32
+
33
+ [mermaid]
34
+ ----
35
+ graph TD
36
+ A[Input Documents] --> B[Layer 1: Preprocessing]
37
+ B --> C[Layer 2: Algorithm Selection]
38
+ C --> D[Layer 3: Match Options]
39
+ D --> E[Layer 4: Diff Formatting]
40
+ E --> F[Output]
41
+
42
+ C -->|DOM Algorithm| D1[Positional Matching]
43
+ C -->|Semantic Algorithm| D2[Signature Matching]
44
+
45
+ D1 --> E1[Line-based Diff]
46
+ D2 --> E2[Operation-based Diff]
47
+
48
+ style B fill:#e1f5ff
49
+ style C fill:#fff4e1
50
+ style D fill:#ffe1f5
51
+ style E fill:#e1ffe1
52
+ ----
53
+
54
+ == Layer 1: Preprocessing
55
+
56
+ === Purpose
57
+
58
+ Transform documents into a normalized form before comparison. This eliminates format-specific variations that should not affect semantic equivalence.
59
+
60
+ === Options
61
+
62
+ `none` (default):: No preprocessing - compare documents as-is
63
+
64
+ `c14n`:: Canonical form:
65
+ * XML: W3C Canonical XML 1.1
66
+ * HTML: Normalized HTML structure
67
+ * JSON: Sorted keys, normalized whitespace
68
+ * YAML: Sorted keys, standard format
69
+
70
+ `normalize`:: Normalize whitespace:
71
+ * Collapse multiple whitespace to single space
72
+ * Trim leading/trailing whitespace
73
+ * Normalize line endings
74
+
75
+ `format`:: Pretty-print with standard formatting:
76
+ * 2-space indentation
77
+ * One element/property per line
78
+ * Consistent structure
79
+
80
+ === Usage
81
+
82
+ .Ruby API
83
+ [example]
84
+ ====
85
+ [source,ruby]
86
+ ----
87
+ Canon::Comparison.equivalent?(doc1, doc2,
88
+ preprocessing: :normalize
89
+ )
90
+ ----
91
+ ====
92
+
93
+ .CLI
94
+ [example]
95
+ ====
96
+ [source,bash]
97
+ ----
98
+ $ canon diff file1.xml file2.xml --preprocessing normalize
99
+ ----
100
+ ====
101
+
102
+ See link:../features/preprocessing/[Preprocessing documentation] for details.
103
+
104
+ == Layer 2: Algorithm selection
105
+
106
+ === Purpose
107
+
108
+ Choose the comparison strategy. This is a **critical decision** because it determines how Layers 3 and 4 behave.
109
+
110
+ === Options
111
+
112
+ `dom` (default):: DOM-based positional comparison
113
+ * Fast, stable, well-tested
114
+ * Position-based element matching
115
+ * No move detection
116
+ * Best for similar documents
117
+
118
+ `semantic` (experimental):: Tree-based semantic diff
119
+ * Slower but more intelligent
120
+ * Signature-based matching
121
+ * Detects moves, merges, splits
122
+ * Best for restructured documents
123
+
124
+ === Algorithm characteristics
125
+
126
+ [cols="2,3,3"]
127
+ |===
128
+ |Feature |DOM |Semantic
129
+
130
+ |**Stability**
131
+ |Stable (production-ready)
132
+ |Experimental
133
+
134
+ |**Performance**
135
+ |Fast (linear)
136
+ |Slower (quadratic worst case)
137
+
138
+ |**Move Detection**
139
+ |No
140
+ |Yes
141
+
142
+ |**Match Strategy**
143
+ |Positional
144
+ |Signature-based
145
+
146
+ |**Layer 3 Behavior**
147
+ |Element-by-element comparison
148
+ |Signature calculation
149
+
150
+ |**Layer 4 Behavior**
151
+ |Line-based differences
152
+ |Operation-based (INSERT, DELETE, UPDATE, MOVE)
153
+
154
+ |**Best For**
155
+ |Similar documents
156
+ |Restructured documents
157
+ |===
158
+
159
+ === Usage
160
+
161
+ .Ruby API
162
+ [example]
163
+ ====
164
+ [source,ruby]
165
+ ----
166
+ # DOM algorithm (default)
167
+ Canon::Comparison.equivalent?(doc1, doc2,
168
+ diff_algorithm: :dom
169
+ )
170
+
171
+ # Semantic algorithm
172
+ Canon::Comparison.equivalent?(doc1, doc2,
173
+ diff_algorithm: :semantic
174
+ )
175
+ ----
176
+ ====
177
+
178
+ .CLI
179
+ [example]
180
+ ====
181
+ [source,bash]
182
+ ----
183
+ # DOM algorithm
184
+ $ canon diff file1.xml file2.xml --diff-algorithm dom
185
+
186
+ # Semantic algorithm
187
+ $ canon diff file1.xml file2.xml --diff-algorithm semantic
188
+ ----
189
+ ====
190
+
191
+ See link:algorithms/[Algorithm documentation] for details.
192
+
193
+ == Layer 3: Match options
194
+
195
+ === Purpose
196
+
197
+ Configure what to compare and how strictly. **This layer is algorithm-specific** - each algorithm interprets match options differently.
198
+
199
+ === Match dimensions
200
+
201
+ Match dimensions are orthogonal aspects of documents that can be compared independently:
202
+
203
+ `text_content`:: Text within elements/values
204
+ `structural_whitespace`:: Whitespace between elements
205
+ `attribute_whitespace`:: Whitespace in attribute values (XML/HTML)
206
+ `attribute_order`:: Order of attributes (XML/HTML)
207
+ `attribute_values`:: Attribute value content (XML/HTML)
208
+ `key_order`:: Order of object keys (JSON/YAML)
209
+ `comments`:: Comment content and placement
210
+
211
+ Each dimension supports behaviors:
212
+
213
+ * `:strict` - Must match exactly
214
+ * `:normalize` - Match after normalization
215
+ * `:ignore` - Don't compare
216
+
217
+ === Match profiles
218
+
219
+ Profiles are predefined combinations of dimension settings for common scenarios:
220
+
221
+ `:strict`:: Exact matching - all dimensions use `:strict` behavior
222
+ `:rendered`:: Browser rendering - ignores formatting that doesn't affect display
223
+ `:spec_friendly`:: Test-friendly - ignores formatting, focuses on content
224
+ `:content_only`:: Maximum tolerance - only semantic content matters
225
+
226
+ === Algorithm-specific behavior
227
+
228
+ **Critical**: The same match options behave differently with each algorithm!
229
+
230
+ * **DOM algorithm**: Uses options for positional element comparison
231
+ * **Semantic algorithm**: Uses options during signature calculation
232
+
233
+ See link:../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] for detailed comparison.
234
+
235
+ === Usage
236
+
237
+ .With dimensions
238
+ [example]
239
+ ====
240
+ [source,ruby]
241
+ ----
242
+ Canon::Comparison.equivalent?(doc1, doc2,
243
+ match: {
244
+ text_content: :normalize,
245
+ structural_whitespace: :ignore,
246
+ comments: :ignore
247
+ }
248
+ )
249
+ ----
250
+ ====
251
+
252
+ .With profile
253
+ [example]
254
+ ====
255
+ [source,ruby]
256
+ ----
257
+ Canon::Comparison.equivalent?(doc1, doc2,
258
+ match_profile: :spec_friendly
259
+ )
260
+ ----
261
+ ====
262
+
263
+ .Profile with dimension overrides
264
+ [example]
265
+ ====
266
+ [source,ruby]
267
+ ----
268
+ Canon::Comparison.equivalent?(doc1, doc2,
269
+ match_profile: :spec_friendly,
270
+ match: {
271
+ comments: :strict # Override profile setting
272
+ }
273
+ )
274
+ ----
275
+ ====
276
+
277
+ See link:../features/match-options/[Match Options] for complete reference.
278
+
279
+ == Layer 4: Diff formatting
280
+
281
+ === Purpose
282
+
283
+ Control how differences are displayed. **This layer is algorithm-specific** - each algorithm generates different output types.
284
+
285
+ === Diff modes
286
+
287
+ `by_line`:: Traditional line-by-line diff
288
+ * Natural fit for DOM algorithm
289
+ * Shows positional changes
290
+ * Traditional diff format
291
+
292
+ `by_object`:: Tree-based semantic diff
293
+ * Natural fit for Semantic algorithm
294
+ * Shows structural operations
295
+ * Visual tree representation
296
+
297
+ === Algorithm-specific output
298
+
299
+ **Critical**: Each algorithm produces fundamentally different output!
300
+
301
+ * **DOM algorithm**: Generates line-based differences
302
+ * **Semantic algorithm**: Generates operation-based differences (INSERT, DELETE, UPDATE, MOVE)
303
+
304
+ See link:../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output] for detailed comparison.
305
+
306
+ === Diff options
307
+
308
+ `use_color`:: Enable/disable ANSI color codes (default: `true`)
309
+
310
+ `context_lines`:: Number of unchanged lines around changes (default: `3`)
311
+
312
+ `diff_grouping_lines`:: Group changes within N lines (default: `nil`)
313
+
314
+ See link:../features/diff-formatting/[Diff Formatting] for details.
315
+
316
+ === Usage
317
+
318
+ .Ruby API
319
+ [example]
320
+ ====
321
+ [source,ruby]
322
+ ----
323
+ Canon::Comparison.equivalent?(doc1, doc2,
324
+ verbose: true,
325
+ diff_mode: :by_line,
326
+ use_color: true,
327
+ context_lines: 5,
328
+ diff_grouping_lines: 10
329
+ )
330
+ ----
331
+ ====
332
+
333
+ .CLI
334
+ [example]
335
+ ====
336
+ [source,bash]
337
+ ----
338
+ $ canon diff file1.xml file2.xml \
339
+ --verbose \
340
+ --diff-mode by-line \
341
+ --context-lines 5 \
342
+ --diff-grouping-lines 10
343
+ ----
344
+ ====
345
+
346
+ == Complete example: All 4 layers
347
+
348
+ Here's a full configuration showing all 4 layers working together:
349
+
350
+ [source,ruby]
351
+ ----
352
+ result = Canon::Comparison.equivalent?(doc1, doc2,
353
+ # Layer 1: Preprocessing
354
+ preprocessing: :normalize,
355
+
356
+ # Layer 2: Algorithm
357
+ diff_algorithm: :semantic,
358
+
359
+ # Layer 3: Match Options
360
+ match_profile: :spec_friendly,
361
+
362
+ # Layer 4: Diff Formatting
363
+ verbose: true,
364
+ diff_mode: :by_object,
365
+ use_color: true,
366
+ context_lines: 3
367
+ )
368
+ ----
369
+
370
+ See link:comparison-pipeline.adoc[Comparison Pipeline] for layer-by-layer examples.
371
+
372
+ == Configuration precedence
373
+
374
+ When options are specified in multiple places, Canon resolves them using this hierarchy (highest to lowest priority):
375
+
376
+ [source]
377
+ ----
378
+ 1. Per-comparison explicit options (highest)
379
+
380
+ 2. Per-comparison profile
381
+
382
+ 3. Global configuration explicit options
383
+
384
+ 4. Global configuration profile
385
+
386
+ 5. Format defaults (lowest)
387
+ ----
388
+
389
+ .Precedence example
390
+ [example]
391
+ ====
392
+ Global configuration:
393
+
394
+ [source,ruby]
395
+ ----
396
+ Canon::RSpecMatchers.configure do |config|
397
+ config.xml.match.profile = :spec_friendly
398
+ config.xml.match.options = { comments: :strict }
399
+ end
400
+ ----
401
+
402
+ Per-test usage:
403
+
404
+ [source,ruby]
405
+ ----
406
+ expect(actual).to be_xml_equivalent_to(expected)
407
+ .with_profile(:rendered)
408
+ .with_options(structural_whitespace: :ignore)
409
+ ----
410
+
411
+ **Final resolved options**:
412
+
413
+ * `text_content: :normalize` (from `:rendered` per-test profile)
414
+ * `structural_whitespace: :ignore` (from per-test explicit option)
415
+ * `comments: :strict` (from global explicit option)
416
+ * Other dimensions use `:rendered` profile or format defaults
417
+ ====
418
+
419
+ == Benefits of 4-layer architecture
420
+
421
+ **Separation of concerns**:: Each layer has a single responsibility
422
+
423
+ **Composability**:: Mix and match preprocessing, algorithm, matching, and rendering options
424
+
425
+ **Algorithm flexibility**:: Choose between speed (DOM) and intelligence (Semantic)
426
+
427
+ **Testability**:: Each layer can be tested independently
428
+
429
+ **Flexibility**:: Fine-grained control over comparison behavior
430
+
431
+ **Clarity**:: Clear data flow from input to output
432
+
433
+ **Extensibility**:: Easy to add new preprocessing, algorithms, dimensions, or rendering modes
434
+
435
+ == See also
436
+
437
+ * link:comparison-pipeline.adoc[Comparison Pipeline] - Complete 4-layer walkthrough
438
+ * link:algorithms/[Algorithms] - DOM and Semantic algorithm details
439
+ * link:../features/preprocessing/[Preprocessing options]
440
+ * link:../features/match-options/[Match dimensions and profiles]
441
+ * link:../features/match-options/algorithm-specific-behavior.adoc[Algorithm-Specific Behavior]
442
+ * link:../features/diff-formatting/[Diff formatting]
443
+ * link:../features/diff-formatting/algorithm-specific-output.adoc[Algorithm-Specific Output]
444
+ * link:../guides/choosing-configuration.adoc[Choosing Configuration]
445
+ * link:../interfaces/ruby-api/[Ruby API documentation]
446
+ * link:../interfaces/cli/[Command-line interface]
447
+ * link:../interfaces/rspec/[RSpec matchers]