Class: SvgConform::ValidationContext
- Inherits:
-
Object
- Object
- SvgConform::ValidationContext
- Defined in:
- lib/svg_conform/validation_context.rb
Overview
Context object passed to requirements during validation
The ValidationContext serves as the central state management object during SVG validation. It tracks errors, warnings, structural issues, and provides helper methods for requirements to report issues.
Architecture
ValidationContext delegates to specialized tracker classes:
- ErrorTracker: tracks errors, warnings, and notices
- StructuralInvalidityTracker: tracks structurally invalid nodes
- NodeIdManager: handles node ID generation for both SAX and DOM modes
- ReferenceManifest: tracks ID definitions and references
- State Registry: manages requirement-specific state for deferred validation
Validation modes
DOM validation (remediation mode)
context = ValidationContext.new(document, profile)
requirement.validate_document(document, context)
SAX validation (streaming mode)
context = ValidationContext.new(nil, profile)
requirement.validate_sax_element(element, context)
State management for deferred validation
Requirements that need deferred validation (collecting data during SAX parsing and validating at document end) use requirement-specific State classes:
class MyRequirement < BaseRequirement
class State
attr_accessor :collected_items
def initialize
@collected_items = []
end
end
def collect_sax_data(element, context)
state = context.state_for(self)
state.collected_items << extract_from(element)
end
def validate_sax_complete(context)
state = context.state_for(self)
# Validate state.collected_items
end
end
The state_for method:
- Returns a State instance specific to the requirement class
- Creates the State instance on first access (lazy initialization)
- Maintains one State instance per requirement class per validation
- Prevents state pollution when reusing profiles across validations
Each validation gets a fresh ValidationContext with a fresh state registry, ensuring that reusing the same Profile for multiple validations doesn't leak state between validations.
Error reporting
context.add_error(
requirement_id: id,
message: "Element not allowed",
node: node,
severity: :error,
fix: -> { remove_element(node) }
)
Node ID tracking
The context generates unique node IDs for tracking:
- SAX mode: uses pre-computed path_id from ElementProxy
- DOM mode: uses DocumentAnalyzer with forward-counting algorithm
Structural invalidity
Requirements can mark nodes as structurally invalid (e.g., invalid parent-child relationships). Other requirements should skip validation on these nodes since they will be removed during remediation.
context.mark_node_structurally_invalid(node)
context.node_structurally_invalid?(node) # => true
Instance Attribute Summary collapse
-
#document ⇒ Object
readonly
The document being validated (nil in SAX mode).
-
#fixes ⇒ Object
readonly
Array of fixes that can be applied.
-
#profile ⇒ Object
readonly
The profile containing requirements to validate against.
-
#reference_manifest ⇒ Object
readonly
Reference manifest tracking IDs and references.
Instance Method Summary collapse
- #add_error(node:, message:, rule: nil, requirement: nil, requirement_id: nil, severity: nil, fix: nil, data: {}) ⇒ Object
-
#add_external_reference_notice(node:, reference:, message: nil) ⇒ Object
Add notice for external references (not errors).
- #add_fix(fix) ⇒ Object
-
#add_notice(rule:, node:, message:, fix: nil, data: {}) ⇒ Object
Add an informational notice (delegates to ErrorTracker).
- #add_warning(rule:, node:, message:, fix: nil) ⇒ Object
-
#errors ⇒ Object
Delegate error tracking methods to ErrorTracker.
- #fixable_count ⇒ Object
-
#generate_node_id(node) ⇒ Object
Generate a unique identifier for a node based on its path Delegates to NodeIdManager which handles both SAX and DOM modes.
- #has_errors? ⇒ Boolean
- #has_fixes? ⇒ Boolean
- #has_warnings? ⇒ Boolean
-
#id_defined?(id_value) ⇒ Boolean
Check if ID exists in manifest.
- #infos ⇒ Object
-
#initialize(document, profile) ⇒ ValidationContext
constructor
A new instance of ValidationContext.
- #issue_count ⇒ Object
-
#mark_descendants_invalid(node) ⇒ Object
Mark all descendants of a node as structurally invalid.
-
#mark_node_structurally_invalid(node) ⇒ Object
Mark a node as structurally invalid (e.g., invalid parent-child relationship) Other requirements should skip attribute validation on these nodes Also marks all descendants as invalid since they'll be removed with the parent.
-
#node_structurally_invalid?(node) ⇒ Boolean
Check if a node is structurally invalid.
-
#register_id(id_value, element_name:, line_number: nil, column_number: nil) ⇒ Object
Register an ID definition.
-
#register_reference(reference) ⇒ Object
Register a reference.
-
#state_for(requirement) ⇒ Object
Get or create state for a requirement Each requirement gets its own state instance, preventing state pollution.
- #validity_errors ⇒ Object
- #warnings ⇒ Object
Constructor Details
#initialize(document, profile) ⇒ ValidationContext
Returns a new instance of ValidationContext.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/svg_conform/validation_context.rb', line 129 def initialize(document, profile) @document = document @profile = profile # Use TrackerFactory to create all tracker instances trackers = Validation::TrackerFactory.create_all_trackers(document) @error_tracker = trackers[:error_tracker] @node_id_manager = trackers[:node_id_manager] @structural_invalidity_tracker = trackers[:structural_invalidity_tracker] @reference_manifest = trackers[:reference_manifest] @fixes = [] @state_registry = {} # Maps requirement class => state instance end |
Instance Attribute Details
#document ⇒ Object (readonly)
The document being validated (nil in SAX mode)
101 102 103 |
# File 'lib/svg_conform/validation_context.rb', line 101 def document @document end |
#fixes ⇒ Object (readonly)
Array of fixes that can be applied
107 108 109 |
# File 'lib/svg_conform/validation_context.rb', line 107 def fixes @fixes end |
#profile ⇒ Object (readonly)
The profile containing requirements to validate against
104 105 106 |
# File 'lib/svg_conform/validation_context.rb', line 104 def profile @profile end |
#reference_manifest ⇒ Object (readonly)
Reference manifest tracking IDs and references
110 111 112 |
# File 'lib/svg_conform/validation_context.rb', line 110 def reference_manifest @reference_manifest end |
Instance Method Details
#add_error(node:, message:, rule: nil, requirement: nil, requirement_id: nil, severity: nil, fix: nil, data: {}) ⇒ Object
167 168 169 170 171 172 173 |
# File 'lib/svg_conform/validation_context.rb', line 167 def add_error(node:, message:, rule: nil, requirement: nil, requirement_id: nil, severity: nil, fix: nil, data: {}) @error_tracker.add_error( node: node, message: , rule: rule, requirement: requirement, requirement_id: requirement_id, severity: severity, fix: fix, data: data ) end |
#add_external_reference_notice(node:, reference:, message: nil) ⇒ Object
Add notice for external references (not errors)
232 233 234 235 236 237 238 239 |
# File 'lib/svg_conform/validation_context.rb', line 232 def add_external_reference_notice(node:, reference:, message: nil) @error_tracker.add_notice( rule: nil, node: node, message: || "External reference: #{reference.value}", data: { reference: reference }, ) end |
#add_fix(fix) ⇒ Object
186 187 188 |
# File 'lib/svg_conform/validation_context.rb', line 186 def add_fix(fix) @fixes << fix end |
#add_notice(rule:, node:, message:, fix: nil, data: {}) ⇒ Object
Add an informational notice (delegates to ErrorTracker)
181 182 183 184 |
# File 'lib/svg_conform/validation_context.rb', line 181 def add_notice(rule:, node:, message:, fix: nil, data: {}) @error_tracker.add_notice(rule: rule, node: node, message: , fix: fix, data: data) end |
#add_warning(rule:, node:, message:, fix: nil) ⇒ Object
175 176 177 178 |
# File 'lib/svg_conform/validation_context.rb', line 175 def add_warning(rule:, node:, message:, fix: nil) @error_tracker.add_warning(rule: rule, node: node, message: , fix: fix) end |
#errors ⇒ Object
Delegate error tracking methods to ErrorTracker
113 114 115 |
# File 'lib/svg_conform/validation_context.rb', line 113 def errors @error_tracker.errors end |
#fixable_count ⇒ Object
206 207 208 |
# File 'lib/svg_conform/validation_context.rb', line 206 def fixable_count (@error_tracker.errors + @error_tracker.warnings).count(&:fixable?) end |
#generate_node_id(node) ⇒ Object
Generate a unique identifier for a node based on its path Delegates to NodeIdManager which handles both SAX and DOM modes
243 244 245 |
# File 'lib/svg_conform/validation_context.rb', line 243 def generate_node_id(node) @node_id_manager.generate_node_id(node) end |
#has_errors? ⇒ Boolean
190 191 192 |
# File 'lib/svg_conform/validation_context.rb', line 190 def has_errors? @error_tracker.has_errors? end |
#has_fixes? ⇒ Boolean
198 199 200 |
# File 'lib/svg_conform/validation_context.rb', line 198 def has_fixes? !@fixes.empty? end |
#has_warnings? ⇒ Boolean
194 195 196 |
# File 'lib/svg_conform/validation_context.rb', line 194 def has_warnings? @error_tracker.has_warnings? end |
#id_defined?(id_value) ⇒ Boolean
Check if ID exists in manifest
227 228 229 |
# File 'lib/svg_conform/validation_context.rb', line 227 def id_defined?(id_value) @reference_manifest.id_defined?(id_value) end |
#infos ⇒ Object
125 126 127 |
# File 'lib/svg_conform/validation_context.rb', line 125 def infos @error_tracker.infos end |
#issue_count ⇒ Object
202 203 204 |
# File 'lib/svg_conform/validation_context.rb', line 202 def issue_count @error_tracker.total_error_count + warnings.size end |
#mark_descendants_invalid(node) ⇒ Object
Mark all descendants of a node as structurally invalid
158 159 160 |
# File 'lib/svg_conform/validation_context.rb', line 158 def mark_descendants_invalid(node) @structural_invalidity_tracker.mark_descendants_invalid(node) end |
#mark_node_structurally_invalid(node) ⇒ Object
Mark a node as structurally invalid (e.g., invalid parent-child relationship) Other requirements should skip attribute validation on these nodes Also marks all descendants as invalid since they'll be removed with the parent
153 154 155 |
# File 'lib/svg_conform/validation_context.rb', line 153 def mark_node_structurally_invalid(node) @structural_invalidity_tracker.mark_node_structurally_invalid(node) end |
#node_structurally_invalid?(node) ⇒ Boolean
Check if a node is structurally invalid
163 164 165 |
# File 'lib/svg_conform/validation_context.rb', line 163 def node_structurally_invalid?(node) @structural_invalidity_tracker.node_structurally_invalid?(node) end |
#register_id(id_value, element_name:, line_number: nil, column_number: nil) ⇒ Object
Register an ID definition
211 212 213 214 215 216 217 218 219 |
# File 'lib/svg_conform/validation_context.rb', line 211 def register_id(id_value, element_name:, line_number: nil, column_number: nil) @reference_manifest.register_id( id_value, element_name: element_name, line_number: line_number, column_number: column_number, ) end |
#register_reference(reference) ⇒ Object
Register a reference
222 223 224 |
# File 'lib/svg_conform/validation_context.rb', line 222 def register_reference(reference) @reference_manifest.register_reference(reference) end |
#state_for(requirement) ⇒ Object
Get or create state for a requirement Each requirement gets its own state instance, preventing state pollution
146 147 148 |
# File 'lib/svg_conform/validation_context.rb', line 146 def state_for(requirement) @state_registry[requirement.class] ||= requirement.class::State.new end |
#validity_errors ⇒ Object
121 122 123 |
# File 'lib/svg_conform/validation_context.rb', line 121 def validity_errors @error_tracker.validity_errors end |
#warnings ⇒ Object
117 118 119 |
# File 'lib/svg_conform/validation_context.rb', line 117 def warnings @error_tracker.warnings end |