1. Purpose

Canon provides a unified option system across all three interfaces: CLI, Ruby API, and RSpec. Each option can be expressed in different ways depending on the interface, but they all control the same underlying behavior.

This reference shows how to express the same configuration across all interfaces, making it easy to:

  • Translate between interfaces

  • Understand option equivalence

  • Choose the right interface for your needs

  • Maintain consistent configuration

2. Option Equivalence Table

The following table shows how major Canon options are expressed in each interface:

2.1. Layer 1: Preprocessing Options

Option CLI Flag Ruby API RSpec Config ENV Variable

Comparison Preprocessing

--preprocessing normalize

preprocessing: :normalize

config.canon.xml.preprocessing = :normalize

CANON_PREPROCESSING=normalize

Preprocessing values: none, c14n, normalize, format

This controls how documents are normalized before comparison (equivalence detection). It is independent of display preprocessing, which controls how documents are formatted for the diff output.

2.2. Layer 1b: Display Preprocessing Options

Display preprocessing controls how documents are normalized before the line diff is rendered. This is independent of comparison preprocessing. Because both sides go through the same normalization, the resulting line diff shows only genuine content differences rather than formatting differences.

Option CLI Flag Ruby API RSpec Config ENV Variable

Display Preprocessing

--display-preprocessing pretty_print

display_preprocessing: :pretty_print

cfg.xml.diff.display_preprocessing = :pretty_print

CANON_XML_DIFF_DISPLAY_PREPROCESSING=pretty_print

Pretty-printer Indent

N/A

N/A (config only)

cfg.xml.diff.pretty_printer.indent = 2

CANON_XML_DIFF_PRETTY_PRINTER_INDENT=2

Pretty-printer Indent Type

N/A

N/A (config only)

cfg.xml.diff.pretty_printer.indent_type = :space

CANON_XML_DIFF_PRETTY_PRINTER_INDENT_TYPE=space

Collapse Whitespace Elements

N/A

N/A (config only)

cfg.xml.match.collapse_whitespace_elements = %w[p li td th]

CANON_XML_MATCH_COLLAPSE_WHITESPACE_ELEMENTS=p,li,td,th

Preserve Whitespace Elements

N/A

N/A (config only)

cfg.xml.match.preserve_whitespace_elements = %w[pre code]

CANON_XML_MATCH_PRESERVE_WHITESPACE_ELEMENTS=pre,code

Pretty-printed Expected

N/A

match: { pretty_printed_expected: true }

cfg.xml.diff.pretty_printed_expected = true

CANON_XML_DIFF_PRETTY_PRINTED_EXPECTED=true

Pretty-printed Received

N/A

match: { pretty_printed_received: true }

cfg.xml.diff.pretty_printed_received = true

CANON_XML_DIFF_PRETTY_PRINTED_RECEIVED=true

Sort Attributes (pretty printer)

N/A

N/A (config only)

cfg.xml.diff.pretty_printer_sort_attributes = true

CANON_XML_DIFF_PRETTY_PRINTER_SORT_ATTRIBUTES=true

Compact Semantic Report

N/A

N/A (config only)

cfg.xml.diff.compact_semantic_report = true

CANON_XML_DIFF_COMPACT_SEMANTIC_REPORT=true

Expand Difference

N/A

N/A (config only)

cfg.xml.diff.expand_difference = true

CANON_XML_DIFF_EXPAND_DIFFERENCE=true

Display preprocessing values: none (default), pretty_print, normalize_pretty_print, c14n

  • :none — documents are used as-is for the line diff (existing behaviour)

  • :pretty_print — both documents are run through a format-specific pretty-printer before the line diff: Canon::PrettyPrinter::Xml for XML (one tag per line, consistent indentation); Canon::PrettyPrinter::Html (Nokogiri HTML5 serializer) for HTML. Recommended for XML and HTML RSpec tests.

  • :normalize_pretty_print — like :pretty_print but uses Canon::PrettyPrinter::XmlNormalized, which guarantees one line per XML node even for mixed-content elements (those containing both text and child elements). Recommended when XML contains inline markup (Metanorma, DocBook). Use collapse_whitespace_elements or preserve_whitespace_elements to control per-element whitespace visualization.

  • :c14n — both documents are run through canonical normalization before the line diff. For XML: canonical XML (C14N, attribute-order sorting). For HTML: Nokogiri HTML5 serialization (normalizes attribute order and whitespace).

Pretty-printer indent options only apply when display_preprocessing is :pretty_print or :normalize_pretty_print.
compact_semantic_report controls the representation of XML element nodes in the Semantic Diff Report section (the structured summary that appears above the line diff). When false (default), element nodes are described with their node_info string (e.g. name: strong namespace_uri: …), which is unambiguous but verbose. When true, element nodes are serialized as compact inline XML (e.g. <strong>Annex A</strong>), which is much easier to read at a glance. Plain text nodes (leaf text content) are not affected — they always display their decoded string value.

2.3. Layer 1c: Character Visualization

Character visualization controls whether invisible characters (spaces, tabs, non-breaking spaces, etc.) are replaced with visible Unicode symbols in diff output.

Option CLI Flag Ruby API RSpec Config ENV Variable

Character Visualization

N/A

character_visualization: true

cfg.xml.diff.character_visualization = false

CANON_XML_DIFF_CHARACTER_VISUALIZATION=false

Character visualization values:

  • true — (default) the full default visualization map is applied; spaces appear as , tabs as , non-breaking spaces as , etc.

  • false — visualization is disabled; all characters appear as plain text.

  • :content_only — reserved for future use; currently behaves as true. Future intent: apply visualization only to text-node content, leaving structural indentation whitespace plain.

Setting character_visualization: false is useful when copying diff output from a failure message, or when downstream tooling cannot handle Unicode symbol substitutions.

2.4. Layer 2: Algorithm Selection

Option CLI Flag Ruby API RSpec Config ENV Variable

Diff Algorithm

--diff-algorithm semantic

diff_algorithm: :semantic

config.canon.xml.diff.algorithm = :semantic

CANON_ALGORITHM=semantic

Diff Mode

--diff-mode by_object

diff_mode: :by_object

config.canon.xml.diff.mode = :by_object

CANON_MODE=by_object

Algorithm values: dom, semantic
Diff mode values: by_line, by_object, pretty_diff

2.5. Layer 3: Match Options

2.5.1. Match Profile

Option CLI Flag Ruby API RSpec Config ENV Variable

Match Profile

--match-profile strict

match_profile: :strict

config.canon.xml.match.profile = :strict

CANON_PROFILE=strict

Profile values: strict, rendered, spec_friendly, content_only

2.5.2. Match Dimensions (All Formats)

Dimension CLI Flag Ruby API RSpec Config ENV Variable

Text Content

--text-content normalize

match: { text_content: :normalize }

config.canon.xml.match.options = { text_content: :normalize }

CANON_TEXT_CONTENT=normalize

Structural Whitespace

--structural-whitespace ignore

match: { structural_whitespace: :ignore }

config.canon.xml.match.options = { structural_whitespace: :ignore }

CANON_STRUCTURAL_WHITESPACE=ignore

Comments

--comments ignore

match: { comments: :ignore }

config.canon.xml.match.options = { comments: :ignore }

CANON_COMMENTS=ignore

Element Structure

--element-structure strict

match: { element_structure: :strict }

config.canon.xml.match.options = { element_structure: :strict }

CANON_ELEMENT_STRUCTURE=strict

Element Position

--element-position ignore

match: { element_position: :ignore }

config.canon.xml.match.options = { element_position: :ignore }

CANON_ELEMENT_POSITION=ignore

Element Hierarchy

--element-hierarchy strict

match: { element_hierarchy: :strict }

config.canon.xml.match.options = { element_hierarchy: :strict }

CANON_ELEMENT_HIERARCHY=strict

Whitespace Type

--whitespace-type normalize

match: { whitespace_type: :normalize }

config.canon.xml.match.options = { whitespace_type: :normalize }

CANON_WHITESPACE_TYPE=normalize

Values: strict, normalize, ignore (or strict, ignore for structure/position/hierarchy). whitespace_type values: strict (default), normalize

2.5.3. XML/HTML-Specific Match Dimensions

Dimension CLI Flag Ruby API RSpec Config ENV Variable

Attribute Whitespace

--attribute-whitespace normalize

match: { attribute_whitespace: :normalize }

config.canon.xml.match.options = { attribute_whitespace: :normalize }

CANON_ATTRIBUTE_WHITESPACE=normalize

Attribute Order

--attribute-order ignore

match: { attribute_order: :ignore }

config.canon.xml.match.options = { attribute_order: :ignore }

CANON_ATTRIBUTE_ORDER=ignore

Attribute Values

--attribute-values normalize

match: { attribute_values: :normalize }

config.canon.xml.match.options = { attribute_values: :normalize }

CANON_ATTRIBUTE_VALUES=normalize

Values: strict, normalize, ignore (or strict, ignore for order)

2.5.4. JSON/YAML-Specific Match Dimensions

Dimension CLI Flag Ruby API RSpec Config ENV Variable

Key Order

--key-order ignore

match: { key_order: :ignore }

config.canon.json.match.options = { key_order: :ignore }

CANON_KEY_ORDER=ignore

Values: strict, ignore

2.6. Layer 4: Diff Formatting Options

Option CLI Flag Ruby API RSpec Config ENV Variable

Use Color

--color / --no-color

color: true / color: false

config.canon.xml.diff.use_color = true

CANON_USE_COLOR=true

Verbose

--verbose / -v

verbose: true

config.canon.xml.diff.verbose_diff = true

CANON_VERBOSE_DIFF=true

Context Lines

--context-lines 5

context_lines: 5

config.canon.xml.diff.context_lines = 5

CANON_CONTEXT_LINES=5

Grouping Lines

--diff-grouping-lines 15

diff_grouping_lines: 15

config.canon.xml.diff.grouping_lines = 15

CANON_GROUPING_LINES=15

2.7. Debug Input Display Options

These options control whether Canon dumps the raw or preprocessed document content to the terminal alongside the diff. They are useful for debugging comparisons — e.g. inspecting what the received output actually looks like before filing an issue.

Option CLI Flag Ruby API RSpec Config ENV Variable

Show Raw Inputs (both)

--show-raw-inputs

N/A (config only)

cfg.xml.diff.show_raw_inputs = true

CANON_XML_DIFF_SHOW_RAW_INPUTS=true

Show Raw Expected only

N/A

N/A (config only)

cfg.xml.diff.show_raw_expected = true

CANON_XML_DIFF_SHOW_RAW_EXPECTED=true

Show Raw Received only

N/A

N/A (config only)

cfg.xml.diff.show_raw_received = true

CANON_XML_DIFF_SHOW_RAW_RECEIVED=true

Show Preprocessed Inputs (both)

--show-preprocessed-inputs

N/A (config only)

cfg.xml.diff.show_preprocessed_inputs = true

CANON_XML_DIFF_SHOW_PREPROCESSED_INPUTS=true

Show Preprocessed Expected only

--show-preprocessed-expected

N/A (config only)

cfg.xml.diff.show_preprocessed_expected = true

CANON_XML_DIFF_SHOW_PREPROCESSED_EXPECTED=true

Show Preprocessed Received only

--show-preprocessed-received

N/A (config only)

cfg.xml.diff.show_preprocessed_received = true

CANON_XML_DIFF_SHOW_PREPROCESSED_RECEIVED=true

Show Pretty-printed Inputs (both)

--show-prettyprint-inputs

N/A (config only)

cfg.xml.diff.show_prettyprint_inputs = true

CANON_XML_DIFF_SHOW_PRETTYPRINT_INPUTS=true

Show Pretty-printed Expected only

--show-prettyprint-expected

N/A (config only)

cfg.xml.diff.show_prettyprint_expected = true

CANON_XML_DIFF_SHOW_PRETTYPRINT_EXPECTED=true

Show Pretty-printed Received only

--show-prettyprint-received

N/A (config only)

cfg.xml.diff.show_prettyprint_received = true

CANON_XML_DIFF_SHOW_PRETTYPRINT_RECEIVED=true

Show Line-Numbered Inputs

--show-line-numbered-inputs

N/A (config only)

cfg.xml.diff.show_line_numbered_inputs = true

CANON_XML_DIFF_SHOW_LINE_NUMBERED_INPUTS=true

show_raw_inputs, show_preprocessed_inputs, and show_prettyprint_inputs are convenience shorthands for enabling both sides of their respective section simultaneously. Use the per-side variants (*_expected / *_received) when you only want to display one side — e.g. suppress the (long) expected fixture and show only what was generated.
The pretty-printed section (show_prettyprint_*) differs from the preprocessed section (show_preprocessed_*) in two ways: (1) it always pretty-prints the original strings using PrettyPrinter::Xml/Html, independently of any preprocessing or display_preprocessing setting; and (2) it outputs plain ASCII with no character visualization (spaces remain spaces), making the output suitable for direct copy-paste into RSpec heredoc fixtures.
verbose_diff enables the raw, preprocessed, and line-numbered debug sections simultaneously. It does not enable the pretty-printed section, which is a fixture-oriented feature independent of debugging verbosity.

2.8. Size Limit Options

Option CLI Flag Ruby API RSpec Config ENV Variable

Max File Size

N/A

N/A (config only)

config.canon.xml.diff.max_file_size = 10485760

CANON_MAX_FILE_SIZE=10485760

Max Node Count

N/A

N/A (config only)

config.canon.xml.diff.max_node_count = 50000

CANON_MAX_NODE_COUNT=50000

Max Diff Lines

N/A

N/A (config only)

config.canon.xml.diff.max_diff_lines = 20000

CANON_MAX_DIFF_LINES=20000

Size limit options are only available through environment variables or programmatic configuration (Ruby API/RSpec), not via CLI flags.

3. Complete Example: Same Configuration

This example shows the SAME configuration expressed in all four ways:

Example 1. Configuration Goal
  • Use semantic diff algorithm

  • Apply strict match profile

  • Ignore attribute order (XML/HTML)

  • Normalize text content

  • Disable color output

  • Show 5 context lines

3.1. Via Environment Variables

export CANON_ALGORITHM=semantic
export CANON_PROFILE=strict
export CANON_ATTRIBUTE_ORDER=ignore
export CANON_TEXT_CONTENT=normalize
export CANON_USE_COLOR=false
export CANON_CONTEXT_LINES=5

3.2. Via CLI

canon diff file1.xml file2.xml \
  --diff-algorithm semantic \
  --match-profile strict \
  --attribute-order ignore \
  --text-content normalize \
  --no-color \
  --context-lines 5

3.3. Via Ruby API

Canon.compare(file1, file2,
  format: :xml,
  diff_algorithm: :semantic,
  match_profile: :strict,
  match: {
    attribute_order: :ignore,
    text_content: :normalize
  },
  color: false,
  context_lines: 5
)

3.4. Via RSpec

RSpec.configure do |config|
  # Algorithm
  config.canon.xml.diff.algorithm = :semantic

  # Match configuration
  config.canon.xml.match.profile = :strict
  config.canon.xml.match.options = {
    attribute_order: :ignore,
    text_content: :normalize
  }

  # Formatting
  config.canon.xml.diff.use_color = false
  config.canon.xml.diff.context_lines = 5
end

# In specs
expect(actual_xml).to match_xml(expected_xml)

4. Format-Specific Configuration

Different formats can have different configurations:

4.1. Via Environment Variables

# XML-specific
export CANON_XML_DIFF_ALGORITHM=semantic
export CANON_XML_MATCH_PROFILE=strict

# HTML-specific
export CANON_HTML_DIFF_ALGORITHM=dom
export CANON_HTML_MATCH_PROFILE=rendered

# JSON-specific
export CANON_JSON_MATCH_PROFILE=content_only

4.2. Via RSpec

RSpec.configure do |config|
  # XML configuration
  config.canon.xml.diff.algorithm = :semantic
  config.canon.xml.match.profile = :strict

  # HTML configuration
  config.canon.html.diff.algorithm = :dom
  config.canon.html.match.profile = :rendered

  # JSON configuration
  config.canon.json.match.profile = :content_only
end

5. Option Naming Conventions

5.1. CLI Naming

  • Uses kebab-case: --diff-algorithm, --match-profile

  • Boolean flags: --color, --no-color, --verbose

  • Underscores become hyphens: text_content--text-content

5.2. Ruby API Naming

  • Uses snake_case symbols: :diff_algorithm, :match_profile

  • Boolean values: true, false

  • Match dimensions in hash: match: { text_content: :normalize }

5.3. RSpec Naming

  • Uses snake_case methods: .diff.algorithm, .match.profile

  • Boolean values: true, false

  • Match dimensions in hash: .match.options = { text_content: :normalize }

5.4. ENV Variable Naming

  • Uses SCREAMING_SNAKE_CASE: CANON_ALGORITHM, CANON_PROFILE

  • Prefixed with CANON_

  • Format-specific: CANON_XML_DIFF_ALGORITHM

  • Boolean as strings: "true", "false"

6. Priority Order

When multiple configuration sources are present:

  1. Explicit arguments (highest priority)

    • CLI flags

    • Ruby API parameters

  2. Environment variables

    • Format-specific ENV vars

    • Global ENV vars

  3. Programmatic configuration

    • Canon.configure blocks

    • RSpec.configure blocks

  4. Default values (lowest priority)

    • Built-in Canon defaults

Example 2. Priority example
# Environment variable
export CANON_ALGORITHM=semantic

# RSpec configuration
RSpec.configure do |config|
  config.canon.xml.diff.algorithm = :dom
end

# Explicit in test - WINS
expect(actual).to match_xml(expected).with_options(
  diff_algorithm: :semantic
)
# Result: Uses semantic (explicit argument overrides all)