Class: Uniword::Quality::HeadingHierarchyRule

Inherits:
QualityRule
  • Object
show all
Defined in:
lib/uniword/quality/rules/heading_hierarchy_rule.rb

Overview

Checks that headings follow proper hierarchical structure.

Responsibility: Validate heading level sequence and hierarchy. Single Responsibility - only checks heading hierarchy.

Validates:

  • Headings don’t skip levels (e.g., H1 -> H3)

  • Heading levels don’t exceed maximum

  • Document structure follows logical hierarchy

Examples:

Configuration

heading_hierarchy:
  enabled: true
  max_level: 6
  require_sequential: true

Constant Summary collapse

HEADING_PATTERN =
/^heading\s*(\d+)$/i

Instance Attribute Summary

Attributes inherited from QualityRule

#config, #enabled

Instance Method Summary collapse

Methods inherited from QualityRule

#enabled?, #name

Constructor Details

#initialize(config = {}) ⇒ HeadingHierarchyRule

Returns a new instance of HeadingHierarchyRule.



23
24
25
26
27
# File 'lib/uniword/quality/rules/heading_hierarchy_rule.rb', line 23

def initialize(config = {})
  super
  @max_level = @config[:max_level] || 6
  @require_sequential = @config.fetch(:require_sequential, true)
end

Instance Method Details

#check(document) ⇒ Array<QualityViolation>

Check document for heading hierarchy violations

Parameters:

  • document (Document)

    The document to check

Returns:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/uniword/quality/rules/heading_hierarchy_rule.rb', line 33

def check(document)
  violations = []
  previous_level = 0

  document.paragraphs.each_with_index do |para, index|
    heading_level = extract_heading_level(para)
    next unless heading_level

    # Check max level
    if heading_level > @max_level
      violations << create_violation(
        severity: :error,
        message: "Heading level #{heading_level} exceeds maximum allowed level #{@max_level}",
        location: "Paragraph #{index + 1}",
        element: para,
      )
    end

    # Check sequential hierarchy
    if @require_sequential && previous_level.positive? && (heading_level > previous_level + 1)
      violations << create_violation(
        severity: :warning,
        message: "Heading level skips from #{previous_level} to #{heading_level} " \
                 "(expected #{previous_level + 1} or less)",
        location: "Paragraph #{index + 1}",
        element: para,
      )
    end

    previous_level = heading_level
  end

  violations
end