canon 0.1.23 → 0.2.1
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 +155 -30
- data/docs/INDEX.adoc +4 -0
- data/docs/advanced/diff-classification.adoc +3 -2
- data/docs/advanced/verbose-mode-architecture.adoc +23 -0
- data/docs/features/configuration-profiles.adoc +288 -0
- data/docs/features/diff-formatting/character-visualization.adoc +153 -454
- data/docs/features/diff-formatting/display-filtering.adoc +44 -0
- data/docs/features/diff-formatting/display-preprocessing.adoc +656 -0
- data/docs/features/diff-formatting/index.adoc +47 -0
- data/docs/features/diff-formatting/pretty-diff-mode.adoc +154 -0
- data/docs/features/environment-configuration/override-system.adoc +10 -3
- data/docs/features/index.adoc +9 -0
- data/docs/features/match-options/html-policies.adoc +3 -0
- data/docs/features/match-options/index.adoc +32 -42
- data/docs/features/match-options/pretty-printed-fixtures.adoc +270 -0
- data/docs/guides/choosing-configuration.adoc +22 -0
- data/docs/reference/environment-variables.adoc +121 -1
- data/docs/reference/options-across-interfaces.adoc +182 -2
- data/lib/canon/cli.rb +20 -0
- data/lib/canon/commands/diff_command.rb +7 -2
- data/lib/canon/commands/format_command.rb +1 -1
- data/lib/canon/comparison/html_comparator.rb +29 -19
- data/lib/canon/comparison/html_compare_profile.rb +4 -4
- data/lib/canon/comparison/markup_comparator.rb +12 -3
- data/lib/canon/comparison/match_options/base_resolver.rb +29 -7
- data/lib/canon/comparison/match_options/json_resolver.rb +9 -0
- data/lib/canon/comparison/match_options/xml_resolver.rb +16 -2
- data/lib/canon/comparison/match_options/yaml_resolver.rb +10 -0
- data/lib/canon/comparison/match_options.rb +4 -1
- data/lib/canon/comparison/whitespace_sensitivity.rb +189 -137
- data/lib/canon/comparison/xml_comparator/child_comparison.rb +21 -4
- data/lib/canon/comparison/xml_comparator.rb +14 -12
- data/lib/canon/comparison/xml_node_comparison.rb +51 -6
- data/lib/canon/comparison.rb +52 -9
- data/lib/canon/config/env_schema.rb +32 -4
- data/lib/canon/config/override_resolver.rb +16 -3
- data/lib/canon/config/profile_loader.rb +135 -0
- data/lib/canon/config/profiles/metanorma.yml +74 -0
- data/lib/canon/config/profiles/metanorma_debug.yml +8 -0
- data/lib/canon/config/type_converter.rb +8 -0
- data/lib/canon/config.rb +469 -5
- data/lib/canon/diff/diff_classifier.rb +41 -11
- data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +48 -17
- data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +58 -0
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +73 -17
- data/lib/canon/diff_formatter.rb +493 -36
- data/lib/canon/pretty_printer/xml_normalized.rb +395 -0
- data/lib/canon/rspec_matchers.rb +36 -0
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/nodes/namespace_node.rb +4 -0
- data/lib/canon/xml/nodes/processing_instruction_node.rb +4 -0
- data/lib/canon/xml/nodes/root_node.rb +4 -0
- data/lib/canon/xml/nodes/text_node.rb +4 -0
- data/lib/tasks/performance_helpers.rb +2 -2
- metadata +24 -2
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration Profiles
|
|
3
|
+
parent: Features
|
|
4
|
+
nav_order: 7
|
|
5
|
+
---
|
|
6
|
+
= Configuration profiles
|
|
7
|
+
:toc:
|
|
8
|
+
:toclevels: 3
|
|
9
|
+
|
|
10
|
+
== Purpose
|
|
11
|
+
|
|
12
|
+
Configuration profiles bundle many settings into a single named preset,
|
|
13
|
+
eliminating repetitive configuration blocks across multiple gems.
|
|
14
|
+
Instead of 60+ lines of per-format settings, use one line:
|
|
15
|
+
|
|
16
|
+
[source,ruby]
|
|
17
|
+
----
|
|
18
|
+
Canon::Config.instance.profile = :metanorma
|
|
19
|
+
----
|
|
20
|
+
|
|
21
|
+
Profiles are defined in YAML files and support inheritance, so a debug
|
|
22
|
+
variant can extend a base profile with only the differences.
|
|
23
|
+
|
|
24
|
+
== Built-in profiles
|
|
25
|
+
|
|
26
|
+
[cols="1,3"]
|
|
27
|
+
|===
|
|
28
|
+
| Profile | Description
|
|
29
|
+
|
|
30
|
+
| `:metanorma`
|
|
31
|
+
| Standard Metanorma spec configuration. Sets preprocessing to `:format`,
|
|
32
|
+
match profile to `:spec_friendly`, diff algorithm to `:dom`, canonical
|
|
33
|
+
display format, normalized pretty-print display preprocessing,
|
|
34
|
+
and XML-specific whitespace element lists.
|
|
35
|
+
|
|
36
|
+
| `:metanorma_debug`
|
|
37
|
+
| Extends `:metanorma` with debug output enabled
|
|
38
|
+
(`show_prettyprint_received: true`).
|
|
39
|
+
|===
|
|
40
|
+
|
|
41
|
+
List all available profiles programmatically:
|
|
42
|
+
|
|
43
|
+
[source,ruby]
|
|
44
|
+
----
|
|
45
|
+
Canon::Config::ProfileLoader.available_profiles
|
|
46
|
+
# => [:metanorma, :metanorma_debug]
|
|
47
|
+
----
|
|
48
|
+
|
|
49
|
+
== Element-level whitespace classification
|
|
50
|
+
|
|
51
|
+
The metanorma profile's key feature is its **element-level whitespace classification**.
|
|
52
|
+
This controls how whitespace differences within specific elements are treated:
|
|
53
|
+
|
|
54
|
+
**Three-way classification:**
|
|
55
|
+
|
|
56
|
+
* **Preserve** (`:preserve`) — Every whitespace character is significant. Use for elements
|
|
57
|
+
where exact whitespace matters (like `<pre>`, `<code>`).
|
|
58
|
+
|
|
59
|
+
* **Collapse** (`:collapse`) — Presence matters but whitespace form doesn't.
|
|
60
|
+
`" hello "` equals `"hello"`. Differences are formatting-only (informative).
|
|
61
|
+
Use for elements like `<p>`, `<li>`, `<td>` in prose documents.
|
|
62
|
+
|
|
63
|
+
* **Strip** (`:strip`) — Whitespace is structural noise, dropped entirely.
|
|
64
|
+
The default for XML elements not in any list.
|
|
65
|
+
|
|
66
|
+
**Metanorma profile element lists:**
|
|
67
|
+
|
|
68
|
+
[source,ruby]
|
|
69
|
+
----
|
|
70
|
+
# In metanorma profile
|
|
71
|
+
Canon::Config.instance.profile = :metanorma
|
|
72
|
+
Canon::Config.instance.xml.match.collapse_whitespace_elements
|
|
73
|
+
# => ["p", "title", "name", "td", "th", "dt", "dd", "li", ...]
|
|
74
|
+
|
|
75
|
+
Canon::Config.instance.xml.match.preserve_whitespace_elements
|
|
76
|
+
# => ["body", "passthrough"]
|
|
77
|
+
----
|
|
78
|
+
|
|
79
|
+
**How it works with `text_content: :normalize`:**
|
|
80
|
+
|
|
81
|
+
[source,ruby]
|
|
82
|
+
----
|
|
83
|
+
# With metanorma profile: <p> is in collapse_whitespace_elements
|
|
84
|
+
Canon::Config.instance.profile = :metanorma
|
|
85
|
+
|
|
86
|
+
# These are EQUIVALENT (whitespace in <p> is formatting-only)
|
|
87
|
+
Canon::Comparison.equivalent?('<p> hello </p>', '<p>hello</p>')
|
|
88
|
+
# => true
|
|
89
|
+
|
|
90
|
+
# But <body> is in preserve_whitespace_elements — every character matters
|
|
91
|
+
# These are NOT EQUIVALENT (whitespace in <body> is normative)
|
|
92
|
+
Canon::Comparison.equivalent?('<body> hello </body>', '<body>hello</body>')
|
|
93
|
+
# => false
|
|
94
|
+
----
|
|
95
|
+
|
|
96
|
+
**Why this matters:**
|
|
97
|
+
|
|
98
|
+
In Metanorma/DocBook documents, elements like `<p>`, `<li>`, `<td>` contain prose
|
|
99
|
+
where whitespace formatting (extra spaces, line breaks) is irrelevant. But `<body>`
|
|
100
|
+
or `<passthrough>` contain code or exact whitespace that matters.
|
|
101
|
+
|
|
102
|
+
Without element-level classification, you'd have to choose:
|
|
103
|
+
- `text_content: :normalize` — ignores ALL whitespace, too permissive
|
|
104
|
+
- `text_content: :strict` — requires exact match everywhere, too strict
|
|
105
|
+
|
|
106
|
+
Element-level classification gives you fine-grained control.
|
|
107
|
+
|
|
108
|
+
== Usage
|
|
109
|
+
|
|
110
|
+
=== Programmatic (Ruby API)
|
|
111
|
+
|
|
112
|
+
Use a **Symbol** for built-in profiles and a **String** for file paths:
|
|
113
|
+
|
|
114
|
+
[source,ruby]
|
|
115
|
+
----
|
|
116
|
+
# Built-in profile (Symbol)
|
|
117
|
+
Canon::Config.instance.profile = :metanorma
|
|
118
|
+
|
|
119
|
+
# Local YAML file (String)
|
|
120
|
+
Canon::Config.instance.profile = "/path/to/my_profile.yml"
|
|
121
|
+
Canon::Config.instance.profile = "~/my_canon_profile.yml"
|
|
122
|
+
Canon::Config.instance.profile = "config/canon_profile.yml"
|
|
123
|
+
|
|
124
|
+
# Or in a configure block
|
|
125
|
+
Canon::Config.configure do |cfg|
|
|
126
|
+
cfg.profile = :metanorma
|
|
127
|
+
# Override individual settings after profile if needed
|
|
128
|
+
cfg.xml.diff.verbose_diff = true
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Clear the profile (revert to defaults + programmatic values)
|
|
132
|
+
Canon::Config.instance.profile = nil
|
|
133
|
+
----
|
|
134
|
+
|
|
135
|
+
IMPORTANT: The type of the value determines how it is resolved:
|
|
136
|
+
**Symbols** are looked up as built-in profile names;
|
|
137
|
+
**Strings** are treated as file paths (with `~` expansion and relative
|
|
138
|
+
path resolution against the working directory).
|
|
139
|
+
|
|
140
|
+
Local YAML files can inherit from built-in profiles (see <<inheritance>>).
|
|
141
|
+
|
|
142
|
+
=== Environment variable
|
|
143
|
+
|
|
144
|
+
Set `CANON_CONFIG_PROFILE` to apply a profile automatically on
|
|
145
|
+
initialization:
|
|
146
|
+
|
|
147
|
+
[source,bash]
|
|
148
|
+
----
|
|
149
|
+
# Built-in profile
|
|
150
|
+
CANON_CONFIG_PROFILE=metanorma bundle exec rspec
|
|
151
|
+
|
|
152
|
+
# File path
|
|
153
|
+
CANON_CONFIG_PROFILE=~/my_profile.yml bundle exec rspec
|
|
154
|
+
----
|
|
155
|
+
|
|
156
|
+
NOTE: `CANON_CONFIG_PROFILE` is distinct from `CANON_PROFILE`, which
|
|
157
|
+
controls the match profile (comparison behavior). The config profile
|
|
158
|
+
controls all settings at once.
|
|
159
|
+
|
|
160
|
+
== Priority chain
|
|
161
|
+
|
|
162
|
+
With profiles, the resolution chain becomes four layers:
|
|
163
|
+
|
|
164
|
+
[source]
|
|
165
|
+
----
|
|
166
|
+
+------------------------------------+
|
|
167
|
+
| 1. Environment Variables | <- Highest Priority
|
|
168
|
+
| (CANON_XML_DIFF_ALGORITHM) |
|
|
169
|
+
+------------------------------------+
|
|
170
|
+
| overrides
|
|
171
|
+
+------------------------------------+
|
|
172
|
+
| 2. Programmatic Configuration |
|
|
173
|
+
| (config.xml.diff.algorithm=) |
|
|
174
|
+
+------------------------------------+
|
|
175
|
+
| overrides
|
|
176
|
+
+------------------------------------+
|
|
177
|
+
| 3. Profile Values |
|
|
178
|
+
| (from YAML profile file) |
|
|
179
|
+
+------------------------------------+
|
|
180
|
+
| overrides
|
|
181
|
+
+------------------------------------+
|
|
182
|
+
| 4. Default Values | <- Lowest Priority
|
|
183
|
+
| (defined in Canon::Config) |
|
|
184
|
+
+------------------------------------+
|
|
185
|
+
----
|
|
186
|
+
|
|
187
|
+
This means:
|
|
188
|
+
|
|
189
|
+
* ENV variables always win (useful for CI overrides)
|
|
190
|
+
* Programmatic setter calls override profile values
|
|
191
|
+
* Profile values override built-in defaults
|
|
192
|
+
* Clearing the profile (`cfg.profile = nil`) removes only layer 3
|
|
193
|
+
|
|
194
|
+
[[inheritance]]
|
|
195
|
+
== Profile inheritance
|
|
196
|
+
|
|
197
|
+
A profile can inherit from another using the `inherits` key:
|
|
198
|
+
|
|
199
|
+
[source,yaml]
|
|
200
|
+
----
|
|
201
|
+
name: my_debug
|
|
202
|
+
inherits: metanorma
|
|
203
|
+
|
|
204
|
+
shared:
|
|
205
|
+
diff:
|
|
206
|
+
verbose_diff: true
|
|
207
|
+
show_prettyprint_received: true
|
|
208
|
+
----
|
|
209
|
+
|
|
210
|
+
Inheritance rules:
|
|
211
|
+
|
|
212
|
+
* Parent values are loaded first, then child values are deep-merged on top
|
|
213
|
+
* Hashes are merged recursively (child keys override parent keys)
|
|
214
|
+
* Arrays are replaced entirely (not concatenated)
|
|
215
|
+
* Single-parent inheritance only
|
|
216
|
+
* Cycle detection prevents infinite loops
|
|
217
|
+
* Local files can inherit from built-in profiles by name
|
|
218
|
+
|
|
219
|
+
== Creating custom profiles
|
|
220
|
+
|
|
221
|
+
=== YAML file format
|
|
222
|
+
|
|
223
|
+
[source,yaml]
|
|
224
|
+
----
|
|
225
|
+
---
|
|
226
|
+
name: my_profile # <1>
|
|
227
|
+
description: My custom config # <2>
|
|
228
|
+
inherits: metanorma # <3>
|
|
229
|
+
|
|
230
|
+
shared: # <4>
|
|
231
|
+
preprocessing: format
|
|
232
|
+
match:
|
|
233
|
+
profile: spec_friendly
|
|
234
|
+
diff:
|
|
235
|
+
algorithm: dom
|
|
236
|
+
context_lines: 5
|
|
237
|
+
verbose_diff: false
|
|
238
|
+
|
|
239
|
+
formats: # <5>
|
|
240
|
+
xml:
|
|
241
|
+
match:
|
|
242
|
+
collapse_whitespace_elements:
|
|
243
|
+
- p
|
|
244
|
+
- title
|
|
245
|
+
- td
|
|
246
|
+
preserve_whitespace_elements:
|
|
247
|
+
- body
|
|
248
|
+
- passthrough
|
|
249
|
+
html:
|
|
250
|
+
diff:
|
|
251
|
+
show_raw_inputs: true
|
|
252
|
+
----
|
|
253
|
+
<1> Profile name (metadata)
|
|
254
|
+
<2> Description (metadata)
|
|
255
|
+
<3> Optional: inherit from another profile (name or path)
|
|
256
|
+
<4> `shared` settings apply to all formats (xml, html, json, yaml, string)
|
|
257
|
+
<5> `formats.<name>` settings override `shared` for that specific format
|
|
258
|
+
|
|
259
|
+
=== Attribute mapping
|
|
260
|
+
|
|
261
|
+
Profile YAML keys map directly to Canon configuration accessors:
|
|
262
|
+
|
|
263
|
+
[cols="2,2"]
|
|
264
|
+
|===
|
|
265
|
+
| YAML path | Ruby equivalent
|
|
266
|
+
|
|
267
|
+
| `shared.preprocessing`
|
|
268
|
+
| `cfg.xml.preprocessing = :format`
|
|
269
|
+
|
|
270
|
+
| `shared.match.profile`
|
|
271
|
+
| `cfg.xml.match.profile = :spec_friendly`
|
|
272
|
+
|
|
273
|
+
| `shared.diff.algorithm`
|
|
274
|
+
| `cfg.xml.diff.algorithm = :dom`
|
|
275
|
+
|
|
276
|
+
| `formats.xml.diff.context_lines`
|
|
277
|
+
| `cfg.xml.diff.context_lines = 5`
|
|
278
|
+
|===
|
|
279
|
+
|
|
280
|
+
All `DiffConfig` and `MatchConfig` attributes documented in
|
|
281
|
+
link:../reference/options-across-interfaces.adoc[Options Across Interfaces]
|
|
282
|
+
are supported.
|
|
283
|
+
|
|
284
|
+
== See also
|
|
285
|
+
|
|
286
|
+
* link:environment-configuration/override-system.adoc[Override System] -- ENV variable priority
|
|
287
|
+
* link:match-options/index.adoc[Match Options] -- match profile presets (`:strict`, `:spec_friendly`, etc.)
|
|
288
|
+
* link:../guides/choosing-configuration.adoc[Choosing Configuration] -- decision guide
|